aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-10-18 17:04:31 -0400
committerSage Weil <sage@newdream.net>2010-10-20 18:38:27 -0400
commitefa4c1206eaff047c474af2136748a58eb8cc33b (patch)
tree61f8957ed7735c01a6d6900a3c4c2c45d084c3a7
parent61413c2f594e6b63db2b14c70c2e7d8cf02f9c00 (diff)
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>
-rw-r--r--fs/ceph/dir.c41
-rw-r--r--fs/ceph/super.h3
2 files changed, 18 insertions, 26 deletions
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 495825268cb9..e0a2dc6fcafc 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -95,10 +95,7 @@ static unsigned fpos_off(loff_t p)
95 */ 95 */
96static int __dcache_readdir(struct file *filp, 96static int __dcache_readdir(struct file *filp,
97 void *dirent, filldir_t filldir) 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 struct ceph_file_info *fi = filp->private_data; 99 struct ceph_file_info *fi = filp->private_data;
103 struct dentry *parent = filp->f_dentry; 100 struct dentry *parent = filp->f_dentry;
104 struct inode *dir = parent->d_inode; 101 struct inode *dir = parent->d_inode;
@@ -154,7 +151,6 @@ more:
154 151
155 atomic_inc(&dentry->d_count); 152 atomic_inc(&dentry->d_count);
156 spin_unlock(&dcache_lock); 153 spin_unlock(&dcache_lock);
157 spin_unlock(&inode->i_lock);
158 154
159 dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, 155 dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
160 dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); 156 dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
@@ -172,35 +168,30 @@ more:
172 } else { 168 } else {
173 dput(last); 169 dput(last);
174 } 170 }
175 last = NULL;
176 } 171 }
177
178 spin_lock(&inode->i_lock);
179 spin_lock(&dcache_lock);
180
181 last = dentry; 172 last = dentry;
182 173
183 if (err < 0) 174 if (err < 0)
184 goto out_unlock; 175 goto out;
185 176
186 p = p->prev;
187 filp->f_pos++; 177 filp->f_pos++;
188 178
189 /* make sure a dentry wasn't dropped while we didn't have dcache_lock */ 179 /* make sure a dentry wasn't dropped while we didn't have dcache_lock */
190 if ((ceph_inode(dir)->i_ceph_flags & CEPH_I_COMPLETE)) 180 if (!ceph_i_test(dir, CEPH_I_COMPLETE)) {
191 goto more; 181 dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);
192 dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); 182 err = -EAGAIN;
193 err = -EAGAIN; 183 goto out;
184 }
185
186 spin_lock(&dcache_lock);
187 p = p->prev; /* advance to next dentry */
188 goto more;
194 189
195out_unlock: 190out_unlock:
196 spin_unlock(&dcache_lock); 191 spin_unlock(&dcache_lock);
197 192out:
198 if (last) { 193 if (last)
199 spin_unlock(&inode->i_lock);
200 dput(last); 194 dput(last);
201 spin_lock(&inode->i_lock);
202 }
203
204 return err; 195 return err;
205} 196}
206 197
@@ -272,13 +263,13 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
272 ceph_snap(inode) != CEPH_SNAPDIR && 263 ceph_snap(inode) != CEPH_SNAPDIR &&
273 (ci->i_ceph_flags & CEPH_I_COMPLETE) && 264 (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
274 __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) { 265 __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
266 spin_unlock(&inode->i_lock);
275 err = __dcache_readdir(filp, dirent, filldir); 267 err = __dcache_readdir(filp, dirent, filldir);
276 if (err != -EAGAIN) { 268 if (err != -EAGAIN)
277 spin_unlock(&inode->i_lock);
278 return err; 269 return err;
279 } 270 } else {
271 spin_unlock(&inode->i_lock);
280 } 272 }
281 spin_unlock(&inode->i_lock);
282 if (fi->dentry) { 273 if (fi->dentry) {
283 err = note_last_dentry(fi, fi->dentry->d_name.name, 274 err = note_last_dentry(fi, fi->dentry->d_name.name,
284 fi->dentry->d_name.len); 275 fi->dentry->d_name.len);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index e2e904442ce2..1886294e12f7 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -400,8 +400,9 @@ static inline bool ceph_i_test(struct inode *inode, unsigned mask)
400 struct ceph_inode_info *ci = ceph_inode(inode); 400 struct ceph_inode_info *ci = ceph_inode(inode);
401 bool r; 401 bool r;
402 402
403 smp_mb(); 403 spin_lock(&inode->i_lock);
404 r = (ci->i_ceph_flags & mask) == mask; 404 r = (ci->i_ceph_flags & mask) == mask;
405 spin_unlock(&inode->i_lock);
405 return r; 406 return r;
406} 407}
407 408