Skip to content

Commit

Permalink
libfs: take cursors out of list when moving past the end of directory
Browse files Browse the repository at this point in the history
that eliminates the last place where we accessed the tail of ->d_subdirs

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Al Viro committed Oct 10, 2019
1 parent d4f4de5 commit 26b6c98
Showing 1 changed file with 25 additions and 24 deletions.
49 changes: 25 additions & 24 deletions fs/libfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,13 @@ EXPORT_SYMBOL(dcache_dir_close);
/*
* Returns an element of siblings' list.
* We are looking for <count>th positive after <p>; if
* found, dentry is grabbed and passed to caller via *<res>.
* If no such element exists, the anchor of list is returned
* and *<res> is set to NULL.
* found, dentry is grabbed and returned to caller.
* If no such element exists, NULL is returned.
*/
static struct list_head *scan_positives(struct dentry *cursor,
static struct dentry *scan_positives(struct dentry *cursor,
struct list_head *p,
loff_t count,
struct dentry **res)
struct dentry *last)
{
struct dentry *dentry = cursor->d_parent, *found = NULL;

Expand Down Expand Up @@ -127,9 +126,8 @@ static struct list_head *scan_positives(struct dentry *cursor,
}
}
spin_unlock(&dentry->d_lock);
dput(*res);
*res = found;
return p;
dput(last);
return found;
}

loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
Expand All @@ -149,25 +147,22 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
if (offset != file->f_pos) {
struct dentry *cursor = file->private_data;
struct dentry *to = NULL;
struct list_head *p;

file->f_pos = offset;
inode_lock_shared(dentry->d_inode);

if (file->f_pos > 2) {
p = scan_positives(cursor, &dentry->d_subdirs,
file->f_pos - 2, &to);
spin_lock(&dentry->d_lock);
list_move(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
} else {
spin_lock(&dentry->d_lock);
if (offset > 2)
to = scan_positives(cursor, &dentry->d_subdirs,
offset - 2, NULL);
spin_lock(&dentry->d_lock);
if (to)
list_move(&cursor->d_child, &to->d_child);
else
list_del_init(&cursor->d_child);
spin_unlock(&dentry->d_lock);
}

spin_unlock(&dentry->d_lock);
dput(to);

file->f_pos = offset;

inode_unlock_shared(dentry->d_inode);
}
return offset;
Expand Down Expand Up @@ -199,17 +194,23 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)

if (ctx->pos == 2)
p = anchor;
else
else if (!list_empty(&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,
d_inode(next)->i_ino, dt_type(d_inode(next))))
break;
ctx->pos++;
p = &next->d_child;
}
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);
dput(next);

Expand Down

0 comments on commit 26b6c98

Please sign in to comment.