Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (107 commits) vfs: use ERR_CAST for err-ptr tossing in lookup_instantiate_filp isofs: Remove global fs lock jffs2: fix IN_DELETE_SELF on overwriting rename() killing a directory fix IN_DELETE_SELF on overwriting rename() on ramfs et.al. mm/truncate.c: fix build for CONFIG_BLOCK not enabled fs:update the NOTE of the file_operations structure Remove dead code in dget_parent() AFS: Fix silly characters in a comment switch d_add_ci() to d_splice_alias() in "found negative" case as well simplify gfs2_lookup() jfs_lookup(): don't bother with . or .. get rid of useless dget_parent() in btrfs rename() and link() get rid of useless dget_parent() in fs/btrfs/ioctl.c fs: push i_mutex and filemap_write_and_wait down into ->fsync() handlers drivers: fix up various ->llseek() implementations fs: handle SEEK_HOLE/SEEK_DATA properly in all fs's that define their own llseek Ext4: handle SEEK_HOLE/SEEK_DATA generically Btrfs: implement our own ->llseek fs: add SEEK_HOLE and SEEK_DATA flags reiserfs: make reiserfs default to barrier=flush ... Fix up trivial conflicts in fs/xfs/linux-2.6/xfs_super.c due to the new shrinker callout for the inode cache, that clashed with the xfs code to start the periodic workers later.
This commit is contained in:
262
fs/dcache.c
262
fs/dcache.c
@@ -343,6 +343,24 @@ void d_drop(struct dentry *dentry)
|
||||
}
|
||||
EXPORT_SYMBOL(d_drop);
|
||||
|
||||
/*
|
||||
* d_clear_need_lookup - drop a dentry from cache and clear the need lookup flag
|
||||
* @dentry: dentry to drop
|
||||
*
|
||||
* This is called when we do a lookup on a placeholder dentry that needed to be
|
||||
* looked up. The dentry should have been hashed in order for it to be found by
|
||||
* the lookup code, but now needs to be unhashed while we do the actual lookup
|
||||
* and clear the DCACHE_NEED_LOOKUP flag.
|
||||
*/
|
||||
void d_clear_need_lookup(struct dentry *dentry)
|
||||
{
|
||||
spin_lock(&dentry->d_lock);
|
||||
__d_drop(dentry);
|
||||
dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(d_clear_need_lookup);
|
||||
|
||||
/*
|
||||
* Finish off a dentry we've decided to kill.
|
||||
* dentry->d_lock must be held, returns with it unlocked.
|
||||
@@ -432,8 +450,13 @@ repeat:
|
||||
if (d_unhashed(dentry))
|
||||
goto kill_it;
|
||||
|
||||
/* Otherwise leave it cached and ensure it's on the LRU */
|
||||
dentry->d_flags |= DCACHE_REFERENCED;
|
||||
/*
|
||||
* If this dentry needs lookup, don't set the referenced flag so that it
|
||||
* is more likely to be cleaned up by the dcache shrinker in case of
|
||||
* memory pressure.
|
||||
*/
|
||||
if (!d_need_lookup(dentry))
|
||||
dentry->d_flags |= DCACHE_REFERENCED;
|
||||
dentry_lru_add(dentry);
|
||||
|
||||
dentry->d_count--;
|
||||
@@ -526,10 +549,6 @@ repeat:
|
||||
*/
|
||||
rcu_read_lock();
|
||||
ret = dentry->d_parent;
|
||||
if (!ret) {
|
||||
rcu_read_unlock();
|
||||
goto out;
|
||||
}
|
||||
spin_lock(&ret->d_lock);
|
||||
if (unlikely(ret != dentry->d_parent)) {
|
||||
spin_unlock(&ret->d_lock);
|
||||
@@ -540,7 +559,6 @@ repeat:
|
||||
BUG_ON(!ret->d_count);
|
||||
ret->d_count++;
|
||||
spin_unlock(&ret->d_lock);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dget_parent);
|
||||
@@ -720,13 +738,11 @@ static void shrink_dentry_list(struct list_head *list)
|
||||
*
|
||||
* If flags contains DCACHE_REFERENCED reference dentries will not be pruned.
|
||||
*/
|
||||
static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags)
|
||||
static void __shrink_dcache_sb(struct super_block *sb, int count, int flags)
|
||||
{
|
||||
/* called from prune_dcache() and shrink_dcache_parent() */
|
||||
struct dentry *dentry;
|
||||
LIST_HEAD(referenced);
|
||||
LIST_HEAD(tmp);
|
||||
int cnt = *count;
|
||||
|
||||
relock:
|
||||
spin_lock(&dcache_lru_lock);
|
||||
@@ -754,7 +770,7 @@ relock:
|
||||
} else {
|
||||
list_move_tail(&dentry->d_lru, &tmp);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
if (!--cnt)
|
||||
if (!--count)
|
||||
break;
|
||||
}
|
||||
cond_resched_lock(&dcache_lru_lock);
|
||||
@@ -764,83 +780,22 @@ relock:
|
||||
spin_unlock(&dcache_lru_lock);
|
||||
|
||||
shrink_dentry_list(&tmp);
|
||||
|
||||
*count = cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* prune_dcache - shrink the dcache
|
||||
* @count: number of entries to try to free
|
||||
* prune_dcache_sb - shrink the dcache
|
||||
* @nr_to_scan: number of entries to try to free
|
||||
*
|
||||
* Shrink the dcache. This is done when we need more memory, or simply when we
|
||||
* need to unmount something (at which point we need to unuse all dentries).
|
||||
* Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is
|
||||
* done when we need more memory an called from the superblock shrinker
|
||||
* function.
|
||||
*
|
||||
* This function may fail to free any resources if all the dentries are in use.
|
||||
* This function may fail to free any resources if all the dentries are in
|
||||
* use.
|
||||
*/
|
||||
static void prune_dcache(int count)
|
||||
void prune_dcache_sb(struct super_block *sb, int nr_to_scan)
|
||||
{
|
||||
struct super_block *sb, *p = NULL;
|
||||
int w_count;
|
||||
int unused = dentry_stat.nr_unused;
|
||||
int prune_ratio;
|
||||
int pruned;
|
||||
|
||||
if (unused == 0 || count == 0)
|
||||
return;
|
||||
if (count >= unused)
|
||||
prune_ratio = 1;
|
||||
else
|
||||
prune_ratio = unused / count;
|
||||
spin_lock(&sb_lock);
|
||||
list_for_each_entry(sb, &super_blocks, s_list) {
|
||||
if (list_empty(&sb->s_instances))
|
||||
continue;
|
||||
if (sb->s_nr_dentry_unused == 0)
|
||||
continue;
|
||||
sb->s_count++;
|
||||
/* Now, we reclaim unused dentrins with fairness.
|
||||
* We reclaim them same percentage from each superblock.
|
||||
* We calculate number of dentries to scan on this sb
|
||||
* as follows, but the implementation is arranged to avoid
|
||||
* overflows:
|
||||
* number of dentries to scan on this sb =
|
||||
* count * (number of dentries on this sb /
|
||||
* number of dentries in the machine)
|
||||
*/
|
||||
spin_unlock(&sb_lock);
|
||||
if (prune_ratio != 1)
|
||||
w_count = (sb->s_nr_dentry_unused / prune_ratio) + 1;
|
||||
else
|
||||
w_count = sb->s_nr_dentry_unused;
|
||||
pruned = w_count;
|
||||
/*
|
||||
* We need to be sure this filesystem isn't being unmounted,
|
||||
* otherwise we could race with generic_shutdown_super(), and
|
||||
* end up holding a reference to an inode while the filesystem
|
||||
* is unmounted. So we try to get s_umount, and make sure
|
||||
* s_root isn't NULL.
|
||||
*/
|
||||
if (down_read_trylock(&sb->s_umount)) {
|
||||
if ((sb->s_root != NULL) &&
|
||||
(!list_empty(&sb->s_dentry_lru))) {
|
||||
__shrink_dcache_sb(sb, &w_count,
|
||||
DCACHE_REFERENCED);
|
||||
pruned -= w_count;
|
||||
}
|
||||
up_read(&sb->s_umount);
|
||||
}
|
||||
spin_lock(&sb_lock);
|
||||
if (p)
|
||||
__put_super(p);
|
||||
count -= pruned;
|
||||
p = sb;
|
||||
/* more work left to do? */
|
||||
if (count <= 0)
|
||||
break;
|
||||
}
|
||||
if (p)
|
||||
__put_super(p);
|
||||
spin_unlock(&sb_lock);
|
||||
__shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1215,45 +1170,13 @@ void shrink_dcache_parent(struct dentry * parent)
|
||||
int found;
|
||||
|
||||
while ((found = select_parent(parent)) != 0)
|
||||
__shrink_dcache_sb(sb, &found, 0);
|
||||
__shrink_dcache_sb(sb, found, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(shrink_dcache_parent);
|
||||
|
||||
/*
|
||||
* Scan `sc->nr_slab_to_reclaim' dentries and return the number which remain.
|
||||
*
|
||||
* We need to avoid reentering the filesystem if the caller is performing a
|
||||
* GFP_NOFS allocation attempt. One example deadlock is:
|
||||
*
|
||||
* ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->
|
||||
* prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->put_inode->
|
||||
* ext2_discard_prealloc->ext2_free_blocks->lock_super->DEADLOCK.
|
||||
*
|
||||
* In this case we return -1 to tell the caller that we baled.
|
||||
*/
|
||||
static int shrink_dcache_memory(struct shrinker *shrink,
|
||||
struct shrink_control *sc)
|
||||
{
|
||||
int nr = sc->nr_to_scan;
|
||||
gfp_t gfp_mask = sc->gfp_mask;
|
||||
|
||||
if (nr) {
|
||||
if (!(gfp_mask & __GFP_FS))
|
||||
return -1;
|
||||
prune_dcache(nr);
|
||||
}
|
||||
|
||||
return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
|
||||
}
|
||||
|
||||
static struct shrinker dcache_shrinker = {
|
||||
.shrink = shrink_dcache_memory,
|
||||
.seeks = DEFAULT_SEEKS,
|
||||
};
|
||||
|
||||
/**
|
||||
* d_alloc - allocate a dcache entry
|
||||
* @parent: parent of entry to allocate
|
||||
* __d_alloc - allocate a dcache entry
|
||||
* @sb: filesystem it will belong to
|
||||
* @name: qstr of the name
|
||||
*
|
||||
* Allocates a dentry. It returns %NULL if there is insufficient memory
|
||||
@@ -1261,7 +1184,7 @@ static struct shrinker dcache_shrinker = {
|
||||
* copied and the copy passed in may be reused after this call.
|
||||
*/
|
||||
|
||||
struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
|
||||
struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
char *dname;
|
||||
@@ -1291,8 +1214,8 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
|
||||
spin_lock_init(&dentry->d_lock);
|
||||
seqcount_init(&dentry->d_seq);
|
||||
dentry->d_inode = NULL;
|
||||
dentry->d_parent = NULL;
|
||||
dentry->d_sb = NULL;
|
||||
dentry->d_parent = dentry;
|
||||
dentry->d_sb = sb;
|
||||
dentry->d_op = NULL;
|
||||
dentry->d_fsdata = NULL;
|
||||
INIT_HLIST_BL_NODE(&dentry->d_hash);
|
||||
@@ -1300,36 +1223,47 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
|
||||
INIT_LIST_HEAD(&dentry->d_subdirs);
|
||||
INIT_LIST_HEAD(&dentry->d_alias);
|
||||
INIT_LIST_HEAD(&dentry->d_u.d_child);
|
||||
|
||||
if (parent) {
|
||||
spin_lock(&parent->d_lock);
|
||||
/*
|
||||
* don't need child lock because it is not subject
|
||||
* to concurrency here
|
||||
*/
|
||||
__dget_dlock(parent);
|
||||
dentry->d_parent = parent;
|
||||
dentry->d_sb = parent->d_sb;
|
||||
d_set_d_op(dentry, dentry->d_sb->s_d_op);
|
||||
list_add(&dentry->d_u.d_child, &parent->d_subdirs);
|
||||
spin_unlock(&parent->d_lock);
|
||||
}
|
||||
d_set_d_op(dentry, dentry->d_sb->s_d_op);
|
||||
|
||||
this_cpu_inc(nr_dentry);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* d_alloc - allocate a dcache entry
|
||||
* @parent: parent of entry to allocate
|
||||
* @name: qstr of the name
|
||||
*
|
||||
* Allocates a dentry. It returns %NULL if there is insufficient memory
|
||||
* available. On a success the dentry is returned. The name passed in is
|
||||
* copied and the copy passed in may be reused after this call.
|
||||
*/
|
||||
struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
|
||||
{
|
||||
struct dentry *dentry = __d_alloc(parent->d_sb, name);
|
||||
if (!dentry)
|
||||
return NULL;
|
||||
|
||||
spin_lock(&parent->d_lock);
|
||||
/*
|
||||
* don't need child lock because it is not subject
|
||||
* to concurrency here
|
||||
*/
|
||||
__dget_dlock(parent);
|
||||
dentry->d_parent = parent;
|
||||
list_add(&dentry->d_u.d_child, &parent->d_subdirs);
|
||||
spin_unlock(&parent->d_lock);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
EXPORT_SYMBOL(d_alloc);
|
||||
|
||||
struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
|
||||
{
|
||||
struct dentry *dentry = d_alloc(NULL, name);
|
||||
if (dentry) {
|
||||
dentry->d_sb = sb;
|
||||
d_set_d_op(dentry, dentry->d_sb->s_d_op);
|
||||
dentry->d_parent = dentry;
|
||||
struct dentry *dentry = __d_alloc(sb, name);
|
||||
if (dentry)
|
||||
dentry->d_flags |= DCACHE_DISCONNECTED;
|
||||
}
|
||||
return dentry;
|
||||
}
|
||||
EXPORT_SYMBOL(d_alloc_pseudo);
|
||||
@@ -1499,13 +1433,9 @@ struct dentry * d_alloc_root(struct inode * root_inode)
|
||||
if (root_inode) {
|
||||
static const struct qstr name = { .name = "/", .len = 1 };
|
||||
|
||||
res = d_alloc(NULL, &name);
|
||||
if (res) {
|
||||
res->d_sb = root_inode->i_sb;
|
||||
d_set_d_op(res, res->d_sb->s_d_op);
|
||||
res->d_parent = res;
|
||||
res = __d_alloc(root_inode->i_sb, &name);
|
||||
if (res)
|
||||
d_instantiate(res, root_inode);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1566,13 +1496,11 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
||||
if (res)
|
||||
goto out_iput;
|
||||
|
||||
tmp = d_alloc(NULL, &anonstring);
|
||||
tmp = __d_alloc(inode->i_sb, &anonstring);
|
||||
if (!tmp) {
|
||||
res = ERR_PTR(-ENOMEM);
|
||||
goto out_iput;
|
||||
}
|
||||
tmp->d_parent = tmp; /* make sure dput doesn't croak */
|
||||
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
res = __d_find_any_alias(inode);
|
||||
@@ -1584,8 +1512,6 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
||||
|
||||
/* attach a disconnected dentry */
|
||||
spin_lock(&tmp->d_lock);
|
||||
tmp->d_sb = inode->i_sb;
|
||||
d_set_d_op(tmp, tmp->d_sb->s_d_op);
|
||||
tmp->d_inode = inode;
|
||||
tmp->d_flags |= DCACHE_DISCONNECTED;
|
||||
list_add(&tmp->d_alias, &inode->i_dentry);
|
||||
@@ -1626,6 +1552,9 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
|
||||
{
|
||||
struct dentry *new = NULL;
|
||||
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
if (inode && S_ISDIR(inode->i_mode)) {
|
||||
spin_lock(&inode->i_lock);
|
||||
new = __d_find_alias(inode, 1);
|
||||
@@ -1707,30 +1636,23 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are going to instantiate this dentry, unhash it and clear the
|
||||
* lookup flag so we can do that.
|
||||
*/
|
||||
if (unlikely(d_need_lookup(found)))
|
||||
d_clear_need_lookup(found);
|
||||
|
||||
/*
|
||||
* Negative dentry: instantiate it unless the inode is a directory and
|
||||
* already has a dentry.
|
||||
*/
|
||||
spin_lock(&inode->i_lock);
|
||||
if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) {
|
||||
__d_instantiate(found, inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
security_d_instantiate(found, inode);
|
||||
return found;
|
||||
new = d_splice_alias(inode, found);
|
||||
if (new) {
|
||||
dput(found);
|
||||
found = new;
|
||||
}
|
||||
|
||||
/*
|
||||
* In case a directory already has a (disconnected) entry grab a
|
||||
* reference to it, move it in place and use it.
|
||||
*/
|
||||
new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
|
||||
__dget(new);
|
||||
spin_unlock(&inode->i_lock);
|
||||
security_d_instantiate(found, inode);
|
||||
d_move(new, found);
|
||||
iput(inode);
|
||||
dput(found);
|
||||
return new;
|
||||
return found;
|
||||
|
||||
err_out:
|
||||
iput(inode);
|
||||
@@ -3045,8 +2967,6 @@ static void __init dcache_init(void)
|
||||
*/
|
||||
dentry_cache = KMEM_CACHE(dentry,
|
||||
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
|
||||
|
||||
register_shrinker(&dcache_shrinker);
|
||||
|
||||
/* Hash may have been set up in dcache_init_early */
|
||||
if (!hashdist)
|
||||
|
Reference in New Issue
Block a user