diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:39 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:39 -0500 |
| commit | 6849c0cab69f5d1a0fc7b05fa5bfb3dec53f86df (patch) | |
| tree | 8bf595be663cc641b000846737c3ba1b6419eb6a | |
| parent | 09c7938c5640a6f22bef074ca6b803dccfdb93e3 (diff) | |
lockd: Add refcounting to struct nlm_block
Otherwise, the block may disappear from underneath us when in
nlmsvc_retry_blocked.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | fs/lockd/svclock.c | 94 | ||||
| -rw-r--r-- | include/linux/lockd/lockd.h | 3 |
2 files changed, 47 insertions, 50 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 1d3a74df93f3..20caeceffb14 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #define nlm_deadlock nlm_lck_denied | 39 | #define nlm_deadlock nlm_lck_denied |
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | static void nlmsvc_release_block(struct nlm_block *block); | ||
| 42 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); | 43 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); |
| 43 | static int nlmsvc_remove_block(struct nlm_block *block); | 44 | static int nlmsvc_remove_block(struct nlm_block *block); |
| 44 | 45 | ||
| @@ -58,6 +59,7 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when) | |||
| 58 | struct nlm_block **bp, *b; | 59 | struct nlm_block **bp, *b; |
| 59 | 60 | ||
| 60 | dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); | 61 | dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); |
| 62 | kref_get(&block->b_count); | ||
| 61 | if (block->b_queued) | 63 | if (block->b_queued) |
| 62 | nlmsvc_remove_block(block); | 64 | nlmsvc_remove_block(block); |
| 63 | bp = &nlm_blocked; | 65 | bp = &nlm_blocked; |
| @@ -90,6 +92,7 @@ nlmsvc_remove_block(struct nlm_block *block) | |||
| 90 | if (b == block) { | 92 | if (b == block) { |
| 91 | *bp = block->b_next; | 93 | *bp = block->b_next; |
| 92 | block->b_queued = 0; | 94 | block->b_queued = 0; |
| 95 | nlmsvc_release_block(block); | ||
| 93 | return 1; | 96 | return 1; |
| 94 | } | 97 | } |
| 95 | } | 98 | } |
| @@ -123,6 +126,7 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove) | |||
| 123 | *head = block->b_next; | 126 | *head = block->b_next; |
| 124 | block->b_queued = 0; | 127 | block->b_queued = 0; |
| 125 | } | 128 | } |
| 129 | kref_get(&block->b_count); | ||
| 126 | return block; | 130 | return block; |
| 127 | } | 131 | } |
| 128 | } | 132 | } |
| @@ -155,6 +159,8 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) | |||
| 155 | break; | 159 | break; |
| 156 | } | 160 | } |
| 157 | 161 | ||
| 162 | if (block != NULL) | ||
| 163 | kref_get(&block->b_count); | ||
| 158 | return block; | 164 | return block; |
| 159 | } | 165 | } |
| 160 | 166 | ||
| @@ -188,6 +194,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | |||
| 188 | memset(block, 0, sizeof(*block)); | 194 | memset(block, 0, sizeof(*block)); |
| 189 | locks_init_lock(&block->b_call.a_args.lock.fl); | 195 | locks_init_lock(&block->b_call.a_args.lock.fl); |
| 190 | locks_init_lock(&block->b_call.a_res.lock.fl); | 196 | locks_init_lock(&block->b_call.a_res.lock.fl); |
| 197 | kref_init(&block->b_count); | ||
| 191 | 198 | ||
| 192 | if (!nlmclnt_setgrantargs(&block->b_call, lock)) | 199 | if (!nlmclnt_setgrantargs(&block->b_call, lock)) |
| 193 | goto failed_free; | 200 | goto failed_free; |
| @@ -228,27 +235,24 @@ failed: | |||
| 228 | * It is the caller's responsibility to check whether the file | 235 | * It is the caller's responsibility to check whether the file |
| 229 | * can be closed hereafter. | 236 | * can be closed hereafter. |
| 230 | */ | 237 | */ |
| 231 | static int | 238 | static int nlmsvc_unlink_block(struct nlm_block *block) |
| 232 | nlmsvc_delete_block(struct nlm_block *block) | ||
| 233 | { | 239 | { |
| 234 | struct file_lock *fl = &block->b_call.a_args.lock.fl; | ||
| 235 | struct nlm_file *file = block->b_file; | ||
| 236 | struct nlm_block **bp; | ||
| 237 | int status; | 240 | int status; |
| 238 | 241 | dprintk("lockd: unlinking block %p...\n", block); | |
| 239 | dprintk("lockd: deleting block %p...\n", block); | ||
| 240 | 242 | ||
| 241 | /* Remove block from list */ | 243 | /* Remove block from list */ |
| 244 | status = posix_unblock_lock(block->b_file->f_file, &block->b_call.a_args.lock.fl); | ||
| 242 | nlmsvc_remove_block(block); | 245 | nlmsvc_remove_block(block); |
| 243 | status = posix_unblock_lock(file->f_file, fl); | 246 | return status; |
| 247 | } | ||
| 244 | 248 | ||
| 245 | /* If the block is in the middle of a GRANT callback, | 249 | static void nlmsvc_free_block(struct kref *kref) |
| 246 | * don't kill it yet. */ | 250 | { |
| 247 | if (block->b_incall) { | 251 | struct nlm_block *block = container_of(kref, struct nlm_block, b_count); |
| 248 | nlmsvc_insert_block(block, NLM_NEVER); | 252 | struct nlm_file *file = block->b_file; |
| 249 | block->b_done = 1; | 253 | struct nlm_block **bp; |
| 250 | return status; | 254 | |
| 251 | } | 255 | dprintk("lockd: freeing block %p...\n", block); |
| 252 | 256 | ||
| 253 | /* Remove block from file's list of blocks */ | 257 | /* Remove block from file's list of blocks */ |
| 254 | for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { | 258 | for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { |
| @@ -262,7 +266,12 @@ nlmsvc_delete_block(struct nlm_block *block) | |||
| 262 | nlm_release_host(block->b_host); | 266 | nlm_release_host(block->b_host); |
| 263 | nlmclnt_freegrantargs(&block->b_call); | 267 | nlmclnt_freegrantargs(&block->b_call); |
| 264 | kfree(block); | 268 | kfree(block); |
| 265 | return status; | 269 | } |
| 270 | |||
| 271 | static void nlmsvc_release_block(struct nlm_block *block) | ||
| 272 | { | ||
| 273 | if (block != NULL) | ||
| 274 | kref_put(&block->b_count, nlmsvc_free_block); | ||
| 266 | } | 275 | } |
| 267 | 276 | ||
| 268 | /* | 277 | /* |
| @@ -282,7 +291,7 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) | |||
| 282 | block->b_host->h_inuse = 1; | 291 | block->b_host->h_inuse = 1; |
| 283 | else if (action == NLM_ACT_UNLOCK) { | 292 | else if (action == NLM_ACT_UNLOCK) { |
| 284 | if (host == NULL || host == block->b_host) | 293 | if (host == NULL || host == block->b_host) |
| 285 | nlmsvc_delete_block(block); | 294 | nlmsvc_unlink_block(block); |
| 286 | } | 295 | } |
| 287 | } | 296 | } |
| 288 | up(&file->f_sema); | 297 | up(&file->f_sema); |
| @@ -318,9 +327,9 @@ again: | |||
| 318 | block = nlmsvc_lookup_block(file, lock, 0); | 327 | block = nlmsvc_lookup_block(file, lock, 0); |
| 319 | if (block == NULL) { | 328 | if (block == NULL) { |
| 320 | if (newblock != NULL) | 329 | if (newblock != NULL) |
| 321 | lock = &newblock->b_call.a_args.lock.fl; | 330 | lock = &newblock->b_call.a_args.lock; |
| 322 | } else | 331 | } else |
| 323 | lock = &block->b_call.a_args.lock.fl; | 332 | lock = &block->b_call.a_args.lock; |
| 324 | 333 | ||
| 325 | error = posix_lock_file(file->f_file, &lock->fl); | 334 | error = posix_lock_file(file->f_file, &lock->fl); |
| 326 | lock->fl.fl_flags &= ~FL_SLEEP; | 335 | lock->fl.fl_flags &= ~FL_SLEEP; |
| @@ -363,12 +372,10 @@ again: | |||
| 363 | 372 | ||
| 364 | /* Append to list of blocked */ | 373 | /* Append to list of blocked */ |
| 365 | nlmsvc_insert_block(newblock, NLM_NEVER); | 374 | nlmsvc_insert_block(newblock, NLM_NEVER); |
| 366 | newblock = NULL; | ||
| 367 | |||
| 368 | out: | 375 | out: |
| 369 | up(&file->f_sema); | 376 | up(&file->f_sema); |
| 370 | if (newblock != NULL) | 377 | nlmsvc_release_block(newblock); |
| 371 | nlmsvc_delete_block(newblock); | 378 | nlmsvc_release_block(block); |
| 372 | dprintk("lockd: nlmsvc_lock returned %u\n", ret); | 379 | dprintk("lockd: nlmsvc_lock returned %u\n", ret); |
| 373 | return ret; | 380 | return ret; |
| 374 | } | 381 | } |
| @@ -450,8 +457,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
| 450 | (long long)lock->fl.fl_end); | 457 | (long long)lock->fl.fl_end); |
| 451 | 458 | ||
| 452 | down(&file->f_sema); | 459 | down(&file->f_sema); |
| 453 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) | 460 | if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) { |
| 454 | status = nlmsvc_delete_block(block); | 461 | status = nlmsvc_unlink_block(block); |
| 462 | nlmsvc_release_block(block); | ||
| 463 | } | ||
| 455 | up(&file->f_sema); | 464 | up(&file->f_sema); |
| 456 | return status ? nlm_lck_denied : nlm_granted; | 465 | return status ? nlm_lck_denied : nlm_granted; |
| 457 | } | 466 | } |
| @@ -514,7 +523,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
| 514 | down(&file->f_sema); | 523 | down(&file->f_sema); |
| 515 | 524 | ||
| 516 | /* Unlink block request from list */ | 525 | /* Unlink block request from list */ |
| 517 | nlmsvc_remove_block(block); | 526 | nlmsvc_unlink_block(block); |
| 518 | 527 | ||
| 519 | /* If b_granted is true this means we've been here before. | 528 | /* If b_granted is true this means we've been here before. |
| 520 | * Just retry the grant callback, possibly refreshing the RPC | 529 | * Just retry the grant callback, possibly refreshing the RPC |
| @@ -525,7 +534,6 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
| 525 | } | 534 | } |
| 526 | 535 | ||
| 527 | /* Try the lock operation again */ | 536 | /* Try the lock operation again */ |
| 528 | posix_unblock_lock(file->f_file, &lock->fl); | ||
| 529 | lock->fl.fl_flags |= FL_SLEEP; | 537 | lock->fl.fl_flags |= FL_SLEEP; |
| 530 | error = posix_lock_file(file->f_file, &lock->fl); | 538 | error = posix_lock_file(file->f_file, &lock->fl); |
| 531 | lock->fl.fl_flags &= ~FL_SLEEP; | 539 | lock->fl.fl_flags &= ~FL_SLEEP; |
| @@ -548,16 +556,15 @@ callback: | |||
| 548 | /* Lock was granted by VFS. */ | 556 | /* Lock was granted by VFS. */ |
