diff options
author | Greg Farnum <gregf@hq.newdream.net> | 2010-09-17 13:24:02 -0400 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2010-10-20 18:38:17 -0400 |
commit | fca4451acfdcf894154e4809529ca28a09db88ff (patch) | |
tree | 446381c8e8c7b592b47c2e50c32b1e40817fcfe1 | |
parent | ac0b74d8a1ced8ea86147467daf06b15b130dd94 (diff) |
ceph: preallocate flock state without locks held
When the lock_kernel() turns into lock_flocks() and a spinlock, we won't
be able to do allocations with the lock held. Preallocate space without
the lock, and retry if the lock state changes out from underneath us.
Signed-off-by: Greg Farnum <gregf@hq.newdream.net>
Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r-- | fs/ceph/locks.c | 17 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 42 |
2 files changed, 44 insertions, 15 deletions
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 087afe9ca367..40abde93c345 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c | |||
@@ -181,8 +181,9 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) | |||
181 | * Encode the flock and fcntl locks for the given inode into the pagelist. | 181 | * Encode the flock and fcntl locks for the given inode into the pagelist. |
182 | * Format is: #fcntl locks, sequential fcntl locks, #flock locks, | 182 | * Format is: #fcntl locks, sequential fcntl locks, #flock locks, |
183 | * sequential flock locks. | 183 | * sequential flock locks. |
184 | * Must be called with BLK already held, and the lock numbers should have | 184 | * Must be called with lock_flocks() already held. |
185 | * been gathered under the same lock holding window. | 185 | * If we encounter more of a specific lock type than expected, |
186 | * we return the value 1. | ||
186 | */ | 187 | */ |
187 | int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist, | 188 | int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist, |
188 | int num_fcntl_locks, int num_flock_locks) | 189 | int num_fcntl_locks, int num_flock_locks) |
@@ -190,6 +191,8 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist, | |||
190 | struct file_lock *lock; | 191 | struct file_lock *lock; |
191 | struct ceph_filelock cephlock; | 192 | struct ceph_filelock cephlock; |
192 | int err = 0; | 193 | int err = 0; |
194 | int seen_fcntl = 0; | ||
195 | int seen_flock = 0; | ||
193 | 196 | ||
194 | dout("encoding %d flock and %d fcntl locks", num_flock_locks, | 197 | dout("encoding %d flock and %d fcntl locks", num_flock_locks, |
195 | num_fcntl_locks); | 198 | num_fcntl_locks); |
@@ -198,6 +201,11 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist, | |||
198 | goto fail; | 201 | goto fail; |
199 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | 202 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { |
200 | if (lock->fl_flags & FL_POSIX) { | 203 | if (lock->fl_flags & FL_POSIX) { |
204 | ++seen_fcntl; | ||
205 | if (seen_fcntl > num_fcntl_locks) { | ||
206 | err = -ENOSPC; | ||
207 | goto fail; | ||
208 | } | ||
201 | err = lock_to_ceph_filelock(lock, &cephlock); | 209 | err = lock_to_ceph_filelock(lock, &cephlock); |
202 | if (err) | 210 | if (err) |
203 | goto fail; | 211 | goto fail; |
@@ -213,6 +221,11 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist, | |||
213 | goto fail; | 221 | goto fail; |
214 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | 222 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { |
215 | if (lock->fl_flags & FL_FLOCK) { | 223 | if (lock->fl_flags & FL_FLOCK) { |
224 | ++seen_flock; | ||
225 | if (seen_flock > num_flock_locks) { | ||
226 | err = -ENOSPC; | ||
227 | goto fail; | ||
228 | } | ||
216 | err = lock_to_ceph_filelock(lock, &cephlock); | 229 | err = lock_to_ceph_filelock(lock, &cephlock); |
217 | if (err) | 230 | if (err) |
218 | goto fail; | 231 | goto fail; |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 33568239a08e..fbfc298ac55b 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -2365,19 +2365,35 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
2365 | 2365 | ||
2366 | if (recon_state->flock) { | 2366 | if (recon_state->flock) { |
2367 | int num_fcntl_locks, num_flock_locks; | 2367 | int num_fcntl_locks, num_flock_locks; |
2368 | 2368 | struct ceph_pagelist_cursor trunc_point; | |
2369 | lock_kernel(); | 2369 | |
2370 | ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks); | 2370 | ceph_pagelist_set_cursor(pagelist, &trunc_point); |
2371 | rec.v2.flock_len = (2*sizeof(u32) + | 2371 | do { |
2372 | (num_fcntl_locks+num_flock_locks) * | 2372 | lock_kernel(); |
2373 | sizeof(struct ceph_filelock)); | 2373 | ceph_count_locks(inode, &num_fcntl_locks, |
2374 | 2374 | &num_flock_locks); | |
2375 | err = ceph_pagelist_append(pagelist, &rec, reclen); | 2375 | rec.v2.flock_len = (2*sizeof(u32) + |
2376 | if (!err) | 2376 | (num_fcntl_locks+num_flock_locks) * |
2377 | err = ceph_encode_locks(inode, pagelist, | 2377 | sizeof(struct ceph_filelock)); |
2378 | num_fcntl_locks, | 2378 | unlock_kernel(); |
2379 | num_flock_locks); | 2379 | |
2380 | unlock_kernel(); | 2380 | /* pre-alloc pagelist */ |
2381 | ceph_pagelist_truncate(pagelist, &trunc_point); | ||
2382 | err = ceph_pagelist_append(pagelist, &rec, reclen); | ||
2383 | if (!err) | ||
2384 | err = ceph_pagelist_reserve(pagelist, | ||
2385 | rec.v2.flock_len); | ||
2386 | |||
2387 | /* encode locks */ | ||
2388 | if (!err) { | ||
2389 | lock_kernel(); | ||
2390 | err = ceph_encode_locks(inode, | ||
2391 | pagelist, | ||
2392 | num_fcntl_locks, | ||
2393 | num_flock_locks); | ||
2394 | unlock_kernel(); | ||
2395 | } | ||
2396 | } while (err == -ENOSPC); | ||
2381 | } else { | 2397 | } else { |
2382 | err = ceph_pagelist_append(pagelist, &rec, reclen); | 2398 | err = ceph_pagelist_append(pagelist, &rec, reclen); |
2383 | } | 2399 | } |