vfs: split generic_forget_inode() so that hugetlbfs does not have to copy it
Hugetlbfs needs to do special things instead of truncate_inode_pages(). Currently, it copied generic_forget_inode() except for truncate_inode_pages() call which is asking for trouble (the code there isn't trivial). So create a separate function generic_detach_inode() which does all the list magic done in generic_forget_inode() and call it from hugetlbfs_forget_inode(). Signed-off-by: Jan Kara <jack@suse.cz> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
af0d9ae811
commit
22fe404218
3 changed files with 24 additions and 31 deletions
|
@ -380,37 +380,12 @@ static void hugetlbfs_delete_inode(struct inode *inode)
|
||||||
|
|
||||||
static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
|
static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
|
||||||
{
|
{
|
||||||
struct super_block *sb = inode->i_sb;
|
if (generic_detach_inode(inode)) {
|
||||||
|
|
||||||
if (!hlist_unhashed(&inode->i_hash)) {
|
|
||||||
if (!(inode->i_state & (I_DIRTY|I_SYNC)))
|
|
||||||
list_move(&inode->i_list, &inode_unused);
|
|
||||||
inodes_stat.nr_unused++;
|
|
||||||
if (!sb || (sb->s_flags & MS_ACTIVE)) {
|
|
||||||
spin_unlock(&inode_lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
inode->i_state |= I_WILL_FREE;
|
|
||||||
spin_unlock(&inode_lock);
|
|
||||||
/*
|
|
||||||
* write_inode_now is a noop as we set BDI_CAP_NO_WRITEBACK
|
|
||||||
* in our backing_dev_info.
|
|
||||||
*/
|
|
||||||
write_inode_now(inode, 1);
|
|
||||||
spin_lock(&inode_lock);
|
|
||||||
inode->i_state &= ~I_WILL_FREE;
|
|
||||||
inodes_stat.nr_unused--;
|
|
||||||
hlist_del_init(&inode->i_hash);
|
|
||||||
}
|
|
||||||
list_del_init(&inode->i_list);
|
|
||||||
list_del_init(&inode->i_sb_list);
|
|
||||||
inode->i_state |= I_FREEING;
|
|
||||||
inodes_stat.nr_inodes--;
|
|
||||||
spin_unlock(&inode_lock);
|
|
||||||
truncate_hugepages(inode, 0);
|
truncate_hugepages(inode, 0);
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
destroy_inode(inode);
|
destroy_inode(inode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void hugetlbfs_drop_inode(struct inode *inode)
|
static void hugetlbfs_drop_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
|
|
21
fs/inode.c
21
fs/inode.c
|
@ -1241,7 +1241,16 @@ void generic_delete_inode(struct inode *inode)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(generic_delete_inode);
|
EXPORT_SYMBOL(generic_delete_inode);
|
||||||
|
|
||||||
static void generic_forget_inode(struct inode *inode)
|
/**
|
||||||
|
* generic_detach_inode - remove inode from inode lists
|
||||||
|
* @inode: inode to remove
|
||||||
|
*
|
||||||
|
* Remove inode from inode lists, write it if it's dirty. This is just an
|
||||||
|
* internal VFS helper exported for hugetlbfs. Do not use!
|
||||||
|
*
|
||||||
|
* Returns 1 if inode should be completely destroyed.
|
||||||
|
*/
|
||||||
|
int generic_detach_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
|
|
||||||
|
@ -1251,7 +1260,7 @@ static void generic_forget_inode(struct inode *inode)
|
||||||
inodes_stat.nr_unused++;
|
inodes_stat.nr_unused++;
|
||||||
if (sb->s_flags & MS_ACTIVE) {
|
if (sb->s_flags & MS_ACTIVE) {
|
||||||
spin_unlock(&inode_lock);
|
spin_unlock(&inode_lock);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
WARN_ON(inode->i_state & I_NEW);
|
WARN_ON(inode->i_state & I_NEW);
|
||||||
inode->i_state |= I_WILL_FREE;
|
inode->i_state |= I_WILL_FREE;
|
||||||
|
@ -1269,6 +1278,14 @@ static void generic_forget_inode(struct inode *inode)
|
||||||
inode->i_state |= I_FREEING;
|
inode->i_state |= I_FREEING;
|
||||||
inodes_stat.nr_inodes--;
|
inodes_stat.nr_inodes--;
|
||||||
spin_unlock(&inode_lock);
|
spin_unlock(&inode_lock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(generic_detach_inode);
|
||||||
|
|
||||||
|
static void generic_forget_inode(struct inode *inode)
|
||||||
|
{
|
||||||
|
if (!generic_detach_inode(inode))
|
||||||
|
return;
|
||||||
if (inode->i_data.nrpages)
|
if (inode->i_data.nrpages)
|
||||||
truncate_inode_pages(&inode->i_data, 0);
|
truncate_inode_pages(&inode->i_data, 0);
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
|
|
|
@ -2156,6 +2156,7 @@ extern ino_t iunique(struct super_block *, ino_t);
|
||||||
extern int inode_needs_sync(struct inode *inode);
|
extern int inode_needs_sync(struct inode *inode);
|
||||||
extern void generic_delete_inode(struct inode *inode);
|
extern void generic_delete_inode(struct inode *inode);
|
||||||
extern void generic_drop_inode(struct inode *inode);
|
extern void generic_drop_inode(struct inode *inode);
|
||||||
|
extern int generic_detach_inode(struct inode *inode);
|
||||||
|
|
||||||
extern struct inode *ilookup5_nowait(struct super_block *sb,
|
extern struct inode *ilookup5_nowait(struct super_block *sb,
|
||||||
unsigned long hashval, int (*test)(struct inode *, void *),
|
unsigned long hashval, int (*test)(struct inode *, void *),
|
||||||
|
|
Loading…
Reference in a new issue