[PATCH] knfsd: Allow lockd to drop replies as appropriate
authorNeilBrown <neilb@suse.de>
Tue, 17 Oct 2006 07:10:18 +0000 (00:10 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 17 Oct 2006 15:18:46 +0000 (08:18 -0700)
It is possible for the ->fopen callback from lockd into nfsd to find that an
answer cannot be given straight away (an upcall is needed) and so the request
has to be 'dropped', to be retried later.  That error status is not currently
propagated back.

So:
  Change nlm_fopen to return nlm error codes (rather than a private
  protocol) and define a new nlm_drop_reply code.
  Cause nlm_drop_reply to cause the rpc request to get rpc_drop_reply
  when this error comes back.
  Cause svc_process to drop a request which returns a status of
  rpc_drop_reply.

[akpm@osdl.org: fix warning storm]
Cc: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/lockd/svc4proc.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/nfsd/lockd.c
include/linux/lockd/bind.h
include/linux/lockd/xdr.h
include/linux/sunrpc/msg_prot.h
include/linux/sunrpc/xdr.h
net/sunrpc/svc.c

index fa370f6eb07b27ddf2b1dc2b984ed5633b3d7c82..399ad11b97bebed99e7a1487a0dab9986d0144ad 100644 (file)
@@ -96,7 +96,7 @@ nlm4svc_proc_test(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 check for conflicting locks */
        resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
@@ -126,7 +126,7 @@ nlm4svc_proc_lock(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;
 
 #if 0
        /* If supplied state doesn't match current state, we assume it's
@@ -169,7 +169,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);
@@ -202,7 +202,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);
@@ -339,7 +339,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);
@@ -372,7 +372,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);
index 75b2c81bcb93c01782710b7a36fc501aea42ca9a..6a931f4ab75cacda0398e637f38cb2c3116f7c46 100644 (file)
@@ -59,7 +59,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
        struct nlm_host         *host = NULL;
        struct nlm_file         *file = NULL;
        struct nlm_lock         *lock = &argp->lock;
-       u32                     error;
+       u32                     error = 0;
 
        /* nfsd callbacks must have been installed for this procedure */
        if (!nlmsvc_ops)
@@ -88,6 +88,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
 no_locks:
        if (host)
                nlm_release_host(host);
+       if (error)
+               return error;
        return nlm_lck_denied_nolocks;
 }
 
@@ -122,7 +124,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlmsvc_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 = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
@@ -153,7 +155,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlmsvc_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
@@ -196,7 +198,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlmsvc_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 = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
@@ -229,7 +231,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlmsvc_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 = cast_status(nlmsvc_unlock(file, &argp->lock));
@@ -368,7 +370,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlmsvc_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 = cast_status(nlmsvc_share_file(host, file, argp));
@@ -401,7 +403,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
 
        /* Obtain client and file */
        if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
-               return rpc_success;
+               return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
 
        /* Now try to unshare the file */
        resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
index c5f9113cdc70e89d84c4789e8c1271bf1e52a7b6..7dac96e6c82c666f93d69743d74752dc08e69848 100644 (file)
@@ -135,12 +135,6 @@ out_unlock:
 
 out_free:
        kfree(file);
-#ifdef CONFIG_LOCKD_V4
-       if (nfserr == 1)
-               nfserr = nlm4_stale_fh;
-       else
-#endif
-       nfserr = nlm_lck_denied;
        goto out_unlock;
 }
 
index 7b889ff15ae63a96ef47be64172c7d360ef2d61a..9b9e7e127c03cadd442909c87b6a2012ebbd6432 100644 (file)
@@ -39,18 +39,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
        fh_put(&fh);
        rqstp->rq_client = NULL;
        exp_readunlock();
-       /* nlm and nfsd don't share error codes.
-        * we invent: 0 = no error
-        *            1 = stale file handle
-        *            2 = other error
+       /* We return nlm error codes as nlm doesn't know
+        * about nfsd, but nfsd does know about nlm..
         */
        switch (nfserr) {
        case nfs_ok:
                return 0;
+       case nfserr_dropit:
+               return nlm_drop_reply;
+#ifdef CONFIG_LOCKD_V4
        case nfserr_stale:
-               return 1;
+               return nlm4_stale_fh;
+#endif
        default:
-               return 2;
+               return nlm_lck_denied;
        }
 }
 
index 81e3a185f9515ada07ef16bef6b94a619e9196f6..aa50d89eacd77abb748ad7a892f20575b7c4b1bb 100644 (file)
 #define LINUX_LOCKD_BIND_H
 
 #include <linux/lockd/nlm.h>
+/* need xdr-encoded error codes too, so... */
+#include <linux/lockd/xdr.h>
+#ifdef CONFIG_LOCKD_V4
+#include <linux/lockd/xdr4.h>
+#endif
 
 /* Dummy declarations */
 struct svc_rqst;
index bb0a0f1caa91e9bc521686fe6dfed54d7b85c17a..66fdae3b490cca8eaa5ca96f7f9ab9e9eb43849e 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/nfs.h>
 #include <linux/sunrpc/xdr.h>
 
+struct svc_rqst;
+
 #define NLM_MAXCOOKIELEN       32
 #define NLM_MAXSTRLEN          1024
 
@@ -22,6 +24,8 @@
 #define        nlm_lck_blocked         __constant_htonl(NLM_LCK_BLOCKED)
 #define        nlm_lck_denied_grace_period     __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
 
+#define nlm_drop_reply         __constant_htonl(30000)
+
 /* Lock info passed via NLM */
 struct nlm_lock {
        char *                  caller;
index 1e65f2dd80e5d5aa4bbd8f5a7885862cccfe5c4f..606cb21652322d33ed1d389e44b6c304d4fb6b8f 100644 (file)
@@ -56,7 +56,9 @@ enum rpc_accept_stat {
        RPC_PROG_MISMATCH = 2,
        RPC_PROC_UNAVAIL = 3,
        RPC_GARBAGE_ARGS = 4,
-       RPC_SYSTEM_ERR = 5
+       RPC_SYSTEM_ERR = 5,
+       /* internal use only */
+       RPC_DROP_REPLY = 60000,
 };
 
 enum rpc_reject_stat {
index 953723b09bc6d73cd5ad97bd0143bdf1fbd162f9..ac69e55116060be1d29fb783a812d861011ac548 100644 (file)
@@ -74,6 +74,7 @@ struct xdr_buf {
 #define        rpc_proc_unavail        __constant_htonl(RPC_PROC_UNAVAIL)
 #define        rpc_garbage_args        __constant_htonl(RPC_GARBAGE_ARGS)
 #define        rpc_system_err          __constant_htonl(RPC_SYSTEM_ERR)
+#define        rpc_drop_reply          __constant_htonl(RPC_DROP_REPLY)
 
 #define        rpc_auth_ok             __constant_htonl(RPC_AUTH_OK)
 #define        rpc_autherr_badcred     __constant_htonl(RPC_AUTH_BADCRED)
index 2807fa0eab40bd7644386410a125dc52d1369893..eb44ec929ca115a5944b7dd8f380a79d3b057249 100644 (file)
@@ -828,6 +828,11 @@ svc_process(struct svc_rqst *rqstp)
                *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
 
                /* Encode reply */
+               if (*statp == rpc_drop_reply) {
+                       if (procp->pc_release)
+                               procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+                       goto dropit;
+               }
                if (*statp == rpc_success && (xdr = procp->pc_encode)
                 && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
                        dprintk("svc: failed to encode reply\n");