aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-22 13:16:20 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-22 16:07:04 -0400
commit5ee0ed7d3ab620a764740fb018f469d45f561931 (patch)
tree9b6a938fe521815afd3cfb42e2023b443bb05d28
parent5b616f5d596c0b056129f8aeafbc08409b3cd050 (diff)
[PATCH] RPC: Make rpc_create_client() probe server for RPC program+version support
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>
-rw-r--r--fs/lockd/host.c4
-rw-r--r--fs/lockd/mon.c2
-rw-r--r--include/linux/sunrpc/clnt.h4
-rw-r--r--net/sunrpc/clnt.c59
-rw-r--r--net/sunrpc/pmap_clnt.c2
5 files changed, 66 insertions, 5 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 90a62f27914c..82c77df81c5f 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -189,6 +189,8 @@ nlm_bind_host(struct nlm_host *host)
189 goto forgetit; 189 goto forgetit;
190 190
191 xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); 191 xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
192 xprt->nocong = 1; /* No congestion control for NLM */
193 xprt->resvport = 1; /* NLM requires a reserved port */
192 194
193 /* Existing NLM servers accept AUTH_UNIX only */ 195 /* Existing NLM servers accept AUTH_UNIX only */
194 clnt = rpc_create_client(xprt, host->h_name, &nlm_program, 196 clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
@@ -196,8 +198,6 @@ nlm_bind_host(struct nlm_host *host)
196 if (IS_ERR(clnt)) 198 if (IS_ERR(clnt))
197 goto forgetit; 199 goto forgetit;
198 clnt->cl_autobind = 1; /* turn on pmap queries */ 200 clnt->cl_autobind = 1; /* turn on pmap queries */
199 xprt->nocong = 1; /* No congestion control for NLM */
200 xprt->resvport = 1; /* NLM requires a reserved port */
201 201
202 host->h_rpcclnt = clnt; 202 host->h_rpcclnt = clnt;
203 } 203 }
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 81b5e7778d70..2d144abe84ad 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -115,6 +115,7 @@ nsm_create(void)
115 xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); 115 xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
116 if (IS_ERR(xprt)) 116 if (IS_ERR(xprt))
117 return (struct rpc_clnt *)xprt; 117 return (struct rpc_clnt *)xprt;
118 xprt->resvport = 1; /* NSM requires a reserved port */
118 119
119 clnt = rpc_create_client(xprt, "localhost", 120 clnt = rpc_create_client(xprt, "localhost",
120 &nsm_program, SM_VERSION, 121 &nsm_program, SM_VERSION,
@@ -124,7 +125,6 @@ nsm_create(void)
124 clnt->cl_softrtry = 1; 125 clnt->cl_softrtry = 1;
125 clnt->cl_chatty = 1; 126 clnt->cl_chatty = 1;
126 clnt->cl_oneshot = 1; 127 clnt->cl_oneshot = 1;
127 xprt->resvport = 1; /* NSM requires a reserved port */
128 return clnt; 128 return clnt;
129 129
130out_err: 130out_err:
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 2709caf4d128..d25e80f77ff5 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -111,6 +111,9 @@ struct rpc_procinfo {
111struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, 111struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
112 struct rpc_program *info, 112 struct rpc_program *info,
113 u32 version, rpc_authflavor_t authflavor); 113 u32 version, rpc_authflavor_t authflavor);
114struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname,
115 struct rpc_program *info,
116 u32 version, rpc_authflavor_t authflavor);
114struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); 117struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
115int rpc_shutdown_client(struct rpc_clnt *); 118int rpc_shutdown_client(struct rpc_clnt *);
116int rpc_destroy_client(struct rpc_clnt *); 119int rpc_destroy_client(struct rpc_clnt *);
@@ -129,6 +132,7 @@ void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
129void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); 132void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
130void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); 133void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
131size_t rpc_max_payload(struct rpc_clnt *); 134size_t rpc_max_payload(struct rpc_clnt *);
135int rpc_ping(struct rpc_clnt *clnt, int flags);
132 136
133static __inline__ 137static __inline__
134int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) 138int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 99515d7727a6..b36797ad8083 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -97,7 +97,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
97 * made to sleep too long. 97 * made to sleep too long.
98 */ 98 */
99struct rpc_clnt * 99struct rpc_clnt *
100rpc_create_client(struct rpc_xprt *xprt, char *servname, 100rpc_new_client(struct rpc_xprt *xprt, char *servname,
101 struct rpc_program *program, u32 vers, 101 struct rpc_program *program, u32 vers,
102 rpc_authflavor_t flavor) 102 rpc_authflavor_t flavor)
103{ 103{
@@ -182,6 +182,36 @@ out_err:
182 return ERR_PTR(err); 182 return ERR_PTR(err);
183} 183}
184 184
185/**
186 * Create an RPC client
187 * @xprt - pointer to xprt struct
188 * @servname - name of server
189 * @info - rpc_program
190 * @version - rpc_program version
191 * @authflavor - rpc_auth flavour to use
192 *
193 * Creates an RPC client structure, then pings the server in order to
194 * determine if it is up, and if it supports this program and version.
195 *
196 * This function should never be called by asynchronous tasks such as
197 * the portmapper.
198 */
199struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
200 struct rpc_program *info, u32 version, rpc_authflavor_t authflavor)
201{
202 struct rpc_clnt *clnt;
203 int err;
204
205 clnt = rpc_new_client(xprt, servname, info, version, authflavor);
206 if (IS_ERR(clnt))
207 return clnt;
208 err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
209 if (err == 0)
210 return clnt;
211 rpc_shutdown_client(clnt);
212 return ERR_PTR(err);
213}
214
185/* 215/*
186 * This function clones the RPC client structure. It allows us to share the 216 * This function clones the RPC client structure. It allows us to share the
187 * same transport while varying parameters such as the authentication 217 * same transport while varying parameters such as the authentication
@@ -1086,3 +1116,30 @@ out_overflow:
1086 printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); 1116 printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__);
1087 goto out_retry; 1117 goto out_retry;
1088} 1118}
1119
1120static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)
1121{
1122 return 0;
1123}
1124
1125static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj)
1126{
1127 return 0;
1128}
1129
1130static struct rpc_procinfo rpcproc_null = {
1131 .p_encode = rpcproc_encode_null,
1132 .p_decode = rpcproc_decode_null,
1133};
1134
1135int rpc_ping(struct rpc_clnt *clnt, int flags)
1136{
1137 struct rpc_message msg = {
1138 .rpc_proc = &rpcproc_null,
1139 };
1140 int err;
1141 msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);
1142 err = rpc_call_sync(clnt, &msg, flags);
1143 put_rpccred(msg.rpc_cred);
1144 return err;
1145}
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index 97c420ff1ee0..df4d84c9020d 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -207,7 +207,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto)
207 xprt->addr.sin_port = htons(RPC_PMAP_PORT); 207 xprt->addr.sin_port = htons(RPC_PMAP_PORT);
208 208
209 /* printk("pmap: create clnt\n"); */ 209 /* printk("pmap: create clnt\n"); */
210 clnt = rpc_create_client(xprt, hostname, 210 clnt = rpc_new_client(xprt, hostname,
211 &pmap_program, RPC_PMAP_VERSION, 211 &pmap_program, RPC_PMAP_VERSION,
212 RPC_AUTH_UNIX); 212 RPC_AUTH_UNIX);
213 if (!IS_ERR(clnt)) { 213 if (!IS_ERR(clnt)) {