Merge branch 'for-2.6.27' of git://linux-nfs.org/~bfields/linux
[pandora-kernel.git] / fs / lockd / svc4proc.c
index b10f913..3994446 100644 (file)
 
 #define NLMDBG_FACILITY                NLMDBG_CLIENT
 
-static u32     nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
-
-static const struct rpc_call_ops nlm4svc_callback_ops;
-
 /*
  * Obtain client and file from arguments
  */
-static u32
+static __be32
 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
                        struct nlm_host **hostp, struct nlm_file **filp)
 {
        struct nlm_host         *host = NULL;
        struct nlm_file         *file = NULL;
        struct nlm_lock         *lock = &argp->lock;
-       u32                     error = 0;
+       __be32                  error = 0;
 
        /* nfsd callbacks must have been installed for this procedure */
        if (!nlmsvc_ops)
                return nlm_lck_denied_nolocks;
 
        /* Obtain host handle */
-       if (!(host = nlmsvc_lookup_host(rqstp))
-        || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+       if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+        || (argp->monitor && nsm_monitor(host) < 0))
                goto no_locks;
        *hostp = host;
 
@@ -62,8 +58,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
        return 0;
 
 no_locks:
-       if (host)
-               nlm_release_host(host);
+       nlm_release_host(host);
        if (error)
                return error;   
        return nlm_lck_denied_nolocks;
@@ -72,7 +67,7 @@ no_locks:
 /*
  * NULL: Test for presence of service
  */
-static int
+static __be32
 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
        dprintk("lockd: NULL          called\n");
@@ -82,12 +77,13 @@ nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 /*
  * TEST: Check for conflicting lock
  */
-static int
+static __be32
 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
                                         struct nlm_res  *resp)
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       int rc = rpc_success;
 
        dprintk("lockd: TEST4        called\n");
        resp->cookie = argp->cookie;
@@ -95,28 +91,32 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Don't accept test requests during grace period */
        if (nlmsvc_grace_period) {
                resp->status = nlm_lck_denied_grace_period;
-               return rpc_success;
+               return rc;
        }
 
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now check for conflicting locks */
-       resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+       resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie);
+       if (resp->status == nlm_drop_reply)
+               rc = rpc_drop_reply;
+       else
+               dprintk("lockd: TEST4        status %d\n", ntohl(resp->status));
 
-       dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
        nlm_release_host(host);
        nlm_release_file(file);
-       return rpc_success;
+       return rc;
 }
 
-static int
+static __be32
 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
                                         struct nlm_res  *resp)
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       int rc = rpc_success;
 
        dprintk("lockd: LOCK          called\n");
 
@@ -125,12 +125,12 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Don't accept new lock requests during grace period */
        if (nlmsvc_grace_period && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
-               return rpc_success;
+               return rc;
        }
 
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
 #if 0
        /* If supplied state doesn't match current state, we assume it's
@@ -145,16 +145,19 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 #endif
 
        /* Now try to lock the file */
-       resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
+       resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
                                        argp->block, &argp->cookie);
+       if (resp->status == nlm_drop_reply)
+               rc = rpc_drop_reply;
+       else
+               dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
 
-       dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
        nlm_release_host(host);
        nlm_release_file(file);
-       return rpc_success;
+       return rc;
 }
 
-static int
+static __be32
 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
                                           struct nlm_res  *resp)
 {
@@ -173,7 +176,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Try to cancel request. */
        resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
@@ -187,7 +190,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 /*
  * UNLOCK: release a lock
  */
-static int
+static __be32
 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
                                           struct nlm_res  *resp)
 {
@@ -206,7 +209,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now try to remove the lock */
        resp->status = nlmsvc_unlock(file, &argp->lock);
@@ -221,102 +224,112 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
  * GRANTED: A server calls us to tell that a process' lock request
  * was granted
  */
-static int
+static __be32
 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
                                            struct nlm_res  *resp)
 {
        resp->cookie = argp->cookie;
 
        dprintk("lockd: GRANTED       called\n");
-       resp->status = nlmclnt_grant(&rqstp->rq_addr, &argp->lock);
+       resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
        dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
        return rpc_success;
 }
 
+/*
+ * This is the generic lockd callback for async RPC calls
+ */
+static void nlm4svc_callback_exit(struct rpc_task *task, void *data)
+{
+       dprintk("lockd: %5u callback returned %d\n", task->tk_pid,
+                       -task->tk_status);
+}
+
+static void nlm4svc_callback_release(void *data)
+{
+       lock_kernel();
+       nlm_release_call(data);
+       unlock_kernel();
+}
+
+static const struct rpc_call_ops nlm4svc_callback_ops = {
+       .rpc_call_done = nlm4svc_callback_exit,
+       .rpc_release = nlm4svc_callback_release,
+};
+
 /*
  * `Async' versions of the above service routines. They aren't really,
  * because we send the callback before the reply proper. I hope this
  * doesn't break any clients.
  */
-static int
-nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
-                                            void            *resp)
+static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
+               __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res  *))
 {
-       struct nlm_res  res;
-       u32             stat;
+       struct nlm_host *host;
+       struct nlm_rqst *call;
+       __be32 stat;
 
-       dprintk("lockd: TEST_MSG      called\n");
-       memset(&res, 0, sizeof(res));
+       host = nlmsvc_lookup_host(rqstp,
+                                 argp->lock.caller,
+                                 argp->lock.len);
+       if (host == NULL)
+               return rpc_system_err;
 
-       if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
-               stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
-       return stat;
+       call = nlm_alloc_call(host);
+       if (call == NULL)
+               return rpc_system_err;
+
+       stat = func(rqstp, argp, &call->a_res);
+       if (stat != 0) {
+               nlm_release_call(call);
+               return stat;
+       }
+
+       call->a_flags = RPC_TASK_ASYNC;
+       if (nlm_async_reply(call, proc, &nlm4svc_callback_ops) < 0)
+               return rpc_system_err;
+       return rpc_success;
 }
 
-static int
-nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                             void            *resp)
 {
-       struct nlm_res  res;
-       u32             stat;
+       dprintk("lockd: TEST_MSG      called\n");
+       return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test);
+}
 
+static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+                                            void            *resp)
+{
        dprintk("lockd: LOCK_MSG      called\n");
-       memset(&res, 0, sizeof(res));
-
-       if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
-               stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
-       return stat;
+       return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock);
 }
 
-static int
-nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                               void            *resp)
 {
-       struct nlm_res  res;
-       u32             stat;
-
        dprintk("lockd: CANCEL_MSG    called\n");
-       memset(&res, 0, sizeof(res));
-
-       if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
-               stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
-       return stat;
+       return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel);
 }
 
-static int
-nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                                void            *resp)
 {
-       struct nlm_res  res;
-       u32             stat;
-
        dprintk("lockd: UNLOCK_MSG    called\n");
-       memset(&res, 0, sizeof(res));
-
-       if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
-               stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
-       return stat;
+       return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock);
 }
 
-static int
-nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
                                                 void            *resp)
 {
-       struct nlm_res  res;
-       u32             stat;
-
        dprintk("lockd: GRANTED_MSG   called\n");
-       memset(&res, 0, sizeof(res));
-
-       if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
-               stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
-       return stat;
+       return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, argp, nlm4svc_proc_granted);
 }
 
 /*
  * SHARE: create a DOS share or alter existing share.
  */
-static int
+static __be32
 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
                                          struct nlm_res  *resp)
 {
@@ -335,7 +348,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now try to create the share */
        resp->status = nlmsvc_share_file(host, file, argp);
@@ -349,7 +362,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
 /*
  * UNSHARE: Release a DOS share.
  */
-static int
+static __be32
 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
                                            struct nlm_res  *resp)
 {
@@ -368,7 +381,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now try to lock the file */
        resp->status = nlmsvc_unshare_file(host, file, argp);
@@ -382,7 +395,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
 /*
  * NM_LOCK: Create an unmonitored lock
  */
-static int
+static __be32
 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
                                            struct nlm_res  *resp)
 {
@@ -395,7 +408,7 @@ nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 /*
  * FREE_ALL: Release all locks and shares held by client
  */
-static int
+static __be32
 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
                                             void            *resp)
 {
@@ -413,51 +426,37 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
 /*
  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
  */
-static int
+static __be32
 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
                                              void              *resp)
 {
-       struct sockaddr_in      saddr = rqstp->rq_addr;
-       int                     vers = argp->vers;
-       int                     prot = argp->proto >> 1;
+       struct sockaddr_in      saddr;
 
-       struct nlm_host         *host;
+       memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
 
        dprintk("lockd: SM_NOTIFY     called\n");
        if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
         || ntohs(saddr.sin_port) >= 1024) {
-               printk(KERN_WARNING
-                       "lockd: rejected NSM callback from %08x:%d\n",
-                       ntohl(rqstp->rq_addr.sin_addr.s_addr),
-                       ntohs(rqstp->rq_addr.sin_port));
+               char buf[RPC_MAX_ADDRBUFLEN];
+               printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
+                               svc_print_addr(rqstp, buf, sizeof(buf)));
                return rpc_system_err;
        }
 
        /* Obtain the host pointer for this NFS server and try to
         * reclaim all locks we hold on this server.
         */
+       memset(&saddr, 0, sizeof(saddr));
        saddr.sin_addr.s_addr = argp->addr;
+       nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
 
-       if ((argp->proto & 1)==0) {
-               if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
-                       nlmclnt_recovery(host, argp->state);
-                       nlm_release_host(host);
-               }
-       } else {
-               /* If we run on an NFS server, delete all locks held by the client */
-
-               if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
-                       nlmsvc_free_host_resources(host);
-                       nlm_release_host(host);
-               }
-       }
        return rpc_success;
 }
 
 /*
  * client sent a GRANTED_RES, let's remove the associated block
  */
-static int
+static __be32
 nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
                                                 void            *resp)
 {
@@ -466,60 +465,11 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
 
         dprintk("lockd: GRANTED_RES   called\n");
 
-        nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+        nlmsvc_grant_reply(&argp->cookie, argp->status);
         return rpc_success;
 }
 
 
-/*
- * 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_ops) < 0)
-               goto error;
-
-       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)
-{
-       struct nlm_rqst *call = data;
-
-       if (task->tk_status < 0) {
-               dprintk("lockd: %4d callback failed (errno = %d)\n",
-                                       task->tk_pid, -task->tk_status);
-       }
-       nlm_release_host(call->a_host);
-       kfree(call);
-}
-
-static const struct rpc_call_ops nlm4svc_callback_ops = {
-       .rpc_call_done = nlm4svc_callback_exit,
-};
-
 /*
  * NLM Server procedures.
  */