[PATCH] RPC: Make rpc_create_client() probe server for RPC program+version support
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 22 Jun 2005 17:16:20 +0000 (17:16 +0000)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 22 Jun 2005 20:07:04 +0000 (16:07 -0400)
 Ensure that we don't create an RPC client without checking that the server
 does indeed support the RPC program + version that we are trying to set up.

 This enables us to immediately return an error to "mount" if it turns out
 that the server is only supporting NFSv2, when we requested NFSv3 or NFSv4.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/lockd/host.c
fs/lockd/mon.c
include/linux/sunrpc/clnt.h
net/sunrpc/clnt.c
net/sunrpc/pmap_clnt.c

index 90a62f27914c737757937e68dedf5f6abe0e7823..82c77df81c5f1e2ed706d7f4be5206b121dd1454 100644 (file)
@@ -189,6 +189,8 @@ nlm_bind_host(struct nlm_host *host)
                        goto forgetit;
 
                xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
+               xprt->nocong = 1;       /* No congestion control for NLM */
+               xprt->resvport = 1;     /* NLM requires a reserved port */
 
                /* Existing NLM servers accept AUTH_UNIX only */
                clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
@@ -196,8 +198,6 @@ nlm_bind_host(struct nlm_host *host)
                if (IS_ERR(clnt))
                        goto forgetit;
                clnt->cl_autobind = 1;  /* turn on pmap queries */
-               xprt->nocong = 1;       /* No congestion control for NLM */
-               xprt->resvport = 1;     /* NLM requires a reserved port */
 
                host->h_rpcclnt = clnt;
        }
index 81b5e7778d70c88e8bc4359ec5595598a80c9e07..2d144abe84adbe3a62512cb9cc7c3c2c85a935a7 100644 (file)
@@ -115,6 +115,7 @@ nsm_create(void)
        xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
        if (IS_ERR(xprt))
                return (struct rpc_clnt *)xprt;
+       xprt->resvport = 1;     /* NSM requires a reserved port */
 
        clnt = rpc_create_client(xprt, "localhost",
                                &nsm_program, SM_VERSION,
@@ -124,7 +125,6 @@ nsm_create(void)
        clnt->cl_softrtry = 1;
        clnt->cl_chatty   = 1;
        clnt->cl_oneshot  = 1;
-       xprt->resvport = 1;     /* NSM requires a reserved port */
        return clnt;
 
 out_err:
index 2709caf4d1283c43308589824bf468c7e34b8683..d25e80f77ff5f533134b4c72067525b216be8701 100644 (file)
@@ -111,6 +111,9 @@ struct rpc_procinfo {
 struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
                                struct rpc_program *info,
                                u32 version, rpc_authflavor_t authflavor);
+struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname,
+                               struct rpc_program *info,
+                               u32 version, rpc_authflavor_t authflavor);
 struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
 int            rpc_shutdown_client(struct rpc_clnt *);
 int            rpc_destroy_client(struct rpc_clnt *);
@@ -129,6 +132,7 @@ void                rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void           rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void           rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 size_t         rpc_max_payload(struct rpc_clnt *);
+int            rpc_ping(struct rpc_clnt *clnt, int flags);
 
 static __inline__
 int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
index 99515d7727a61fb7bc1788dd2e42fc0ad39bafda..b36797ad8083166c2c0f966ed38f506468794f8d 100644 (file)
@@ -97,7 +97,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
  * made to sleep too long.
  */
 struct rpc_clnt *
-rpc_create_client(struct rpc_xprt *xprt, char *servname,
+rpc_new_client(struct rpc_xprt *xprt, char *servname,
                  struct rpc_program *program, u32 vers,
                  rpc_authflavor_t flavor)
 {
@@ -182,6 +182,36 @@ out_err:
        return ERR_PTR(err);
 }
 
+/**
+ * Create an RPC client
+ * @xprt - pointer to xprt struct
+ * @servname - name of server
+ * @info - rpc_program
+ * @version - rpc_program version
+ * @authflavor - rpc_auth flavour to use
+ *
+ * Creates an RPC client structure, then pings the server in order to
+ * determine if it is up, and if it supports this program and version.
+ *
+ * This function should never be called by asynchronous tasks such as
+ * the portmapper.
+ */
+struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
+               struct rpc_program *info, u32 version, rpc_authflavor_t authflavor)
+{
+       struct rpc_clnt *clnt;
+       int err;
+       
+       clnt = rpc_new_client(xprt, servname, info, version, authflavor);
+       if (IS_ERR(clnt))
+               return clnt;
+       err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
+       if (err == 0)
+               return clnt;
+       rpc_shutdown_client(clnt);
+       return ERR_PTR(err);
+}
+
 /*
  * This function clones the RPC client structure. It allows us to share the
  * same transport while varying parameters such as the authentication
@@ -1086,3 +1116,30 @@ out_overflow:
        printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__);
        goto out_retry;
 }
+
+static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)
+{
+       return 0;
+}
+
+static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj)
+{
+       return 0;
+}
+
+static struct rpc_procinfo rpcproc_null = {
+       .p_encode = rpcproc_encode_null,
+       .p_decode = rpcproc_decode_null,
+};
+
+int rpc_ping(struct rpc_clnt *clnt, int flags)
+{
+       struct rpc_message msg = {
+               .rpc_proc = &rpcproc_null,
+       };
+       int err;
+       msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);
+       err = rpc_call_sync(clnt, &msg, flags);
+       put_rpccred(msg.rpc_cred);
+       return err;
+}
index 97c420ff1ee004afaf8dc35b6173df37dab9290b..df4d84c9020def6432a97ea89a39d9f374cd1578 100644 (file)
@@ -207,7 +207,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto)
        xprt->addr.sin_port = htons(RPC_PMAP_PORT);
 
        /* printk("pmap: create clnt\n"); */
-       clnt = rpc_create_client(xprt, hostname,
+       clnt = rpc_new_client(xprt, hostname,
                                &pmap_program, RPC_PMAP_VERSION,
                                RPC_AUTH_UNIX);
        if (!IS_ERR(clnt)) {