/* * We received a GRANT_RES callback. Try to find the corresponding * block. */ void nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status) { struct nlm_block *block; struct nlm_file *file; dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n", *(unsigned int *)(cookie->data), ntohl(rqstp->rq_addr.sin_addr.s_addr), status); if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr))) return; file = block->b_file; file->f_count++; down(&file->f_sema); if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, 10 * HZ); block = NULL; } else { /* Lock is now held by client, or has been rejected. * In both cases, the block should be removed. */ file->f_count++; up(&file->f_sema); if (status == NLM_LCK_GRANTED) nlmsvc_delete_block(block, 0); else nlmsvc_delete_block(block, 1); } } if (!block) up(&file->f_sema); nlm_release_file(file); }
/* * We received a GRANT_RES callback. Try to find the corresponding * block. */ void nlmsvc_grant_reply(u32 cookie, u32 status) { struct nlm_block *block; struct nlm_file *file; if (!(block = nlmsvc_find_block(cookie))) return; file = block->b_file; file->f_count++; down(&file->f_sema); if ((block = nlmsvc_find_block(cookie)) != NULL) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, jiffies + 10 * HZ); block = NULL; } else { /* Lock is now held by client, or has been rejected. * In both cases, the block should be removed. */ file->f_count++; up(&file->f_sema); if (status == NLM_LCK_GRANTED) nlmsvc_delete_block(block, 0); else nlmsvc_delete_block(block, 1); } } if (!block) up(&file->f_sema); nlm_release_file(file); }
/* * Retry all blocked locks that have been notified. This is where lockd * picks up locks that can be granted, or grant notifications that must * be retransmitted. */ unsigned long nlmsvc_retry_blocked(void) { struct nlm_block *block; dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", nlm_blocked, nlm_blocked? nlm_blocked->b_when : 0); while ((block = nlm_blocked)) { if (block->b_when == NLM_NEVER) break; if (time_after(block->b_when,jiffies)) break; dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", block, block->b_when, block->b_done); if (block->b_done) nlmsvc_delete_block(block, 0); else nlmsvc_grant_blocked(block); } if ((block = nlm_blocked) && block->b_when != NLM_NEVER) return (block->b_when - jiffies); return MAX_SCHEDULE_TIMEOUT; }
/* * Cancel a previously blocked request. * * A cancel request always overrides any grant that may currently * be in progress. * The calling procedure must check whether the file can be closed. */ u32 nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) { struct nlm_block *block; dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n", file->f_file.f_dentry->d_inode->i_dev, file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_pid, lock->fl.fl_start, lock->fl.fl_end); down(&file->f_sema); if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL) nlmsvc_delete_block(block, 1); up(&file->f_sema); return nlm_granted; }
/* * Loop over all blocks and perform the action specified. * (NLM_ACT_CHECK handled by nlmsvc_inspect_file). */ int nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action) { struct nlm_block *block, *next; down(&file->f_sema); for (block = file->f_blocks; block; block = next) { next = block->b_fnext; if (action == NLM_ACT_MARK) block->b_host->h_inuse = 1; else if (action == NLM_ACT_UNLOCK) { if (host == NULL || host == block->b_host) nlmsvc_delete_block(block, 1); } } up(&file->f_sema); return 0; }
/* * Attempt to establish a lock, and if it can't be granted, block it * if required. */ u32 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_lock *lock, int wait, u32 cookie) { struct file_lock *conflock; struct nlm_block *block; int error; dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n", file->f_file.f_dentry->d_inode->i_dev, file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_type, lock->fl.fl_pid, lock->fl.fl_start, lock->fl.fl_end, wait); /* Lock file against concurrent access */ down(&file->f_sema); /* Get existing block (in case client is busy-waiting) */ block = nlmsvc_lookup_block(file, lock, 0); lock->fl.fl_flags |= FL_LOCKD; again: if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) { error = posix_lock_file(&file->f_file, &lock->fl, 0); if (block) nlmsvc_delete_block(block, 0); up(&file->f_sema); dprintk("lockd: posix_lock_file returned %d\n", -error); switch(-error) { case 0: return nlm_granted; case EDEADLK: /* no applicable NLM status */ case EAGAIN: return nlm_lck_denied; default: /* includes ENOLCK */ return nlm_lck_denied_nolocks; } } if (!wait) { up(&file->f_sema); return nlm_lck_denied; } /* If we don't have a block, create and initialize it. Then * retry because we may have slept in kmalloc. */ if (block == NULL) { dprintk("lockd: blocking on this lock (allocating).\n"); if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie))) return nlm_lck_denied_nolocks; goto again; } /* Append to list of blocked */ nlmsvc_insert_block(block, NLM_NEVER); /* Now add block to block list of the conflicting lock */ dprintk("lockd: blocking on this lock.\n"); posix_block_lock(conflock, &block->b_call.a_args.lock.fl); up(&file->f_sema); return nlm_lck_blocked; }
/* * Attempt to establish a lock, and if it can't be granted, block it * if required. */ u32 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie) { struct file_lock *conflock; struct nlm_block *block, *nblock = NULL; int error; dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", file->f_file.f_dentry->d_inode->i_dev, file->f_file.f_dentry->d_inode->i_ino, lock->fl.fl_type, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end, wait); /* Get existing block (in case client is busy-waiting) */ block = nlmsvc_lookup_block(file, lock, 0); lock->fl.fl_flags |= FL_LOCKD; again: /* Lock file against concurrent access */ down(&file->f_sema); if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) { error = posix_lock_file(&file->f_file, &lock->fl, 0); if (block) nlmsvc_delete_block(block, 0); up(&file->f_sema); dprintk("lockd: posix_lock_file returned %d\n", -error); switch(-error) { case 0: return nlm_granted; case EDEADLK: return nlm_deadlock; case EAGAIN: return nlm_lck_denied; default: /* includes ENOLCK */ return nlm_lck_denied_nolocks; } } if (!wait) { up(&file->f_sema); return nlm_lck_denied; } if (posix_locks_deadlock(&lock->fl, conflock)) { if (nblock) nlmsvc_delete_block(nblock, 0); up(&file->f_sema); return nlm_deadlock; } /* If we don't have a block, create and initialize it. Then * retry because we may have slept in kmalloc. */ /* We have to release f_sema as nlmsvc_create_block may try to * to claim it while doing host garbage collection */ if (block == NULL) { up(&file->f_sema); dprintk("lockd: blocking on this lock (allocating).\n"); if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie))) return nlm_lck_denied_nolocks; nblock = block; goto again; } /* Append to list of blocked */ nlmsvc_insert_block(block, NLM_NEVER); if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) { /* Now add block to block list of the conflicting lock if we haven't done so. */ dprintk("lockd: blocking on this lock.\n"); posix_block_lock(conflock, &block->b_call.a_args.lock.fl); } up(&file->f_sema); return nlm_lck_blocked; }