Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+78 -48
+3 -3
fs/9p/vfs_file.c
··· 74 74 v9fs_proto_dotu(v9ses)); 75 75 fid = file->private_data; 76 76 if (!fid) { 77 - fid = v9fs_fid_clone(file->f_path.dentry); 77 + fid = v9fs_fid_clone(file_dentry(file)); 78 78 if (IS_ERR(fid)) 79 79 return PTR_ERR(fid); 80 80 ··· 100 100 * because we want write after unlink usecase 101 101 * to work. 102 102 */ 103 - fid = v9fs_writeback_fid(file->f_path.dentry); 103 + fid = v9fs_writeback_fid(file_dentry(file)); 104 104 if (IS_ERR(fid)) { 105 105 err = PTR_ERR(fid); 106 106 mutex_unlock(&v9inode->v_mutex); ··· 516 516 * because we want write after unlink usecase 517 517 * to work. 518 518 */ 519 - fid = v9fs_writeback_fid(filp->f_path.dentry); 519 + fid = v9fs_writeback_fid(file_dentry(filp)); 520 520 if (IS_ERR(fid)) { 521 521 retval = PTR_ERR(fid); 522 522 mutex_unlock(&v9inode->v_mutex);
+3 -7
fs/ceph/export.c
··· 95 95 } 96 96 97 97 dentry = d_obtain_alias(inode); 98 - if (IS_ERR(dentry)) { 99 - iput(inode); 98 + if (IS_ERR(dentry)) 100 99 return dentry; 101 - } 102 100 err = ceph_init_dentry(dentry); 103 101 if (err < 0) { 104 102 dput(dentry); ··· 165 167 return ERR_PTR(-ENOENT); 166 168 167 169 dentry = d_obtain_alias(inode); 168 - if (IS_ERR(dentry)) { 169 - iput(inode); 170 + if (IS_ERR(dentry)) 170 171 return dentry; 171 - } 172 172 err = ceph_init_dentry(dentry); 173 173 if (err < 0) { 174 174 dput(dentry); ··· 206 210 207 211 dout("fh_to_parent %llx\n", cfh->parent_ino); 208 212 dentry = __get_parent(sb, NULL, cfh->ino); 209 - if (IS_ERR(dentry) && PTR_ERR(dentry) == -ENOENT) 213 + if (unlikely(dentry == ERR_PTR(-ENOENT))) 210 214 dentry = __fh_to_dentry(sb, cfh->parent_ino); 211 215 return dentry; 212 216 }
+71 -38
fs/libfs.c
··· 84 84 } 85 85 EXPORT_SYMBOL(dcache_dir_close); 86 86 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 + 87 142 loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) 88 143 { 89 144 struct dentry *dentry = file->f_path.dentry; ··· 154 99 if (offset != file->f_pos) { 155 100 file->f_pos = offset; 156 101 if (file->f_pos >= 2) { 157 - struct list_head *p; 158 102 struct dentry *cursor = file->private_data; 103 + struct dentry *to; 159 104 loff_t n = file->f_pos - 2; 160 105 161 - spin_lock(&dentry->d_lock); 162 - /* d_lock not required for cursor */ 163 - list_del(&cursor->d_child); 164 - p = dentry->d_subdirs.next; 165 - while (n && p != &dentry->d_subdirs) { 166 - struct dentry *next; 167 - next = list_entry(p, struct dentry, d_child); 168 - spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); 169 - if (simple_positive(next)) 170 - n--; 171 - spin_unlock(&next->d_lock); 172 - p = p->next; 173 - } 174 - list_add_tail(&cursor->d_child, p); 175 - spin_unlock(&dentry->d_lock); 106 + inode_lock_shared(dentry->d_inode); 107 + to = next_positive(dentry, &dentry->d_subdirs, n); 108 + move_cursor(cursor, to ? &to->d_child : NULL); 109 + inode_unlock_shared(dentry->d_inode); 176 110 } 177 111 } 178 112 return offset; ··· 184 140 { 185 141 struct dentry *dentry = file->f_path.dentry; 186 142 struct dentry *cursor = file->private_data; 187 - struct list_head *p, *q = &cursor->d_child; 143 + struct list_head *p = &cursor->d_child; 144 + struct dentry *next; 145 + bool moved = false; 188 146 189 147 if (!dir_emit_dots(file, ctx)) 190 148 return 0; 191 - spin_lock(&dentry->d_lock); 149 + 192 150 if (ctx->pos == 2) 193 - list_move(q, &dentry->d_subdirs); 194 - 195 - for (p = q->next; p != &dentry->d_subdirs; p = p->next) { 196 - struct dentry *next = list_entry(p, struct dentry, d_child); 197 - spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); 198 - if (!simple_positive(next)) { 199 - spin_unlock(&next->d_lock); 200 - continue; 201 - } 202 - 203 - spin_unlock(&next->d_lock); 204 - spin_unlock(&dentry->d_lock); 151 + p = &dentry->d_subdirs; 152 + while ((next = next_positive(dentry, p, 1)) != NULL) { 205 153 if (!dir_emit(ctx, next->d_name.name, next->d_name.len, 206 154 d_inode(next)->i_ino, dt_type(d_inode(next)))) 207 - return 0; 208 - spin_lock(&dentry->d_lock); 209 - spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); 210 - /* next is still alive */ 211 - list_move(q, p); 212 - spin_unlock(&next->d_lock); 213 - p = q; 155 + break; 156 + moved = true; 157 + p = &next->d_child; 214 158 ctx->pos++; 215 159 } 216 - spin_unlock(&dentry->d_lock); 160 + if (moved) 161 + move_cursor(cursor, p); 217 162 return 0; 218 163 } 219 164 EXPORT_SYMBOL(dcache_readdir);
+1
fs/namespace.c
··· 1562 1562 goto out_unlock; 1563 1563 1564 1564 lock_mount_hash(); 1565 + event++; 1565 1566 while (!hlist_empty(&mp->m_list)) { 1566 1567 mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); 1567 1568 if (mnt->mnt.mnt_flags & MNT_UMOUNT) {