NLM/lockd: Add a reference counter to struct nlm_rqst
[deliverable/linux.git] / fs / lockd / clntproc.c
index 0b4acc1c5e7da2a87a4f626f957b913dae5faff3..749eb5328cb0cf0e51d3a3530a3eac01d60e7fe7 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/fs.h>
 #include <linux/nfs_fs.h>
 #include <linux/utsname.h>
-#include <linux/smp_lock.h>
 #include <linux/freezer.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
@@ -146,34 +145,21 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
        BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
 }
 
-/*
- * This is the main entry point for the NLM client.
+/**
+ * nlmclnt_proc - Perform a single client-side lock request
+ * @host: address of a valid nlm_host context representing the NLM server
+ * @cmd: fcntl-style file lock operation to perform
+ * @fl: address of arguments for the lock operation
+ *
  */
-int
-nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
+int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
 {
-       struct rpc_clnt         *client = NFS_CLIENT(inode);
-       struct sockaddr_in      addr;
-       struct nfs_server       *nfssrv = NFS_SERVER(inode);
-       struct nlm_host         *host;
        struct nlm_rqst         *call;
        sigset_t                oldset;
        unsigned long           flags;
-       int                     status, vers;
-
-       vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
-       if (NFS_PROTO(inode)->version > 3) {
-               printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
-               return -ENOLCK;
-       }
-
-       rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
-       host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers,
-                                  nfssrv->nfs_client->cl_hostname,
-                                  strlen(nfssrv->nfs_client->cl_hostname));
-       if (host == NULL)
-               return -ENOLCK;
+       int                     status;
 
+       nlm_get_host(host);
        call = nlm_alloc_call(host);
        if (call == NULL)
                return -ENOMEM;
@@ -220,7 +206,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
        dprintk("lockd: clnt proc returns %d\n", status);
        return status;
 }
-EXPORT_SYMBOL(nlmclnt_proc);
+EXPORT_SYMBOL_GPL(nlmclnt_proc);
 
 /*
  * Allocate an NLM RPC call struct
@@ -235,6 +221,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
        for(;;) {
                call = kzalloc(sizeof(*call), GFP_KERNEL);
                if (call != NULL) {
+                       atomic_set(&call->a_count, 1);
                        locks_init_lock(&call->a_args.lock.fl);
                        locks_init_lock(&call->a_res.lock.fl);
                        call->a_host = host;
@@ -251,6 +238,8 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
 
 void nlm_release_call(struct nlm_rqst *call)
 {
+       if (!atomic_dec_and_test(&call->a_count))
+               return;
        nlm_release_host(call->a_host);
        nlmclnt_release_lockargs(call);
        kfree(call);
@@ -258,7 +247,7 @@ void nlm_release_call(struct nlm_rqst *call)
 
 static void nlmclnt_rpc_release(void *data)
 {
-       return nlm_release_call(data);
+       nlm_release_call(data);
 }
 
 static int nlm_wait_on_grace(wait_queue_head_t *queue)
@@ -361,7 +350,6 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *
 {
        struct nlm_host *host = req->a_host;
        struct rpc_clnt *clnt;
-       int status = -ENOLCK;
 
        dprintk("lockd: call procedure %d on %s (async)\n",
                        (int)proc, host->h_name);
@@ -373,12 +361,10 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *
        msg->rpc_proc = &clnt->cl_procinfo[proc];
 
         /* bootstrap and kick off the async RPC call */
-        status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req);
-       if (status == 0)
-               return 0;
+        return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req);
 out_err:
-       nlm_release_call(req);
-       return status;
+       tk_ops->rpc_release(req);
+       return -ENOLCK;
 }
 
 int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
@@ -510,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
        }
        fl->fl_flags |= FL_ACCESS;
        status = do_vfs_lock(fl);
+       fl->fl_flags = fl_flags;
        if (status < 0)
                goto out;
 
@@ -547,10 +534,11 @@ again:
                        goto again;
                }
                /* Ensure the resulting lock will get added to granted list */
-               fl->fl_flags = fl_flags | FL_SLEEP;
+               fl->fl_flags |= FL_SLEEP;
                if (do_vfs_lock(fl) < 0)
                        printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
                up_read(&host->h_rwsem);
+               fl->fl_flags = fl_flags;
        }
        status = nlm_stat_to_errno(resp->status);
 out_unblock:
@@ -560,7 +548,6 @@ out_unblock:
                nlmclnt_cancel(host, req->a_args.block, fl);
 out:
        nlm_release_call(req);
-       fl->fl_flags = fl_flags;
        return status;
 }
 
@@ -615,7 +602,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 {
        struct nlm_host *host = req->a_host;
        struct nlm_res  *resp = &req->a_res;
-       int status = 0;
+       int status;
+       unsigned char fl_flags = fl->fl_flags;
 
        /*
         * Note: the server is supposed to either grant us the unlock
@@ -624,11 +612,13 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
         */
        fl->fl_flags |= FL_EXISTS;
        down_read(&host->h_rwsem);
-       if (do_vfs_lock(fl) == -ENOENT) {
-               up_read(&host->h_rwsem);
+       status = do_vfs_lock(fl);
+       up_read(&host->h_rwsem);
+       fl->fl_flags = fl_flags;
+       if (status == -ENOENT) {
+               status = 0;
                goto out;
        }
-       up_read(&host->h_rwsem);
 
        if (req->a_flags & RPC_TASK_ASYNC)
                return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
This page took 0.025475 seconds and 5 git commands to generate.