ceph: do not carry i_lock for readdir from dcache

We were taking dcache_lock inside of i_lock, which introduces a dependency
not found elsewhere in the kernel, complicationg the vfs locking
scalability work. Since we don't actually need it here anyway, remove
it.

We only need i_lock to test for the I_COMPLETE flag, so be careful to do
so without dcache_lock held.

Signed-off-by: Sage Weil <sage@newdream.net>

Sage Weil efa4c120 61413c2f

+18 -26
+16 -25
fs/ceph/dir.c
··· 95 95 */ 96 96 static int __dcache_readdir(struct file *filp, 97 97 void *dirent, filldir_t filldir) 98 - __releases(inode->i_lock) 99 - __acquires(inode->i_lock) 100 98 { 101 - struct inode *inode = filp->f_dentry->d_inode; 102 99 struct ceph_file_info *fi = filp->private_data; 103 100 struct dentry *parent = filp->f_dentry; 104 101 struct inode *dir = parent->d_inode; ··· 151 154 152 155 atomic_inc(&dentry->d_count); 153 156 spin_unlock(&dcache_lock); 154 - spin_unlock(&inode->i_lock); 155 157 156 158 dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, 157 159 dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); ··· 168 172 } else { 169 173 dput(last); 170 174 } 171 - last = NULL; 172 175 } 173 - 174 - spin_lock(&inode->i_lock); 175 - spin_lock(&dcache_lock); 176 - 177 176 last = dentry; 178 177 179 178 if (err < 0) 180 - goto out_unlock; 179 + goto out; 181 180 182 - p = p->prev; 183 181 filp->f_pos++; 184 182 185 183 /* make sure a dentry wasn't dropped while we didn't have dcache_lock */ 186 - if ((ceph_inode(dir)->i_ceph_flags & CEPH_I_COMPLETE)) 187 - goto more; 188 - dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); 189 - err = -EAGAIN; 184 + if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { 185 + dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); 186 + err = -EAGAIN; 187 + goto out; 188 + } 189 + 190 + spin_lock(&dcache_lock); 191 + p = p->prev; /* advance to next dentry */ 192 + goto more; 190 193 191 194 out_unlock: 192 195 spin_unlock(&dcache_lock); 193 - 194 - if (last) { 195 - spin_unlock(&inode->i_lock); 196 + out: 197 + if (last) 196 198 dput(last); 197 - spin_lock(&inode->i_lock); 198 - } 199 - 200 199 return err; 201 200 } 202 201 ··· 263 272 ceph_snap(inode) != CEPH_SNAPDIR && 264 273 (ci->i_ceph_flags & CEPH_I_COMPLETE) && 265 274 __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { 275 + spin_unlock(&inode->i_lock); 266 276 err = __dcache_readdir(filp, dirent, filldir); 267 - if (err != -EAGAIN) { 268 - spin_unlock(&inode->i_lock); 277 + if (err != -EAGAIN) 269 278 return err; 270 - } 279 + } else { 280 + spin_unlock(&inode->i_lock); 271 281 } 272 - spin_unlock(&inode->i_lock); 273 282 if (fi->dentry) { 274 283 err = note_last_dentry(fi, fi->dentry->d_name.name, 275 284 fi->dentry->d_name.len);
+2 -1
fs/ceph/super.h
··· 400 400 struct ceph_inode_info *ci = ceph_inode(inode); 401 401 bool r; 402 402 403 - smp_mb(); 403 + spin_lock(&inode->i_lock); 404 404 r = (ci->i_ceph_flags & mask) == mask; 405 + spin_unlock(&inode->i_lock); 405 406 return r; 406 407 } 407 408