NLM: Add nlmclnt_release_call
Add a helper function to simplify the freeing of NLM client requests. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
e4cd038a45
commit
92737230dd
|
@ -152,9 +152,8 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
|
||||||
int
|
int
|
||||||
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||||
{
|
{
|
||||||
struct nfs_server *nfssrv = NFS_SERVER(inode);
|
|
||||||
struct nlm_host *host;
|
struct nlm_host *host;
|
||||||
struct nlm_rqst reqst, *call = &reqst;
|
struct nlm_rqst *call;
|
||||||
sigset_t oldset;
|
sigset_t oldset;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int status, proto, vers;
|
int status, proto, vers;
|
||||||
|
@ -168,23 +167,17 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||||
/* Retrieve transport protocol from NFS client */
|
/* Retrieve transport protocol from NFS client */
|
||||||
proto = NFS_CLIENT(inode)->cl_xprt->prot;
|
proto = NFS_CLIENT(inode)->cl_xprt->prot;
|
||||||
|
|
||||||
if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
|
host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers);
|
||||||
|
if (host == NULL)
|
||||||
return -ENOLCK;
|
return -ENOLCK;
|
||||||
|
|
||||||
/* Create RPC client handle if not there, and copy soft
|
call = nlm_alloc_call(host);
|
||||||
* and intr flags from NFS client. */
|
if (call == NULL)
|
||||||
if (host->h_rpcclnt == NULL) {
|
return -ENOMEM;
|
||||||
struct rpc_clnt *clnt;
|
|
||||||
|
|
||||||
/* Bind an rpc client to this host handle (does not
|
nlmclnt_locks_init_private(fl, host);
|
||||||
* perform a portmapper lookup) */
|
/* Set up the argument struct */
|
||||||
if (!(clnt = nlm_bind_host(host))) {
|
nlmclnt_setlockargs(call, fl);
|
||||||
status = -ENOLCK;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
clnt->cl_softrtry = nfssrv->client->cl_softrtry;
|
|
||||||
clnt->cl_intr = nfssrv->client->cl_intr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep the old signal mask */
|
/* Keep the old signal mask */
|
||||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||||
|
@ -197,26 +190,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||||
&& (current->flags & PF_EXITING)) {
|
&& (current->flags & PF_EXITING)) {
|
||||||
sigfillset(¤t->blocked); /* Mask all signals */
|
sigfillset(¤t->blocked); /* Mask all signals */
|
||||||
recalc_sigpending();
|
recalc_sigpending();
|
||||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
|
||||||
|
|
||||||
call = nlmclnt_alloc_call();
|
|
||||||
if (!call) {
|
|
||||||
status = -ENOMEM;
|
|
||||||
goto out_restore;
|
|
||||||
}
|
|
||||||
call->a_flags = RPC_TASK_ASYNC;
|
call->a_flags = RPC_TASK_ASYNC;
|
||||||
} else {
|
|
||||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
|
||||||
memset(call, 0, sizeof(*call));
|
|
||||||
locks_init_lock(&call->a_args.lock.fl);
|
|
||||||
locks_init_lock(&call->a_res.lock.fl);
|
|
||||||
}
|
}
|
||||||
call->a_host = host;
|
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||||
|
|
||||||
nlmclnt_locks_init_private(fl, host);
|
|
||||||
|
|
||||||
/* Set up the argument struct */
|
|
||||||
nlmclnt_setlockargs(call, fl);
|
|
||||||
|
|
||||||
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
|
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
|
||||||
if (fl->fl_type != F_UNLCK) {
|
if (fl->fl_type != F_UNLCK) {
|
||||||
|
@ -229,24 +206,26 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
|
||||||
else
|
else
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
|
|
||||||
out_restore:
|
fl->fl_ops->fl_release_private(fl);
|
||||||
|
fl->fl_ops = NULL;
|
||||||
|
|
||||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||||
current->blocked = oldset;
|
current->blocked = oldset;
|
||||||
recalc_sigpending();
|
recalc_sigpending();
|
||||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||||
|
|
||||||
done:
|
|
||||||
dprintk("lockd: clnt proc returns %d\n", status);
|
dprintk("lockd: clnt proc returns %d\n", status);
|
||||||
nlm_release_host(host);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nlmclnt_proc);
|
EXPORT_SYMBOL(nlmclnt_proc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate an NLM RPC call struct
|
* Allocate an NLM RPC call struct
|
||||||
|
*
|
||||||
|
* Note: the caller must hold a reference to host. In case of failure,
|
||||||
|
* this reference will be released.
|
||||||
*/
|
*/
|
||||||
struct nlm_rqst *
|
struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
|
||||||
nlmclnt_alloc_call(void)
|
|
||||||
{
|
{
|
||||||
struct nlm_rqst *call;
|
struct nlm_rqst *call;
|
||||||
|
|
||||||
|
@ -255,16 +234,30 @@ nlmclnt_alloc_call(void)
|
||||||
if (call != NULL) {
|
if (call != NULL) {
|
||||||
locks_init_lock(&call->a_args.lock.fl);
|
locks_init_lock(&call->a_args.lock.fl);
|
||||||
locks_init_lock(&call->a_res.lock.fl);
|
locks_init_lock(&call->a_res.lock.fl);
|
||||||
|
call->a_host = host;
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
if (signalled())
|
if (signalled())
|
||||||
break;
|
break;
|
||||||
printk("nlmclnt_alloc_call: failed, waiting for memory\n");
|
printk("nlm_alloc_call: failed, waiting for memory\n");
|
||||||
schedule_timeout_interruptible(5*HZ);
|
schedule_timeout_interruptible(5*HZ);
|
||||||
}
|
}
|
||||||
|
nlm_release_host(host);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nlm_release_call(struct nlm_rqst *call)
|
||||||
|
{
|
||||||
|
nlm_release_host(call->a_host);
|
||||||
|
nlmclnt_release_lockargs(call);
|
||||||
|
kfree(call);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nlmclnt_rpc_release(void *data)
|
||||||
|
{
|
||||||
|
return nlm_release_call(data);
|
||||||
|
}
|
||||||
|
|
||||||
static int nlm_wait_on_grace(wait_queue_head_t *queue)
|
static int nlm_wait_on_grace(wait_queue_head_t *queue)
|
||||||
{
|
{
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
|
@ -361,7 +354,7 @@ in_grace_period:
|
||||||
/*
|
/*
|
||||||
* Generic NLM call, async version.
|
* Generic NLM call, async version.
|
||||||
*/
|
*/
|
||||||
int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
|
int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
|
||||||
{
|
{
|
||||||
struct nlm_host *host = req->a_host;
|
struct nlm_host *host = req->a_host;
|
||||||
struct rpc_clnt *clnt;
|
struct rpc_clnt *clnt;
|
||||||
|
@ -369,48 +362,23 @@ int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops
|
||||||
.rpc_argp = &req->a_args,
|
.rpc_argp = &req->a_args,
|
||||||
.rpc_resp = &req->a_res,
|
.rpc_resp = &req->a_res,
|
||||||
};
|
};
|
||||||
int status;
|
int status = -ENOLCK;
|
||||||
|
|
||||||
dprintk("lockd: call procedure %d on %s (async)\n",
|
dprintk("lockd: call procedure %d on %s (async)\n",
|
||||||
(int)proc, host->h_name);
|
(int)proc, host->h_name);
|
||||||
|
|
||||||
/* If we have no RPC client yet, create one. */
|
/* If we have no RPC client yet, create one. */
|
||||||
if ((clnt = nlm_bind_host(host)) == NULL)
|
clnt = nlm_bind_host(host);
|
||||||
return -ENOLCK;
|
if (clnt == NULL)
|
||||||
|
goto out_err;
|
||||||
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
||||||
|
|
||||||
/* bootstrap and kick off the async RPC call */
|
/* bootstrap and kick off the async RPC call */
|
||||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
|
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
|
||||||
|
if (status == 0)
|
||||||
return status;
|
return 0;
|
||||||
}
|
out_err:
|
||||||
|
nlm_release_call(req);
|
||||||
static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
|
|
||||||
{
|
|
||||||
struct nlm_host *host = req->a_host;
|
|
||||||
struct rpc_clnt *clnt;
|
|
||||||
struct nlm_args *argp = &req->a_args;
|
|
||||||
struct nlm_res *resp = &req->a_res;
|
|
||||||
struct rpc_message msg = {
|
|
||||||
.rpc_argp = argp,
|
|
||||||
.rpc_resp = resp,
|
|
||||||
};
|
|
||||||
int status;
|
|
||||||
|
|
||||||
dprintk("lockd: call procedure %d on %s (async)\n",
|
|
||||||
(int)proc, host->h_name);
|
|
||||||
|
|
||||||
/* If we have no RPC client yet, create one. */
|
|
||||||
if ((clnt = nlm_bind_host(host)) == NULL)
|
|
||||||
return -ENOLCK;
|
|
||||||
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
|
||||||
|
|
||||||
/* Increment host refcount */
|
|
||||||
nlm_get_host(host);
|
|
||||||
/* bootstrap and kick off the async RPC call */
|
|
||||||
status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req);
|
|
||||||
if (status < 0)
|
|
||||||
nlm_release_host(host);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,26 +391,28 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = nlmclnt_call(req, NLMPROC_TEST);
|
status = nlmclnt_call(req, NLMPROC_TEST);
|
||||||
nlmclnt_release_lockargs(req);
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
goto out;
|
||||||
|
|
||||||
status = req->a_res.status;
|
switch (req->a_res.status) {
|
||||||
if (status == NLM_LCK_GRANTED) {
|
case NLM_LCK_GRANTED:
|
||||||
fl->fl_type = F_UNLCK;
|
fl->fl_type = F_UNLCK;
|
||||||
} if (status == NLM_LCK_DENIED) {
|
break;
|
||||||
/*
|
case NLM_LCK_DENIED:
|
||||||
* Report the conflicting lock back to the application.
|
/*
|
||||||
*/
|
* Report the conflicting lock back to the application.
|
||||||
fl->fl_start = req->a_res.lock.fl.fl_start;
|
*/
|
||||||
fl->fl_end = req->a_res.lock.fl.fl_start;
|
fl->fl_start = req->a_res.lock.fl.fl_start;
|
||||||
fl->fl_type = req->a_res.lock.fl.fl_type;
|
fl->fl_end = req->a_res.lock.fl.fl_start;
|
||||||
fl->fl_pid = 0;
|
fl->fl_type = req->a_res.lock.fl.fl_type;
|
||||||
} else {
|
fl->fl_pid = 0;
|
||||||
return nlm_stat_to_errno(req->a_res.status);
|
break;
|
||||||
|
default:
|
||||||
|
status = nlm_stat_to_errno(req->a_res.status);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
return 0;
|
nlm_release_call(req);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
|
static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl)
|
||||||
|
@ -560,7 +530,7 @@ out_unblock:
|
||||||
if (resp->status == NLM_LCK_BLOCKED)
|
if (resp->status == NLM_LCK_BLOCKED)
|
||||||
nlmclnt_cancel(host, req->a_args.block, fl);
|
nlmclnt_cancel(host, req->a_args.block, fl);
|
||||||
out:
|
out:
|
||||||
nlmclnt_release_lockargs(req);
|
nlm_release_call(req);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,32 +593,24 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||||
*/
|
*/
|
||||||
do_vfs_lock(fl);
|
do_vfs_lock(fl);
|
||||||
|
|
||||||
if (req->a_flags & RPC_TASK_ASYNC) {
|
if (req->a_flags & RPC_TASK_ASYNC)
|
||||||
status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
|
return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
|
||||||
&nlmclnt_unlock_ops);
|
|
||||||
/* Hrmf... Do the unlock early since locks_remove_posix()
|
|
||||||
* really expects us to free the lock synchronously */
|
|
||||||
if (status < 0) {
|
|
||||||
nlmclnt_release_lockargs(req);
|
|
||||||
kfree(req);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = nlmclnt_call(req, NLMPROC_UNLOCK);
|
status = nlmclnt_call(req, NLMPROC_UNLOCK);
|
||||||
nlmclnt_release_lockargs(req);
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
return status;
|
goto out;
|
||||||
|
|
||||||
|
status = 0;
|
||||||
if (resp->status == NLM_LCK_GRANTED)
|
if (resp->status == NLM_LCK_GRANTED)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
if (resp->status != NLM_LCK_DENIED_NOLOCKS)
|
if (resp->status != NLM_LCK_DENIED_NOLOCKS)
|
||||||
printk("lockd: unexpected unlock status: %d\n", resp->status);
|
printk("lockd: unexpected unlock status: %d\n", resp->status);
|
||||||
|
|
||||||
/* What to do now? I'm out of my depth... */
|
/* What to do now? I'm out of my depth... */
|
||||||
|
status = -ENOLCK;
|
||||||
return -ENOLCK;
|
out:
|
||||||
|
nlm_release_call(req);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
|
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
|
||||||
|
@ -670,9 +632,6 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
|
||||||
if (status != NLM_LCK_GRANTED)
|
if (status != NLM_LCK_GRANTED)
|
||||||
printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
|
printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
|
||||||
die:
|
die:
|
||||||
nlm_release_host(req->a_host);
|
|
||||||
nlmclnt_release_lockargs(req);
|
|
||||||
kfree(req);
|
|
||||||
return;
|
return;
|
||||||
retry_rebind:
|
retry_rebind:
|
||||||
nlm_rebind_host(req->a_host);
|
nlm_rebind_host(req->a_host);
|
||||||
|
@ -682,6 +641,7 @@ die:
|
||||||
|
|
||||||
static const struct rpc_call_ops nlmclnt_unlock_ops = {
|
static const struct rpc_call_ops nlmclnt_unlock_ops = {
|
||||||
.rpc_call_done = nlmclnt_unlock_callback,
|
.rpc_call_done = nlmclnt_unlock_callback,
|
||||||
|
.rpc_release = nlmclnt_rpc_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -703,20 +663,15 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
|
||||||
recalc_sigpending();
|
recalc_sigpending();
|
||||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||||
|
|
||||||
req = nlmclnt_alloc_call();
|
req = nlm_alloc_call(nlm_get_host(host));
|
||||||
if (!req)
|
if (!req)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
req->a_host = host;
|
|
||||||
req->a_flags = RPC_TASK_ASYNC;
|
req->a_flags = RPC_TASK_ASYNC;
|
||||||
|
|
||||||
nlmclnt_setlockargs(req, fl);
|
nlmclnt_setlockargs(req, fl);
|
||||||
req->a_args.block = block;
|
req->a_args.block = block;
|
||||||
|
|
||||||
status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
|
status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
|
||||||
if (status < 0) {
|
|
||||||
nlmclnt_release_lockargs(req);
|
|
||||||
kfree(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||||
current->blocked = oldset;
|
current->blocked = oldset;
|
||||||
|
@ -757,9 +712,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
die:
|
die:
|
||||||
nlm_release_host(req->a_host);
|
|
||||||
nlmclnt_release_lockargs(req);
|
|
||||||
kfree(req);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
retry_cancel:
|
retry_cancel:
|
||||||
|
@ -773,6 +725,7 @@ retry_cancel:
|
||||||
|
|
||||||
static const struct rpc_call_ops nlmclnt_cancel_ops = {
|
static const struct rpc_call_ops nlmclnt_cancel_ops = {
|
||||||
.rpc_call_done = nlmclnt_cancel_callback,
|
.rpc_call_done = nlmclnt_cancel_callback,
|
||||||
|
.rpc_release = nlmclnt_rpc_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -480,43 +480,37 @@ nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
|
||||||
struct nlm_host *host;
|
struct nlm_host *host;
|
||||||
struct nlm_rqst *call;
|
struct nlm_rqst *call;
|
||||||
|
|
||||||
if (!(call = nlmclnt_alloc_call()))
|
host = nlmsvc_lookup_host(rqstp);
|
||||||
|
if (host == NULL)
|
||||||
return rpc_system_err;
|
return rpc_system_err;
|
||||||
|
|
||||||
host = nlmsvc_lookup_host(rqstp);
|
call = nlm_alloc_call(host);
|
||||||
if (!host) {
|
if (call == NULL)
|
||||||
kfree(call);
|
|
||||||
return rpc_system_err;
|
return rpc_system_err;
|
||||||
}
|
|
||||||
|
|
||||||
call->a_flags = RPC_TASK_ASYNC;
|
call->a_flags = RPC_TASK_ASYNC;
|
||||||
call->a_host = host;
|
|
||||||
memcpy(&call->a_args, resp, sizeof(*resp));
|
memcpy(&call->a_args, resp, sizeof(*resp));
|
||||||
|
|
||||||
if (nlmsvc_async_call(call, proc, &nlm4svc_callback_ops) < 0)
|
if (nlm_async_call(call, proc, &nlm4svc_callback_ops) < 0)
|
||||||
goto error;
|
return rpc_system_err;
|
||||||
|
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
error:
|
|
||||||
kfree(call);
|
|
||||||
nlm_release_host(host);
|
|
||||||
return rpc_system_err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
|
static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
|
||||||
{
|
{
|
||||||
struct nlm_rqst *call = data;
|
dprintk("lockd: %4d callback returned %d\n", task->tk_pid,
|
||||||
|
-task->tk_status);
|
||||||
|
}
|
||||||
|
|
||||||
if (task->tk_status < 0) {
|
static void nlm4svc_callback_release(void *data)
|
||||||
dprintk("lockd: %4d callback failed (errno = %d)\n",
|
{
|
||||||
task->tk_pid, -task->tk_status);
|
nlm_release_call(data);
|
||||||
}
|
|
||||||
nlm_release_host(call->a_host);
|
|
||||||
kfree(call);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rpc_call_ops nlm4svc_callback_ops = {
|
static const struct rpc_call_ops nlm4svc_callback_ops = {
|
||||||
.rpc_call_done = nlm4svc_callback_exit,
|
.rpc_call_done = nlm4svc_callback_exit,
|
||||||
|
.rpc_release = nlm4svc_callback_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -117,12 +117,12 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock, int remove)
|
||||||
(long long)lock->fl.fl_start,
|
(long long)lock->fl.fl_start,
|
||||||
(long long)lock->fl.fl_end, lock->fl.fl_type);
|
(long long)lock->fl.fl_end, lock->fl.fl_type);
|
||||||
for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
|
for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
|
||||||
fl = &block->b_call.a_args.lock.fl;
|
fl = &block->b_call->a_args.lock.fl;
|
||||||
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
|
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
|
||||||
block->b_file, fl->fl_pid,
|
block->b_file, fl->fl_pid,
|
||||||
(long long)fl->fl_start,
|
(long long)fl->fl_start,
|
||||||
(long long)fl->fl_end, fl->fl_type,
|
(long long)fl->fl_end, fl->fl_type,
|
||||||
nlmdbg_cookie2a(&block->b_call.a_args.cookie));
|
nlmdbg_cookie2a(&block->b_call->a_args.cookie));
|
||||||
if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
|
if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
*head = block->b_next;
|
*head = block->b_next;
|
||||||
|
@ -156,7 +156,7 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
|
||||||
for (block = nlm_blocked; block; block = block->b_next) {
|
for (block = nlm_blocked; block; block = block->b_next) {
|
||||||
dprintk("cookie: head of blocked queue %p, block %p\n",
|
dprintk("cookie: head of blocked queue %p, block %p\n",
|
||||||
nlm_blocked, block);
|
nlm_blocked, block);
|
||||||
if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)
|
if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
|
||||||
&& nlm_cmp_addr(sin, &block->b_host->h_addr))
|
&& nlm_cmp_addr(sin, &block->b_host->h_addr))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -182,28 +182,30 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
{
|
{
|
||||||
struct nlm_block *block;
|
struct nlm_block *block;
|
||||||
struct nlm_host *host;
|
struct nlm_host *host;
|
||||||
struct nlm_rqst *call;
|
struct nlm_rqst *call = NULL;
|
||||||
|
|
||||||
/* Create host handle for callback */
|
/* Create host handle for callback */
|
||||||
host = nlmsvc_lookup_host(rqstp);
|
host = nlmsvc_lookup_host(rqstp);
|
||||||
if (host == NULL)
|
if (host == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
call = nlm_alloc_call(host);
|
||||||
|
if (call == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Allocate memory for block, and initialize arguments */
|
/* Allocate memory for block, and initialize arguments */
|
||||||
if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL)))
|
block = kzalloc(sizeof(*block), GFP_KERNEL);
|
||||||
|
if (block == NULL)
|
||||||
goto failed;
|
goto failed;
|
||||||
memset(block, 0, sizeof(*block));
|
|
||||||
locks_init_lock(&block->b_call.a_args.lock.fl);
|
|
||||||
locks_init_lock(&block->b_call.a_res.lock.fl);
|
|
||||||
kref_init(&block->b_count);
|
kref_init(&block->b_count);
|
||||||
|
|
||||||
if (!nlmsvc_setgrantargs(&block->b_call, lock))
|
if (!nlmsvc_setgrantargs(call, lock))
|
||||||
goto failed_free;
|
goto failed_free;
|
||||||
|
|
||||||
/* Set notifier function for VFS, and init args */
|
/* Set notifier function for VFS, and init args */
|
||||||
block->b_call.a_args.lock.fl.fl_flags |= FL_SLEEP;
|
call->a_args.lock.fl.fl_flags |= FL_SLEEP;
|
||||||
block->b_call.a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
|
call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
|
||||||
block->b_call.a_args.cookie = *cookie; /* see above */
|
call->a_args.cookie = *cookie; /* see above */
|
||||||
|
|
||||||
dprintk("lockd: created block %p...\n", block);
|
dprintk("lockd: created block %p...\n", block);
|
||||||
|
|
||||||
|
@ -217,16 +219,16 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
file->f_blocks = block;
|
file->f_blocks = block;
|
||||||
|
|
||||||
/* Set up RPC arguments for callback */
|
/* Set up RPC arguments for callback */
|
||||||
call = &block->b_call;
|
block->b_call = call;
|
||||||
call->a_host = host;
|
|
||||||
call->a_flags = RPC_TASK_ASYNC;
|
call->a_flags = RPC_TASK_ASYNC;
|
||||||
|
call->a_block = block;
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
|
|
||||||
failed_free:
|
failed_free:
|
||||||
kfree(block);
|
kfree(block);
|
||||||
failed:
|
failed:
|
||||||
nlm_release_host(host);
|
nlm_release_call(call);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +244,7 @@ static int nlmsvc_unlink_block(struct nlm_block *block)
|
||||||
dprintk("lockd: unlinking block %p...\n", block);
|
dprintk("lockd: unlinking block %p...\n", block);
|
||||||
|
|
||||||
/* Remove block from list */
|
/* Remove block from list */
|
||||||
status = posix_unblock_lock(block->b_file->f_file, &block->b_call.a_args.lock.fl);
|
status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl);
|
||||||
nlmsvc_remove_block(block);
|
nlmsvc_remove_block(block);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -263,9 +265,8 @@ static void nlmsvc_free_block(struct kref *kref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->b_host)
|
nlmsvc_freegrantargs(block->b_call);
|
||||||
nlm_release_host(block->b_host);
|
nlm_release_call(block->b_call);
|
||||||
nlmsvc_freegrantargs(&block->b_call);
|
|
||||||
kfree(block);
|
kfree(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,10 +317,8 @@ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
|
||||||
|
|
||||||
if (lock->oh.len > NLMCLNT_OHSIZE) {
|
if (lock->oh.len > NLMCLNT_OHSIZE) {
|
||||||
void *data = kmalloc(lock->oh.len, GFP_KERNEL);
|
void *data = kmalloc(lock->oh.len, GFP_KERNEL);
|
||||||
if (!data) {
|
if (!data)
|
||||||
nlmsvc_freegrantargs(call);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
call->a_args.lock.oh.data = (u8 *) data;
|
call->a_args.lock.oh.data = (u8 *) data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,17 +328,8 @@ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
|
||||||
|
|
||||||
static void nlmsvc_freegrantargs(struct nlm_rqst *call)
|
static void nlmsvc_freegrantargs(struct nlm_rqst *call)
|
||||||
{
|
{
|
||||||
struct file_lock *fl = &call->a_args.lock.fl;
|
if (call->a_args.lock.oh.data != call->a_owner)
|
||||||
/*
|
|
||||||
* Check whether we allocated memory for the owner.
|
|
||||||
*/
|
|
||||||
if (call->a_args.lock.oh.data != (u8 *) call->a_owner) {
|
|
||||||
kfree(call->a_args.lock.oh.data);
|
kfree(call->a_args.lock.oh.data);
|
||||||
}
|
|
||||||
if (fl->fl_ops && fl->fl_ops->fl_release_private)
|
|
||||||
fl->fl_ops->fl_release_private(fl);
|
|
||||||
if (fl->fl_lmops && fl->fl_lmops->fl_release_private)
|
|
||||||
fl->fl_lmops->fl_release_private(fl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -371,9 +361,9 @@ again:
|
||||||
block = nlmsvc_lookup_block(file, lock, 0);
|
block = nlmsvc_lookup_block(file, lock, 0);
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
if (newblock != NULL)
|
if (newblock != NULL)
|
||||||
lock = &newblock->b_call.a_args.lock;
|
lock = &newblock->b_call->a_args.lock;
|
||||||
} else
|
} else
|
||||||
lock = &block->b_call.a_args.lock;
|
lock = &block->b_call->a_args.lock;
|
||||||
|
|
||||||
error = posix_lock_file(file->f_file, &lock->fl);
|
error = posix_lock_file(file->f_file, &lock->fl);
|
||||||
lock->fl.fl_flags &= ~FL_SLEEP;
|
lock->fl.fl_flags &= ~FL_SLEEP;
|
||||||
|
@ -523,7 +513,7 @@ nlmsvc_notify_blocked(struct file_lock *fl)
|
||||||
|
|
||||||
dprintk("lockd: VFS unblock notification for block %p\n", fl);
|
dprintk("lockd: VFS unblock notification for block %p\n", fl);
|
||||||
for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
|
for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
|
||||||
if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
|
if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
|
||||||
nlmsvc_insert_block(block, 0);
|
nlmsvc_insert_block(block, 0);
|
||||||
svc_wake_up(block->b_daemon);
|
svc_wake_up(block->b_daemon);
|
||||||
return;
|
return;
|
||||||
|
@ -558,7 +548,7 @@ static void
|
||||||
nlmsvc_grant_blocked(struct nlm_block *block)
|
nlmsvc_grant_blocked(struct nlm_block *block)
|
||||||
{
|
{
|
||||||
struct nlm_file *file = block->b_file;
|
struct nlm_file *file = block->b_file;
|
||||||
struct nlm_lock *lock = &block->b_call.a_args.lock;
|
struct nlm_lock *lock = &block->b_call->a_args.lock;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
dprintk("lockd: grant blocked lock %p\n", block);
|
dprintk("lockd: grant blocked lock %p\n", block);
|
||||||
|
@ -606,7 +596,7 @@ callback:
|
||||||
|
|
||||||
/* Call the client */
|
/* Call the client */
|
||||||
kref_get(&block->b_count);
|
kref_get(&block->b_count);
|
||||||
if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
|
if (nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG,
|
||||||
&nlmsvc_grant_ops) < 0)
|
&nlmsvc_grant_ops) < 0)
|
||||||
nlmsvc_release_block(block);
|
nlmsvc_release_block(block);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
@ -624,7 +614,7 @@ out_unlock:
|
||||||
static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
|
static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
|
||||||
{
|
{
|
||||||
struct nlm_rqst *call = data;
|
struct nlm_rqst *call = data;
|
||||||
struct nlm_block *block = container_of(call, struct nlm_block, b_call);
|
struct nlm_block *block = call->a_block;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
|
||||||
dprintk("lockd: GRANT_MSG RPC callback\n");
|
dprintk("lockd: GRANT_MSG RPC callback\n");
|
||||||
|
|
|
@ -505,43 +505,36 @@ nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
|
||||||
struct nlm_host *host;
|
struct nlm_host *host;
|
||||||
struct nlm_rqst *call;
|
struct nlm_rqst *call;
|
||||||
|
|
||||||
if (!(call = nlmclnt_alloc_call()))
|
host = nlmsvc_lookup_host(rqstp);
|
||||||
|
if (host == NULL)
|
||||||
return rpc_system_err;
|
return rpc_system_err;
|
||||||
|
|
||||||
host = nlmsvc_lookup_host(rqstp);
|
call = nlm_alloc_call(host);
|
||||||
if (!host) {
|
if (call == NULL)
|
||||||
kfree(call);
|
|
||||||
return rpc_system_err;
|
return rpc_system_err;
|
||||||
}
|
|
||||||
|
|
||||||
call->a_flags = RPC_TASK_ASYNC;
|
call->a_flags = RPC_TASK_ASYNC;
|
||||||
call->a_host = host;
|
|
||||||
memcpy(&call->a_args, resp, sizeof(*resp));
|
memcpy(&call->a_args, resp, sizeof(*resp));
|
||||||
|
|
||||||
if (nlmsvc_async_call(call, proc, &nlmsvc_callback_ops) < 0)
|
if (nlm_async_call(call, proc, &nlmsvc_callback_ops) < 0)
|
||||||
goto error;
|
return rpc_system_err;
|
||||||
|
|
||||||
return rpc_success;
|
return rpc_success;
|
||||||
error:
|
|
||||||
nlm_release_host(host);
|
|
||||||
kfree(call);
|
|
||||||
return rpc_system_err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
|
static void nlmsvc_callback_exit(struct rpc_task *task, void *data)
|
||||||
{
|
{
|
||||||
struct nlm_rqst *call = data;
|
dprintk("lockd: %4d callback returned %d\n", task->tk_pid,
|
||||||
|
-task->tk_status);
|
||||||
|
}
|
||||||
|
|
||||||
if (task->tk_status < 0) {
|
static void nlmsvc_callback_release(void *data)
|
||||||
dprintk("lockd: %4d callback failed (errno = %d)\n",
|
{
|
||||||
task->tk_pid, -task->tk_status);
|
nlm_release_call(data);
|
||||||
}
|
|
||||||
nlm_release_host(call->a_host);
|
|
||||||
kfree(call);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rpc_call_ops nlmsvc_callback_ops = {
|
static const struct rpc_call_ops nlmsvc_callback_ops = {
|
||||||
.rpc_call_done = nlmsvc_callback_exit,
|
.rpc_call_done = nlmsvc_callback_exit,
|
||||||
|
.rpc_release = nlmsvc_callback_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -86,8 +86,9 @@ struct nlm_rqst {
|
||||||
struct nlm_host * a_host; /* host handle */
|
struct nlm_host * a_host; /* host handle */
|
||||||
struct nlm_args a_args; /* arguments */
|
struct nlm_args a_args; /* arguments */
|
||||||
struct nlm_res a_res; /* result */
|
struct nlm_res a_res; /* result */
|
||||||
|
struct nlm_block * a_block;
|
||||||
unsigned int a_retries; /* Retry count */
|
unsigned int a_retries; /* Retry count */
|
||||||
char a_owner[NLMCLNT_OHSIZE];
|
u8 a_owner[NLMCLNT_OHSIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -115,7 +116,7 @@ struct nlm_block {
|
||||||
struct kref b_count; /* Reference count */
|
struct kref b_count; /* Reference count */
|
||||||
struct nlm_block * b_next; /* linked list (all blocks) */
|
struct nlm_block * b_next; /* linked list (all blocks) */
|
||||||
struct nlm_block * b_fnext; /* linked list (per file) */
|
struct nlm_block * b_fnext; /* linked list (per file) */
|
||||||
struct nlm_rqst b_call; /* RPC args & callback info */
|
struct nlm_rqst * b_call; /* RPC args & callback info */
|
||||||
struct svc_serv * b_daemon; /* NLM service */
|
struct svc_serv * b_daemon; /* NLM service */
|
||||||
struct nlm_host * b_host; /* host handle for RPC clnt */
|
struct nlm_host * b_host; /* host handle for RPC clnt */
|
||||||
unsigned long b_when; /* next re-xmit */
|
unsigned long b_when; /* next re-xmit */
|
||||||
|
@ -147,7 +148,9 @@ extern unsigned long nlmsvc_timeout;
|
||||||
/*
|
/*
|
||||||
* Lockd client functions
|
* Lockd client functions
|
||||||
*/
|
*/
|
||||||
struct nlm_rqst * nlmclnt_alloc_call(void);
|
struct nlm_rqst * nlm_alloc_call(struct nlm_host *host);
|
||||||
|
void nlm_release_call(struct nlm_rqst *);
|
||||||
|
int nlm_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
|
||||||
struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
|
struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
|
||||||
void nlmclnt_finish_block(struct nlm_wait *block);
|
void nlmclnt_finish_block(struct nlm_wait *block);
|
||||||
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
|
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
|
||||||
|
@ -172,7 +175,6 @@ extern struct nlm_host *nlm_find_client(void);
|
||||||
/*
|
/*
|
||||||
* Server-side lock handling
|
* Server-side lock handling
|
||||||
*/
|
*/
|
||||||
int nlmsvc_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
|
|
||||||
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
|
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
|
||||||
struct nlm_lock *, int, struct nlm_cookie *);
|
struct nlm_lock *, int, struct nlm_cookie *);
|
||||||
u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
|
u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
|
||||||
|
|
Loading…
Reference in New Issue