Lines Matching +full:default +full:- +full:blocked

1 // SPDX-License-Identifier: GPL-2.0
5 * Handling of server-side locks, mostly of the blocked variety.
7 * GRANT and CANCEL calls may get stuck, meet in mid-flight, etc.
13 * to a file's list of blocked locks through a semaphore. The global
14 * list of blocked locks is not protected in this fashion however.
16 * call) move blocked locks towards the head of the list *while some other
51 * The list of blocked locks to retry
61 * from lockd, which is single-threaded. in nlmdbg_cookie2a()
67 len--; /* allow for trailing \0 */ in nlmdbg_cookie2a()
70 for (i = 0 ; i < cookie->len ; i++) { in nlmdbg_cookie2a()
72 strcpy(p-3, "..."); in nlmdbg_cookie2a()
75 sprintf(p, "%02x", cookie->data[i]); in nlmdbg_cookie2a()
77 len -= 2; in nlmdbg_cookie2a()
86 * Insert a blocked lock into the global list
95 if (list_empty(&block->b_list)) { in nlmsvc_insert_block_locked()
96 kref_get(&block->b_count); in nlmsvc_insert_block_locked()
98 list_del_init(&block->b_list); in nlmsvc_insert_block_locked()
107 if (time_after(b->b_when,when) || b->b_when == NLM_NEVER) in nlmsvc_insert_block_locked()
111 * so we will be adding to the end of the list - good in nlmsvc_insert_block_locked()
115 list_add_tail(&block->b_list, pos); in nlmsvc_insert_block_locked()
116 block->b_when = when; in nlmsvc_insert_block_locked()
133 if (!list_empty(&block->b_list)) { in nlmsvc_remove_block()
134 list_del_init(&block->b_list); in nlmsvc_remove_block()
151 dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n", in nlmsvc_lookup_block()
152 file, lock->fl.c.flc_pid, in nlmsvc_lookup_block()
153 (long long)lock->fl.fl_start, in nlmsvc_lookup_block()
154 (long long)lock->fl.fl_end, in nlmsvc_lookup_block()
155 lock->fl.c.flc_type); in nlmsvc_lookup_block()
158 fl = &block->b_call->a_args.lock.fl; in nlmsvc_lookup_block()
159 dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", in nlmsvc_lookup_block()
160 block->b_file, fl->c.flc_pid, in nlmsvc_lookup_block()
161 (long long)fl->fl_start, in nlmsvc_lookup_block()
162 (long long)fl->fl_end, fl->c.flc_type, in nlmsvc_lookup_block()
163 nlmdbg_cookie2a(&block->b_call->a_args.cookie)); in nlmsvc_lookup_block()
164 if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) { in nlmsvc_lookup_block()
165 kref_get(&block->b_count); in nlmsvc_lookup_block()
177 if (a->len != b->len) in nlm_cookie_match()
179 if (memcmp(a->data, b->data, a->len)) in nlm_cookie_match()
194 if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)) in nlmsvc_find_block()
203 kref_get(&block->b_count); in nlmsvc_find_block()
212 * the blocked lock request. The spec explicitly mentions that the client
221 * address. --okir
239 kref_init(&block->b_count); in nlmsvc_create_block()
240 INIT_LIST_HEAD(&block->b_list); in nlmsvc_create_block()
241 INIT_LIST_HEAD(&block->b_flist); in nlmsvc_create_block()
247 call->a_args.lock.fl.c.flc_flags |= FL_SLEEP; in nlmsvc_create_block()
248 call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations; in nlmsvc_create_block()
249 nlmclnt_next_cookie(&call->a_args.cookie); in nlmsvc_create_block()
254 block->b_daemon = rqstp->rq_server; in nlmsvc_create_block()
255 block->b_host = host; in nlmsvc_create_block()
256 block->b_file = file; in nlmsvc_create_block()
257 file->f_count++; in nlmsvc_create_block()
260 list_add(&block->b_flist, &file->f_blocks); in nlmsvc_create_block()
263 block->b_call = call; in nlmsvc_create_block()
264 call->a_flags = RPC_TASK_ASYNC; in nlmsvc_create_block()
265 call->a_block = block; in nlmsvc_create_block()
287 status = locks_delete_block(&block->b_call->a_args.lock.fl); in nlmsvc_unlink_block()
295 struct nlm_file *file = block->b_file; in nlmsvc_free_block()
300 list_del_init(&block->b_flist); in nlmsvc_free_block()
301 mutex_unlock(&file->f_mutex); in nlmsvc_free_block()
303 nlmsvc_freegrantargs(block->b_call); in nlmsvc_free_block()
304 nlmsvc_release_call(block->b_call); in nlmsvc_free_block()
305 nlm_release_file(block->b_file); in nlmsvc_free_block()
312 kref_put_mutex(&block->b_count, nlmsvc_free_block, &block->b_file->f_mutex); in nlmsvc_release_block()
326 mutex_lock(&file->f_mutex); in nlmsvc_traverse_blocks()
328 list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) { in nlmsvc_traverse_blocks()
329 if (!match(block->b_host, host)) in nlmsvc_traverse_blocks()
332 * the global retry list - why? */ in nlmsvc_traverse_blocks()
333 if (list_empty(&block->b_list)) in nlmsvc_traverse_blocks()
335 kref_get(&block->b_count); in nlmsvc_traverse_blocks()
337 mutex_unlock(&file->f_mutex); in nlmsvc_traverse_blocks()
343 mutex_unlock(&file->f_mutex); in nlmsvc_traverse_blocks()
349 refcount_inc(&lockowner->count); in nlmsvc_get_lockowner()
355 if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock)) in nlmsvc_put_lockowner()
357 list_del(&lockowner->list); in nlmsvc_put_lockowner()
358 spin_unlock(&lockowner->host->h_lock); in nlmsvc_put_lockowner()
359 nlmsvc_release_host(lockowner->host); in nlmsvc_put_lockowner()
366 list_for_each_entry(lockowner, &host->h_lockowners, list) { in __nlmsvc_find_lockowner()
367 if (lockowner->pid != pid) in __nlmsvc_find_lockowner()
378 spin_lock(&host->h_lock); in nlmsvc_find_lockowner()
382 spin_unlock(&host->h_lock); in nlmsvc_find_lockowner()
384 spin_lock(&host->h_lock); in nlmsvc_find_lockowner()
389 refcount_set(&new->count, 1); in nlmsvc_find_lockowner()
390 new->pid = pid; in nlmsvc_find_lockowner()
391 new->host = nlm_get_host(host); in nlmsvc_find_lockowner()
392 list_add(&new->list, &host->h_lockowners); in nlmsvc_find_lockowner()
397 spin_unlock(&host->h_lock); in nlmsvc_find_lockowner()
405 if (lock->fl.c.flc_owner) in nlmsvc_release_lockowner()
406 nlmsvc_put_lockowner(lock->fl.c.flc_owner); in nlmsvc_release_lockowner()
412 fl->c.flc_owner = nlmsvc_find_lockowner(host, pid); in nlmsvc_locks_init_private()
421 locks_copy_lock(&call->a_args.lock.fl, &lock->fl); in nlmsvc_setgrantargs()
422 memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); in nlmsvc_setgrantargs()
423 call->a_args.lock.caller = utsname()->nodename; in nlmsvc_setgrantargs()
424 call->a_args.lock.oh.len = lock->oh.len; in nlmsvc_setgrantargs()
426 /* set default data area */ in nlmsvc_setgrantargs()
427 call->a_args.lock.oh.data = call->a_owner; in nlmsvc_setgrantargs()
428 call->a_args.lock.svid = ((struct nlm_lockowner *) lock->fl.c.flc_owner)->pid; in nlmsvc_setgrantargs()
430 if (lock->oh.len > NLMCLNT_OHSIZE) { in nlmsvc_setgrantargs()
431 void *data = kmalloc(lock->oh.len, GFP_KERNEL); in nlmsvc_setgrantargs()
434 call->a_args.lock.oh.data = (u8 *) data; in nlmsvc_setgrantargs()
437 memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len); in nlmsvc_setgrantargs()
443 if (call->a_args.lock.oh.data != call->a_owner) in nlmsvc_freegrantargs()
444 kfree(call->a_args.lock.oh.data); in nlmsvc_freegrantargs()
446 locks_release_private(&call->a_args.lock.fl); in nlmsvc_freegrantargs()
450 * Deferred lock request handling for non-blocking lock
457 block->b_flags |= B_QUEUED; in nlmsvc_defer_lock_rqst()
461 block->b_cache_req = &rqstp->rq_chandle; in nlmsvc_defer_lock_rqst()
462 if (rqstp->rq_chandle.defer) { in nlmsvc_defer_lock_rqst()
463 block->b_deferred_req = in nlmsvc_defer_lock_rqst()
464 rqstp->rq_chandle.defer(block->b_cache_req); in nlmsvc_defer_lock_rqst()
465 if (block->b_deferred_req != NULL) in nlmsvc_defer_lock_rqst()
469 block, block->b_flags, ntohl(status)); in nlmsvc_defer_lock_rqst()
490 dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", in nlmsvc_lock()
491 inode->i_sb->s_id, inode->i_ino, in nlmsvc_lock()
492 lock->fl.c.flc_type, in nlmsvc_lock()
493 lock->fl.c.flc_pid, in nlmsvc_lock()
494 (long long)lock->fl.fl_start, in nlmsvc_lock()
495 (long long)lock->fl.fl_end, in nlmsvc_lock()
498 if (!locks_can_async_lock(nlmsvc_file_file(file)->f_op)) { in nlmsvc_lock()
504 mutex_lock(&file->f_mutex); in nlmsvc_lock()
505 /* Get existing block (in case client is busy-waiting) in nlmsvc_lock()
514 lock = &block->b_call->a_args.lock; in nlmsvc_lock()
516 lock->fl.c.flc_flags &= ~FL_SLEEP; in nlmsvc_lock()
518 if (block->b_flags & B_QUEUED) { in nlmsvc_lock()
520 block, block->b_flags); in nlmsvc_lock()
521 if (block->b_granted) { in nlmsvc_lock()
526 if (block->b_flags & B_TIMED_OUT) { in nlmsvc_lock()
549 * requests on the underlaying ->lock() implementation but in nlmsvc_lock()
552 if (locks_can_async_lock(nlmsvc_file_file(file)->f_op) && in nlmsvc_lock()
553 !list_empty(&block->b_list)) { in nlmsvc_lock()
559 /* Append to list of blocked */ in nlmsvc_lock()
564 lock->fl.c.flc_flags &= ~FL_SLEEP; in nlmsvc_lock()
565 mode = lock_to_openmode(&lock->fl); in nlmsvc_lock()
566 error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); in nlmsvc_lock()
567 lock->fl.c.flc_flags &= ~FL_SLEEP; in nlmsvc_lock()
575 case -EAGAIN: in nlmsvc_lock()
587 case -EDEADLK: in nlmsvc_lock()
591 default: /* includes ENOLCK */ in nlmsvc_lock()
599 mutex_unlock(&file->f_mutex); in nlmsvc_lock()
617 dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", in nlmsvc_testlock()
618 nlmsvc_file_inode(file)->i_sb->s_id, in nlmsvc_testlock()
619 nlmsvc_file_inode(file)->i_ino, in nlmsvc_testlock()
620 lock->fl.c.flc_type, in nlmsvc_testlock()
621 (long long)lock->fl.fl_start, in nlmsvc_testlock()
622 (long long)lock->fl.fl_end); in nlmsvc_testlock()
629 mode = lock_to_openmode(&lock->fl); in nlmsvc_testlock()
630 error = vfs_test_lock(file->f_file[mode], &lock->fl); in nlmsvc_testlock()
640 if (lock->fl.c.flc_type == F_UNLCK) { in nlmsvc_testlock()
645 dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n", in nlmsvc_testlock()
646 lock->fl.c.flc_type, (long long)lock->fl.fl_start, in nlmsvc_testlock()
647 (long long)lock->fl.fl_end); in nlmsvc_testlock()
648 conflock->caller = "somehost"; /* FIXME */ in nlmsvc_testlock()
649 conflock->len = strlen(conflock->caller); in nlmsvc_testlock()
650 conflock->oh.len = 0; /* don't return OH info */ in nlmsvc_testlock()
651 conflock->svid = lock->fl.c.flc_pid; in nlmsvc_testlock()
652 conflock->fl.c.flc_type = lock->fl.c.flc_type; in nlmsvc_testlock()
653 conflock->fl.fl_start = lock->fl.fl_start; in nlmsvc_testlock()
654 conflock->fl.fl_end = lock->fl.fl_end; in nlmsvc_testlock()
655 locks_release_private(&lock->fl); in nlmsvc_testlock()
674 dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n", in nlmsvc_unlock()
675 nlmsvc_file_inode(file)->i_sb->s_id, in nlmsvc_unlock()
676 nlmsvc_file_inode(file)->i_ino, in nlmsvc_unlock()
677 lock->fl.c.flc_pid, in nlmsvc_unlock()
678 (long long)lock->fl.fl_start, in nlmsvc_unlock()
679 (long long)lock->fl.fl_end); in nlmsvc_unlock()
684 lock->fl.c.flc_type = F_UNLCK; in nlmsvc_unlock()
685 lock->fl.c.flc_file = file->f_file[O_RDONLY]; in nlmsvc_unlock()
686 if (lock->fl.c.flc_file) in nlmsvc_unlock()
687 error = vfs_lock_file(lock->fl.c.flc_file, F_SETLK, in nlmsvc_unlock()
688 &lock->fl, NULL); in nlmsvc_unlock()
689 lock->fl.c.flc_file = file->f_file[O_WRONLY]; in nlmsvc_unlock()
690 if (lock->fl.c.flc_file) in nlmsvc_unlock()
691 error |= vfs_lock_file(lock->fl.c.flc_file, F_SETLK, in nlmsvc_unlock()
692 &lock->fl, NULL); in nlmsvc_unlock()
698 * Cancel a previously blocked request.
711 dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", in nlmsvc_cancel_blocked()
712 nlmsvc_file_inode(file)->i_sb->s_id, in nlmsvc_cancel_blocked()
713 nlmsvc_file_inode(file)->i_ino, in nlmsvc_cancel_blocked()
714 lock->fl.c.flc_pid, in nlmsvc_cancel_blocked()
715 (long long)lock->fl.fl_start, in nlmsvc_cancel_blocked()
716 (long long)lock->fl.fl_end); in nlmsvc_cancel_blocked()
721 mutex_lock(&file->f_mutex); in nlmsvc_cancel_blocked()
723 mutex_unlock(&file->f_mutex); in nlmsvc_cancel_blocked()
725 struct file_lock *fl = &block->b_call->a_args.lock.fl; in nlmsvc_cancel_blocked()
728 vfs_cancel_lock(block->b_file->f_file[mode], fl); in nlmsvc_cancel_blocked()
747 block->b_flags |= B_GOT_CALLBACK; in nlmsvc_update_deferred_block()
749 block->b_granted = 1; in nlmsvc_update_deferred_block()
751 block->b_flags |= B_TIMED_OUT; in nlmsvc_update_deferred_block()
757 int rc = -ENOENT; in nlmsvc_grant_deferred()
761 if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { in nlmsvc_grant_deferred()
763 block, block->b_flags); in nlmsvc_grant_deferred()
764 if (block->b_flags & B_QUEUED) { in nlmsvc_grant_deferred()
765 if (block->b_flags & B_TIMED_OUT) { in nlmsvc_grant_deferred()
766 rc = -ENOLCK; in nlmsvc_grant_deferred()
771 block->b_granted = 1; in nlmsvc_grant_deferred()
774 svc_wake_up(block->b_daemon); in nlmsvc_grant_deferred()
780 if (rc == -ENOENT) in nlmsvc_grant_deferred()
786 * Unblock a blocked lock request. This is a callback invoked from the
787 * VFS layer when a lock on which we blocked is removed.
789 * This function doesn't grant the blocked lock instantly, but rather moves
800 if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { in nlmsvc_notify_blocked()
803 svc_wake_up(block->b_daemon); in nlmsvc_notify_blocked()
829 * Try to claim a lock that was previously blocked.
834 * - we don't want to use a synchronous RPC thread, otherwise
836 * - Some lockd implementations (e.g. HP) don't react to
842 struct nlm_file *file = block->b_file; in nlmsvc_grant_blocked()
843 struct nlm_lock *lock = &block->b_call->a_args.lock; in nlmsvc_grant_blocked()
848 dprintk("lockd: grant blocked lock %p\n", block); in nlmsvc_grant_blocked()
850 kref_get(&block->b_count); in nlmsvc_grant_blocked()
858 if (block->b_granted) { in nlmsvc_grant_blocked()
859 nlm_rebind_host(block->b_host); in nlmsvc_grant_blocked()
867 lock->fl.c.flc_flags |= FL_SLEEP; in nlmsvc_grant_blocked()
868 fl_start = lock->fl.fl_start; in nlmsvc_grant_blocked()
869 fl_end = lock->fl.fl_end; in nlmsvc_grant_blocked()
870 mode = lock_to_openmode(&lock->fl); in nlmsvc_grant_blocked()
871 error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); in nlmsvc_grant_blocked()
872 lock->fl.c.flc_flags &= ~FL_SLEEP; in nlmsvc_grant_blocked()
873 lock->fl.fl_start = fl_start; in nlmsvc_grant_blocked()
874 lock->fl.fl_end = fl_end; in nlmsvc_grant_blocked()
880 dprintk("lockd: lock still blocked error %d\n", error); in nlmsvc_grant_blocked()
884 default: in nlmsvc_grant_blocked()
886 -error, __func__); in nlmsvc_grant_blocked()
894 dprintk("lockd: GRANTing blocked lock.\n"); in nlmsvc_grant_blocked()
895 block->b_granted = 1; in nlmsvc_grant_blocked()
902 /* Call the client -- use a soft RPC task since nlmsvc_retry_blocked in nlmsvc_grant_blocked()
905 error = nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, in nlmsvc_grant_blocked()
917 * better not sleep. Therefore, we put the blocked lock on the nlm_blocked
924 struct nlm_block *block = call->a_block; in nlmsvc_grant_callback()
938 if (list_empty(&block->b_list)) in nlmsvc_grant_callback()
944 if (task->tk_status < 0) { in nlmsvc_grant_callback()
945 /* RPC error: Re-insert for retransmission */ in nlmsvc_grant_callback()
952 svc_wake_up(block->b_daemon); in nlmsvc_grant_callback()
964 nlmsvc_release_block(call->a_block); in nlmsvc_grant_release()
984 *(unsigned int *)(cookie->data), status); in nlmsvc_grant_reply()
996 fl = &block->b_call->a_args.lock.fl; in nlmsvc_grant_reply()
997 fl->c.flc_type = F_UNLCK; in nlmsvc_grant_reply()
998 error = vfs_lock_file(fl->c.flc_file, F_SETLK, fl, NULL); in nlmsvc_grant_reply()
1002 default: in nlmsvc_grant_reply()
1014 * For a non-blocking lock or test lock, revisit the request.
1019 if (!(block->b_flags & B_GOT_CALLBACK)) in retry_deferred_block()
1020 block->b_flags |= B_TIMED_OUT; in retry_deferred_block()
1022 dprintk("revisit block %p flags %d\n", block, block->b_flags); in retry_deferred_block()
1023 if (block->b_deferred_req) { in retry_deferred_block()
1024 block->b_deferred_req->revisit(block->b_deferred_req, 0); in retry_deferred_block()
1025 block->b_deferred_req = NULL; in retry_deferred_block()
1030 * Retry all blocked locks that have been notified. This is where lockd
1044 if (block->b_when == NLM_NEVER) in nlmsvc_retry_blocked()
1046 if (time_after(block->b_when, jiffies)) { in nlmsvc_retry_blocked()
1047 timeout = block->b_when - jiffies; in nlmsvc_retry_blocked()
1053 block, block->b_when); in nlmsvc_retry_blocked()
1054 if (block->b_flags & B_QUEUED) { in nlmsvc_retry_blocked()
1056 block, block->b_granted, block->b_flags); in nlmsvc_retry_blocked()