Skip to content

Commit 26b6c98

Browse files
author
Al Viro
committed
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: Al Viro <[email protected]>
1 parent d4f4de5 commit 26b6c98

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

fs/libfs.c

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,13 @@ EXPORT_SYMBOL(dcache_dir_close);
9292
/*
9393
* Returns an element of siblings' list.
9494
* We are looking for <count>th positive after <p>; if
95-
* found, dentry is grabbed and passed to caller via *<res>.
96-
* If no such element exists, the anchor of list is returned
97-
* and *<res> is set to NULL.
95+
* found, dentry is grabbed and returned to caller.
96+
* If no such element exists, NULL is returned.
9897
*/
99-
static struct list_head *scan_positives(struct dentry *cursor,
98+
static struct dentry *scan_positives(struct dentry *cursor,
10099
struct list_head *p,
101100
loff_t count,
102-
struct dentry **res)
101+
struct dentry *last)
103102
{
104103
struct dentry *dentry = cursor->d_parent, *found = NULL;
105104

@@ -127,9 +126,8 @@ static struct list_head *scan_positives(struct dentry *cursor,
127126
}
128127
}
129128
spin_unlock(&dentry->d_lock);
130-
dput(*res);
131-
*res = found;
132-
return p;
129+
dput(last);
130+
return found;
133131
}
134132

135133
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)
149147
if (offset != file->f_pos) {
150148
struct dentry *cursor = file->private_data;
151149
struct dentry *to = NULL;
152-
struct list_head *p;
153150

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

157-
if (file->f_pos > 2) {
158-
p = scan_positives(cursor, &dentry->d_subdirs,
159-
file->f_pos - 2, &to);
160-
spin_lock(&dentry->d_lock);
161-
list_move(&cursor->d_child, p);
162-
spin_unlock(&dentry->d_lock);
163-
} else {
164-
spin_lock(&dentry->d_lock);
153+
if (offset > 2)
154+
to = scan_positives(cursor, &dentry->d_subdirs,
155+
offset - 2, NULL);
156+
spin_lock(&dentry->d_lock);
157+
if (to)
158+
list_move(&cursor->d_child, &to->d_child);
159+
else
165160
list_del_init(&cursor->d_child);
166-
spin_unlock(&dentry->d_lock);
167-
}
168-
161+
spin_unlock(&dentry->d_lock);
169162
dput(to);
170163

164+
file->f_pos = offset;
165+
171166
inode_unlock_shared(dentry->d_inode);
172167
}
173168
return offset;
@@ -199,17 +194,23 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
199194

200195
if (ctx->pos == 2)
201196
p = anchor;
202-
else
197+
else if (!list_empty(&cursor->d_child))
203198
p = &cursor->d_child;
199+
else
200+
return 0;
204201

205-
while ((p = scan_positives(cursor, p, 1, &next)) != anchor) {
202+
while ((next = scan_positives(cursor, p, 1, next)) != NULL) {
206203
if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
207204
d_inode(next)->i_ino, dt_type(d_inode(next))))
208205
break;
209206
ctx->pos++;
207+
p = &next->d_child;
210208
}
211209
spin_lock(&dentry->d_lock);
212-
list_move_tail(&cursor->d_child, p);
210+
if (next)
211+
list_move_tail(&cursor->d_child, &next->d_child);
212+
else
213+
list_del_init(&cursor->d_child);
213214
spin_unlock(&dentry->d_lock);
214215
dput(next);
215216

0 commit comments

Comments
 (0)