/* * This is the generic lockd callback for async RPC calls */ static u32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) { struct nlm_host *host; struct nlm_rqst *call; if (!(call = nlmclnt_alloc_call())) return rpc_system_err; host = nlmclnt_lookup_host(&rqstp->rq_addr, rqstp->rq_prot, rqstp->rq_vers); if (!host) { kfree(call); return rpc_system_err; } call->a_flags = RPC_TASK_ASYNC; call->a_host = host; memcpy(&call->a_args, resp, sizeof(*resp)); if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0) goto error; return rpc_success; error: kfree(call); nlm_release_host(host); return rpc_system_err; }
/* * Try to claim a lock that was previously blocked. * * Note that we use both the RPC_GRANTED_MSG call _and_ an async * RPC thread when notifying the client. This seems like overkill... * Here's why: * - we don't want to use a synchronous RPC thread, otherwise * we might find ourselves hanging on a dead portmapper. * - Some lockd implementations (e.g. HP) don't react to * RPC_GRANTED calls; they seem to insist on RPC_GRANTED_MSG calls. */ static void nlmsvc_grant_blocked(struct nlm_block *block) { struct nlm_file *file = block->b_file; struct nlm_lock *lock = &block->b_call.a_args.lock; struct file_lock *conflock; int error; dprintk("lockd: grant blocked lock %p\n", block); /* First thing is lock the file */ down(&file->f_sema); /* Unlink block request from list */ nlmsvc_remove_block(block); /* If b_granted is true this means we've been here before. * Just retry the grant callback, possibly refreshing the RPC * binding */ if (block->b_granted) { nlm_rebind_host(block->b_call.a_host); goto callback; } /* Try the lock operation again */ if ((conflock = posix_test_lock(&file->f_file, &lock->fl)) != NULL) { /* Bummer, we blocked again */ dprintk("lockd: lock still blocked\n"); nlmsvc_insert_block(block, NLM_NEVER); posix_block_lock(conflock, &lock->fl); up(&file->f_sema); return; } /* Alright, no conflicting lock. Now lock it for real. If the * following yields an error, this is most probably due to low * memory. Retry the lock in a few seconds. */ if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) { printk(KERN_WARNING "lockd: unexpected error %d in %s!\n", -error, __FUNCTION__); nlmsvc_insert_block(block, 10 * HZ); up(&file->f_sema); return; } callback: /* Lock was granted by VFS. */ dprintk("lockd: GRANTing blocked lock.\n"); block->b_granted = 1; block->b_incall = 1; /* Schedule next grant callback in 30 seconds */ nlmsvc_insert_block(block, 30 * HZ); /* Call the client */ nlm_get_host(block->b_call.a_host); if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, nlmsvc_grant_callback) < 0) nlm_release_host(block->b_call.a_host); up(&file->f_sema); }