diff options
author | Sage Weil <sage@newdream.net> | 2010-10-18 17:04:31 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-10-20 18:38:27 -0400 |
commit | efa4c1206eaff047c474af2136748a58eb8cc33b (patch) | |
tree | 61f8957ed7735c01a6d6900a3c4c2c45d084c3a7 | |
parent | 61413c2f594e6b63db2b14c70c2e7d8cf02f9c00 (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.c | 41 | ||||
-rw-r--r-- | fs/ceph/super.h | 3 |
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 | */ |
96 | static int __dcache_readdir(struct file *filp, | 96 | static 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 | ||
195 | out_unlock: | 190 | out_unlock: |
196 | spin_unlock(&dcache_lock); | 191 | spin_unlock(&dcache_lock); |
197 | 192 | out: | |
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 | ||