Skip to content

Commit 48c4565

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "Tmpfs readdir throughput regression fix (this cycle) + some -stable fodder all over the place. One missing bit is Miklos' tonight locks.c fix - NFS folks had already grabbed that one by the time I woke up ;-)" [ The locks.c fix came through the nfsd tree just moments ago ] * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: namespace: update event counter when umounting a deleted dentry 9p: use file_dentry() ceph: fix d_obtain_alias() misuses lockless next_positive() libfs.c: new helper - next_positive() dcache_{readdir,dir_lseek}(): don't bother with nested ->d_lock
2 parents 2728c57 + e06b933 commit 48c4565

File tree

4 files changed

+78
-48
lines changed

4 files changed

+78
-48
lines changed

fs/9p/vfs_file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
7474
v9fs_proto_dotu(v9ses));
7575
fid = file->private_data;
7676
if (!fid) {
77-
fid = v9fs_fid_clone(file->f_path.dentry);
77+
fid = v9fs_fid_clone(file_dentry(file));
7878
if (IS_ERR(fid))
7979
return PTR_ERR(fid);
8080

@@ -100,7 +100,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
100100
* because we want write after unlink usecase
101101
* to work.
102102
*/
103-
fid = v9fs_writeback_fid(file->f_path.dentry);
103+
fid = v9fs_writeback_fid(file_dentry(file));
104104
if (IS_ERR(fid)) {
105105
err = PTR_ERR(fid);
106106
mutex_unlock(&v9inode->v_mutex);
@@ -516,7 +516,7 @@ v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma)
516516
* because we want write after unlink usecase
517517
* to work.
518518
*/
519-
fid = v9fs_writeback_fid(filp->f_path.dentry);
519+
fid = v9fs_writeback_fid(file_dentry(filp));
520520
if (IS_ERR(fid)) {
521521
retval = PTR_ERR(fid);
522522
mutex_unlock(&v9inode->v_mutex);

fs/ceph/export.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,8 @@ static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
9595
}
9696

9797
dentry = d_obtain_alias(inode);
98-
if (IS_ERR(dentry)) {
99-
iput(inode);
98+
if (IS_ERR(dentry))
10099
return dentry;
101-
}
102100
err = ceph_init_dentry(dentry);
103101
if (err < 0) {
104102
dput(dentry);
@@ -167,10 +165,8 @@ static struct dentry *__get_parent(struct super_block *sb,
167165
return ERR_PTR(-ENOENT);
168166

169167
dentry = d_obtain_alias(inode);
170-
if (IS_ERR(dentry)) {
171-
iput(inode);
168+
if (IS_ERR(dentry))
172169
return dentry;
173-
}
174170
err = ceph_init_dentry(dentry);
175171
if (err < 0) {
176172
dput(dentry);
@@ -210,7 +206,7 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,
210206

211207
dout("fh_to_parent %llx\n", cfh->parent_ino);
212208
dentry = __get_parent(sb, NULL, cfh->ino);
213-
if (IS_ERR(dentry) && PTR_ERR(dentry) == -ENOENT)
209+
if (unlikely(dentry == ERR_PTR(-ENOENT)))
214210
dentry = __fh_to_dentry(sb, cfh->parent_ino);
215211
return dentry;
216212
}

fs/libfs.c

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,61 @@ int dcache_dir_close(struct inode *inode, struct file *file)
8484
}
8585
EXPORT_SYMBOL(dcache_dir_close);
8686

87+
/* parent is locked at least shared */
88+
static struct dentry *next_positive(struct dentry *parent,
89+
struct list_head *from,
90+
int count)
91+
{
92+
unsigned *seq = &parent->d_inode->i_dir_seq, n;
93+
struct dentry *res;
94+
struct list_head *p;
95+
bool skipped;
96+
int i;
97+
98+
retry:
99+
i = count;
100+
skipped = false;
101+
n = smp_load_acquire(seq) & ~1;
102+
res = NULL;
103+
rcu_read_lock();
104+
for (p = from->next; p != &parent->d_subdirs; p = p->next) {
105+
struct dentry *d = list_entry(p, struct dentry, d_child);
106+
if (!simple_positive(d)) {
107+
skipped = true;
108+
} else if (!--i) {
109+
res = d;
110+
break;
111+
}
112+
}
113+
rcu_read_unlock();
114+
if (skipped) {
115+
smp_rmb();
116+
if (unlikely(*seq != n))
117+
goto retry;
118+
}
119+
return res;
120+
}
121+
122+
static void move_cursor(struct dentry *cursor, struct list_head *after)
123+
{
124+
struct dentry *parent = cursor->d_parent;
125+
unsigned n, *seq = &parent->d_inode->i_dir_seq;
126+
spin_lock(&parent->d_lock);
127+
for (;;) {
128+
n = *seq;
129+
if (!(n & 1) && cmpxchg(seq, n, n + 1) == n)
130+
break;
131+
cpu_relax();
132+
}
133+
__list_del(cursor->d_child.prev, cursor->d_child.next);
134+
if (after)
135+
list_add(&cursor->d_child, after);
136+
else
137+
list_add_tail(&cursor->d_child, &parent->d_subdirs);
138+
smp_store_release(seq, n + 2);
139+
spin_unlock(&parent->d_lock);
140+
}
141+
87142
loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
88143
{
89144
struct dentry *dentry = file->f_path.dentry;
@@ -99,25 +154,14 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
99154
if (offset != file->f_pos) {
100155
file->f_pos = offset;
101156
if (file->f_pos >= 2) {
102-
struct list_head *p;
103157
struct dentry *cursor = file->private_data;
158+
struct dentry *to;
104159
loff_t n = file->f_pos - 2;
105160

106-
spin_lock(&dentry->d_lock);
107-
/* d_lock not required for cursor */
108-
list_del(&cursor->d_child);
109-
p = dentry->d_subdirs.next;
110-
while (n && p != &dentry->d_subdirs) {
111-
struct dentry *next;
112-
next = list_entry(p, struct dentry, d_child);
113-
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
114-
if (simple_positive(next))
115-
n--;
116-
spin_unlock(&next->d_lock);
117-
p = p->next;
118-
}
119-
list_add_tail(&cursor->d_child, p);
120-
spin_unlock(&dentry->d_lock);
161+
inode_lock_shared(dentry->d_inode);
162+
to = next_positive(dentry, &dentry->d_subdirs, n);
163+
move_cursor(cursor, to ? &to->d_child : NULL);
164+
inode_unlock_shared(dentry->d_inode);
121165
}
122166
}
123167
return offset;
@@ -140,36 +184,25 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
140184
{
141185
struct dentry *dentry = file->f_path.dentry;
142186
struct dentry *cursor = file->private_data;
143-
struct list_head *p, *q = &cursor->d_child;
187+
struct list_head *p = &cursor->d_child;
188+
struct dentry *next;
189+
bool moved = false;
144190

145191
if (!dir_emit_dots(file, ctx))
146192
return 0;
147-
spin_lock(&dentry->d_lock);
148-
if (ctx->pos == 2)
149-
list_move(q, &dentry->d_subdirs);
150193

151-
for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
152-
struct dentry *next = list_entry(p, struct dentry, d_child);
153-
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
154-
if (!simple_positive(next)) {
155-
spin_unlock(&next->d_lock);
156-
continue;
157-
}
158-
159-
spin_unlock(&next->d_lock);
160-
spin_unlock(&dentry->d_lock);
194+
if (ctx->pos == 2)
195+
p = &dentry->d_subdirs;
196+
while ((next = next_positive(dentry, p, 1)) != NULL) {
161197
if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
162198
d_inode(next)->i_ino, dt_type(d_inode(next))))
163-
return 0;
164-
spin_lock(&dentry->d_lock);
165-
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
166-
/* next is still alive */
167-
list_move(q, p);
168-
spin_unlock(&next->d_lock);
169-
p = q;
199+
break;
200+
moved = true;
201+
p = &next->d_child;
170202
ctx->pos++;
171203
}
172-
spin_unlock(&dentry->d_lock);
204+
if (moved)
205+
move_cursor(cursor, p);
173206
return 0;
174207
}
175208
EXPORT_SYMBOL(dcache_readdir);

fs/namespace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,7 @@ void __detach_mounts(struct dentry *dentry)
15621562
goto out_unlock;
15631563

15641564
lock_mount_hash();
1565+
event++;
15651566
while (!hlist_empty(&mp->m_list)) {
15661567
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
15671568
if (mnt->mnt.mnt_flags & MNT_UMOUNT) {

0 commit comments

Comments
 (0)