提交 26b6c984 编写于 作者: A Al Viro

libfs: take cursors out of list when moving past the end of directory

that eliminates the last place where we accessed the tail of ->d_subdirs
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
上级 d4f4de5e
...@@ -92,14 +92,13 @@ EXPORT_SYMBOL(dcache_dir_close); ...@@ -92,14 +92,13 @@ EXPORT_SYMBOL(dcache_dir_close);
/* /*
* Returns an element of siblings' list. * Returns an element of siblings' list.
* We are looking for <count>th positive after <p>; if * We are looking for <count>th positive after <p>; if
* found, dentry is grabbed and passed to caller via *<res>. * found, dentry is grabbed and returned to caller.
* If no such element exists, the anchor of list is returned * If no such element exists, NULL is returned.
* and *<res> is set to NULL.
*/ */
static struct list_head *scan_positives(struct dentry *cursor, static struct dentry *scan_positives(struct dentry *cursor,
struct list_head *p, struct list_head *p,
loff_t count, loff_t count,
struct dentry **res) struct dentry *last)
{ {
struct dentry *dentry = cursor->d_parent, *found = NULL; struct dentry *dentry = cursor->d_parent, *found = NULL;
...@@ -127,9 +126,8 @@ static struct list_head *scan_positives(struct dentry *cursor, ...@@ -127,9 +126,8 @@ static struct list_head *scan_positives(struct dentry *cursor,
} }
} }
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
dput(*res); dput(last);
*res = found; return found;
return p;
} }
loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
...@@ -149,25 +147,22 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) ...@@ -149,25 +147,22 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
if (offset != file->f_pos) { if (offset != file->f_pos) {
struct dentry *cursor = file->private_data; struct dentry *cursor = file->private_data;
struct dentry *to = NULL; struct dentry *to = NULL;
struct list_head *p;
file->f_pos = offset;
inode_lock_shared(dentry->d_inode); inode_lock_shared(dentry->d_inode);
if (file->f_pos > 2) { if (offset > 2)
p = scan_positives(cursor, &dentry->d_subdirs, to = scan_positives(cursor, &dentry->d_subdirs,
file->f_pos - 2, &to); offset - 2, NULL);
spin_lock(&dentry->d_lock);
list_move(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
} else {
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
if (to)
list_move(&cursor->d_child, &to->d_child);
else
list_del_init(&cursor->d_child); list_del_init(&cursor->d_child);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
}
dput(to); dput(to);
file->f_pos = offset;
inode_unlock_shared(dentry->d_inode); inode_unlock_shared(dentry->d_inode);
} }
return offset; return offset;
...@@ -199,17 +194,23 @@ int dcache_readdir(struct file *file, struct dir_context *ctx) ...@@ -199,17 +194,23 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
if (ctx->pos == 2) if (ctx->pos == 2)
p = anchor; p = anchor;
else else if (!list_empty(&cursor->d_child))
p = &cursor->d_child; p = &cursor->d_child;
else
return 0;
while ((p = scan_positives(cursor, p, 1, &next)) != anchor) { while ((next = scan_positives(cursor, p, 1, next)) != NULL) {
if (!dir_emit(ctx, next->d_name.name, next->d_name.len, if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
d_inode(next)->i_ino, dt_type(d_inode(next)))) d_inode(next)->i_ino, dt_type(d_inode(next))))
break; break;
ctx->pos++; ctx->pos++;
p = &next->d_child;
} }
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
list_move_tail(&cursor->d_child, p); if (next)
list_move_tail(&cursor->d_child, &next->d_child);
else
list_del_init(&cursor->d_child);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
dput(next); dput(next);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册