]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
SUNRPC: Add a callback to initialise server requests
authorTrond Myklebust <trondmy@gmail.com>
Tue, 9 Apr 2019 15:46:15 +0000 (11:46 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 24 Apr 2019 13:46:34 +0000 (09:46 -0400)
Add a callback to help initialise server requests before they are
processed. This will allow us to clean up the NFS server version
support, and to make it container safe.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/lockd/svc.c
fs/nfs/callback.c
fs/nfsd/nfssvc.c
include/linux/sunrpc/svc.h
net/sunrpc/svc.c

index 346ed161756dbca1d712f1ac389888ddc0ea1bf6..75415b21efdae1416460bd2b9e7fb5da2df94164 100644 (file)
@@ -807,5 +807,6 @@ static struct svc_program   nlmsvc_program = {
        .pg_name                = "lockd",              /* service name */
        .pg_class               = "nfsd",               /* share authentication with nfsd */
        .pg_stats               = &nlmsvc_stats,        /* stats table */
-       .pg_authenticate = &lockd_authenticate  /* export authentication */
+       .pg_authenticate        = &lockd_authenticate,  /* export authentication */
+       .pg_init_request        = svc_generic_init_request,
 };
index 0b602a39dd7132f5ba3d678c0279ff68bd3e341b..a9510374bad71950d5a61a0d2a9cffac7ab3ca9a 100644 (file)
@@ -457,4 +457,5 @@ static struct svc_program nfs4_callback_program = {
        .pg_class = "nfs",                              /* authentication class */
        .pg_stats = &nfs4_callback_stats,
        .pg_authenticate = nfs_callback_authenticate,
+       .pg_init_request = svc_generic_init_request,
 };
index 89cb484f1cfbeccde41d872298c7e08aaadd5b87..e26762e84798af467b6e826f490c2f3ec39b4b43 100644 (file)
@@ -86,6 +86,7 @@ static struct svc_program     nfsd_acl_program = {
        .pg_class               = "nfsd",
        .pg_stats               = &nfsd_acl_svcstats,
        .pg_authenticate        = &svc_set_client,
+       .pg_init_request        = svc_generic_init_request,
 };
 
 static struct svc_stat nfsd_acl_svcstats = {
@@ -118,6 +119,7 @@ struct svc_program          nfsd_program = {
        .pg_class               = "nfsd",               /* authentication class */
        .pg_stats               = &nfsd_svcstats,       /* version table */
        .pg_authenticate        = &svc_set_client,      /* export authentication */
+       .pg_init_request        = svc_generic_init_request,
 
 };
 
index 7ff12c9dbeaf9bcd4e8ce8a56afcf135aa30c0ca..f43d5765acffa52d09c412be7d314b041170288f 100644 (file)
@@ -383,6 +383,16 @@ struct svc_deferred_req {
        __be32                  args[0];
 };
 
+struct svc_process_info {
+       union {
+               int  (*dispatch)(struct svc_rqst *, __be32 *);
+               struct {
+                       unsigned int lovers;
+                       unsigned int hivers;
+               } mismatch;
+       };
+};
+
 /*
  * List of RPC programs on the same transport endpoint
  */
@@ -397,6 +407,9 @@ struct svc_program {
        char *                  pg_class;       /* class name: services sharing authentication */
        struct svc_stat *       pg_stats;       /* rpc statistics */
        int                     (*pg_authenticate)(struct svc_rqst *);
+       __be32                  (*pg_init_request)(struct svc_rqst *,
+                                                  const struct svc_program *,
+                                                  struct svc_process_info *);
 };
 
 /*
@@ -506,6 +519,9 @@ char                  *svc_fill_symlink_pathname(struct svc_rqst *rqstp,
                                             struct kvec *first, void *p,
                                             size_t total);
 __be32            svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err);
+__be32            svc_generic_init_request(struct svc_rqst *rqstp,
+                                           const struct svc_program *progp,
+                                           struct svc_process_info *procinfo);
 
 #define        RPC_MAX_ADDRBUFLEN      (63U)
 
index 3d5dd6b86652bc06bc07b2a1b165dfb85489eca9..69f3b9e015ce7ae4da095f8427bec3071d42dd3d 100644 (file)
@@ -1160,6 +1160,59 @@ svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp)
        return rpc_auth_ok;
 }
 
+__be32
+svc_generic_init_request(struct svc_rqst *rqstp,
+               const struct svc_program *progp,
+               struct svc_process_info *ret)
+{
+       const struct svc_version *versp = NULL; /* compiler food */
+       const struct svc_procedure *procp = NULL;
+
+       if (rqstp->rq_vers >= progp->pg_nvers )
+               goto err_bad_vers;
+         versp = progp->pg_vers[rqstp->rq_vers];
+         if (!versp)
+               goto err_bad_vers;
+
+       /*
+        * Some protocol versions (namely NFSv4) require some form of
+        * congestion control.  (See RFC 7530 section 3.1 paragraph 2)
+        * In other words, UDP is not allowed. We mark those when setting
+        * up the svc_xprt, and verify that here.
+        *
+        * The spec is not very clear about what error should be returned
+        * when someone tries to access a server that is listening on UDP
+        * for lower versions. RPC_PROG_MISMATCH seems to be the closest
+        * fit.
+        */
+       if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
+           !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
+               goto err_bad_vers;
+
+       if (rqstp->rq_proc >= versp->vs_nproc)
+               goto err_bad_proc;
+       rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc];
+       if (!procp)
+               goto err_bad_proc;
+
+       /* Initialize storage for argp and resp */
+       memset(rqstp->rq_argp, 0, procp->pc_argsize);
+       memset(rqstp->rq_resp, 0, procp->pc_ressize);
+
+       /* Bump per-procedure stats counter */
+       versp->vs_count[rqstp->rq_proc]++;
+
+       ret->dispatch = versp->vs_dispatch;
+       return rpc_success;
+err_bad_vers:
+       ret->mismatch.lovers = progp->pg_lovers;
+       ret->mismatch.hivers = progp->pg_hivers;
+       return rpc_prog_mismatch;
+err_bad_proc:
+       return rpc_proc_unavail;
+}
+EXPORT_SYMBOL_GPL(svc_generic_init_request);
+
 /*
  * Common routine for processing the RPC request.
  */
@@ -1167,11 +1220,11 @@ static int
 svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 {
        struct svc_program      *progp;
-       const struct svc_version *versp = NULL; /* compiler food */
        const struct svc_procedure *procp = NULL;
        struct svc_serv         *serv = rqstp->rq_server;
+       struct svc_process_info process;
        __be32                  *statp;
-       u32                     prog, vers, proc;
+       u32                     prog, vers;
        __be32                  auth_stat, rpc_stat;
        int                     auth_res;
        __be32                  *reply_statp;
@@ -1203,8 +1256,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        svc_putnl(resv, 0);             /* ACCEPT */
 
        rqstp->rq_prog = prog = svc_getnl(argv);        /* program number */
-       rqstp->rq_vers = vers = svc_getnl(argv);        /* version number */
-       rqstp->rq_proc = proc = svc_getnl(argv);        /* procedure number */
+       rqstp->rq_vers = svc_getnl(argv);       /* version number */
+       rqstp->rq_proc = svc_getnl(argv);       /* procedure number */
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next)
                if (prog == progp->pg_prog)
@@ -1242,29 +1295,22 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        if (progp == NULL)
                goto err_bad_prog;
 
-       if (vers >= progp->pg_nvers ||
-         !(versp = progp->pg_vers[vers]))
-               goto err_bad_vers;
-
-       /*
-        * Some protocol versions (namely NFSv4) require some form of
-        * congestion control.  (See RFC 7530 section 3.1 paragraph 2)
-        * In other words, UDP is not allowed. We mark those when setting
-        * up the svc_xprt, and verify that here.
-        *
-        * The spec is not very clear about what error should be returned
-        * when someone tries to access a server that is listening on UDP
-        * for lower versions. RPC_PROG_MISMATCH seems to be the closest
-        * fit.
-        */
-       if (versp->vs_need_cong_ctrl && rqstp->rq_xprt &&
-           !test_bit(XPT_CONG_CTRL, &rqstp->rq_xprt->xpt_flags))
+       rpc_stat = progp->pg_init_request(rqstp, progp, &process);
+       switch (rpc_stat) {
+       case rpc_success:
+               break;
+       case rpc_prog_unavail:
+               goto err_bad_prog;
+       case rpc_prog_mismatch:
                goto err_bad_vers;
+       case rpc_proc_unavail:
+               goto err_bad_proc;
+       }
 
-       procp = versp->vs_proc + proc;
-       if (proc >= versp->vs_nproc || !procp->pc_func)
+       procp = rqstp->rq_procinfo;
+       /* Should this check go into the dispatcher? */
+       if (!procp || !procp->pc_func)
                goto err_bad_proc;
-       rqstp->rq_procinfo = procp;
 
        /* Syntactic check complete */
        serv->sv_stats->rpccnt++;
@@ -1274,13 +1320,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        statp = resv->iov_base +resv->iov_len;
        svc_putnl(resv, RPC_SUCCESS);
 
-       /* Bump per-procedure stats counter */
-       versp->vs_count[proc]++;
-
-       /* Initialize storage for argp and resp */
-       memset(rqstp->rq_argp, 0, procp->pc_argsize);
-       memset(rqstp->rq_resp, 0, procp->pc_ressize);
-
        /* un-reserve some of the out-queue now that we have a
         * better idea of reply size
         */
@@ -1288,7 +1327,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
 
        /* Call the function that processes the request. */
-       if (!versp->vs_dispatch) {
+       if (!process.dispatch) {
                /*
                 * Decode arguments
                 * XXX: why do we ignore the return value?
@@ -1317,7 +1356,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                }
        } else {
                dprintk("svc: calling dispatcher\n");
-               if (!versp->vs_dispatch(rqstp, statp)) {
+               if (!process.dispatch(rqstp, statp)) {
                        /* Release reply info */
                        if (procp->pc_release)
                                procp->pc_release(rqstp);
@@ -1386,16 +1425,16 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
 
 err_bad_vers:
        svc_printk(rqstp, "unknown version (%d for prog %d, %s)\n",
-                      vers, prog, progp->pg_name);
+                      rqstp->rq_vers, rqstp->rq_prog, progp->pg_name);
 
        serv->sv_stats->rpcbadfmt++;
        svc_putnl(resv, RPC_PROG_MISMATCH);
-       svc_putnl(resv, progp->pg_lovers);
-       svc_putnl(resv, progp->pg_hivers);
+       svc_putnl(resv, process.mismatch.lovers);
+       svc_putnl(resv, process.mismatch.hivers);
        goto sendit;
 
 err_bad_proc:
-       svc_printk(rqstp, "unknown procedure (%d)\n", proc);
+       svc_printk(rqstp, "unknown procedure (%d)\n", rqstp->rq_proc);
 
        serv->sv_stats->rpcbadfmt++;
        svc_putnl(resv, RPC_PROC_UNAVAIL);