diff options
Diffstat (limited to 'fs/nfs/callback.c')
-rw-r--r-- | fs/nfs/callback.c | 83 |
1 files changed, 70 insertions, 13 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 93a8b3bd69e3..199016528fcb 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -16,9 +16,7 @@ | |||
16 | #include <linux/freezer.h> | 16 | #include <linux/freezer.h> |
17 | #include <linux/kthread.h> | 17 | #include <linux/kthread.h> |
18 | #include <linux/sunrpc/svcauth_gss.h> | 18 | #include <linux/sunrpc/svcauth_gss.h> |
19 | #if defined(CONFIG_NFS_V4_1) | ||
20 | #include <linux/sunrpc/bc_xprt.h> | 19 | #include <linux/sunrpc/bc_xprt.h> |
21 | #endif | ||
22 | 20 | ||
23 | #include <net/inet_sock.h> | 21 | #include <net/inet_sock.h> |
24 | 22 | ||
@@ -137,6 +135,33 @@ out_err: | |||
137 | 135 | ||
138 | #if defined(CONFIG_NFS_V4_1) | 136 | #if defined(CONFIG_NFS_V4_1) |
139 | /* | 137 | /* |
138 | * * CB_SEQUENCE operations will fail until the callback sessionid is set. | ||
139 | * */ | ||
140 | int nfs4_set_callback_sessionid(struct nfs_client *clp) | ||
141 | { | ||
142 | struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv; | ||
143 | struct nfs4_sessionid *bc_sid; | ||
144 | |||
145 | if (!serv->sv_bc_xprt) | ||
146 | return -EINVAL; | ||
147 | |||
148 | /* on success freed in xprt_free */ | ||
149 | bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL); | ||
150 | if (!bc_sid) | ||
151 | return -ENOMEM; | ||
152 | memcpy(bc_sid->data, &clp->cl_session->sess_id.data, | ||
153 | NFS4_MAX_SESSIONID_LEN); | ||
154 | spin_lock_bh(&serv->sv_cb_lock); | ||
155 | serv->sv_bc_xprt->xpt_bc_sid = bc_sid; | ||
156 | spin_unlock_bh(&serv->sv_cb_lock); | ||
157 | dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__, | ||
158 | ((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1], | ||
159 | ((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3], | ||
160 | serv->sv_bc_xprt); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* | ||
140 | * The callback service for NFSv4.1 callbacks | 165 | * The callback service for NFSv4.1 callbacks |
141 | */ | 166 | */ |
142 | static int | 167 | static int |
@@ -177,30 +202,38 @@ nfs41_callback_svc(void *vrqstp) | |||
177 | struct svc_rqst * | 202 | struct svc_rqst * |
178 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | 203 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) |
179 | { | 204 | { |
180 | struct svc_xprt *bc_xprt; | 205 | struct svc_rqst *rqstp; |
181 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | 206 | int ret; |
182 | 207 | ||
183 | dprintk("--> %s\n", __func__); | 208 | /* |
184 | /* Create a svc_sock for the service */ | 209 | * Create an svc_sock for the back channel service that shares the |
185 | bc_xprt = svc_sock_create(serv, xprt->prot); | 210 | * fore channel connection. |
186 | if (!bc_xprt) | 211 | * Returns the input port (0) and sets the svc_serv bc_xprt on success |
212 | */ | ||
213 | ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0, | ||
214 | SVC_SOCK_ANONYMOUS); | ||
215 | if (ret < 0) { | ||
216 | rqstp = ERR_PTR(ret); | ||
187 | goto out; | 217 | goto out; |
218 | } | ||
188 | 219 | ||
189 | /* | 220 | /* |
190 | * Save the svc_serv in the transport so that it can | 221 | * Save the svc_serv in the transport so that it can |
191 | * be referenced when the session backchannel is initialized | 222 | * be referenced when the session backchannel is initialized |
192 | */ | 223 | */ |
193 | serv->bc_xprt = bc_xprt; | ||
194 | xprt->bc_serv = serv; | 224 | xprt->bc_serv = serv; |
195 | 225 | ||
196 | INIT_LIST_HEAD(&serv->sv_cb_list); | 226 | INIT_LIST_HEAD(&serv->sv_cb_list); |
197 | spin_lock_init(&serv->sv_cb_lock); | 227 | spin_lock_init(&serv->sv_cb_lock); |
198 | init_waitqueue_head(&serv->sv_cb_waitq); | 228 | init_waitqueue_head(&serv->sv_cb_waitq); |
199 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | 229 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
200 | if (IS_ERR(rqstp)) | 230 | if (IS_ERR(rqstp)) { |
201 | svc_sock_destroy(bc_xprt); | 231 | svc_xprt_put(serv->sv_bc_xprt); |
232 | serv->sv_bc_xprt = NULL; | ||
233 | } | ||
202 | out: | 234 | out: |
203 | dprintk("--> %s return %p\n", __func__, rqstp); | 235 | dprintk("--> %s return %ld\n", __func__, |
236 | IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0); | ||
204 | return rqstp; | 237 | return rqstp; |
205 | } | 238 | } |
206 | 239 | ||
@@ -233,6 +266,10 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | |||
233 | struct nfs_callback_data *cb_info) | 266 | struct nfs_callback_data *cb_info) |
234 | { | 267 | { |
235 | } | 268 | } |
269 | int nfs4_set_callback_sessionid(struct nfs_client *clp) | ||
270 | { | ||
271 | return 0; | ||
272 | } | ||
236 | #endif /* CONFIG_NFS_V4_1 */ | 273 | #endif /* CONFIG_NFS_V4_1 */ |
237 | 274 | ||
238 | /* | 275 | /* |
@@ -328,6 +365,9 @@ static int check_gss_callback_principal(struct nfs_client *clp, | |||
328 | struct rpc_clnt *r = clp->cl_rpcclient; | 365 | struct rpc_clnt *r = clp->cl_rpcclient; |
329 | char *p = svc_gss_principal(rqstp); | 366 | char *p = svc_gss_principal(rqstp); |
330 | 367 | ||
368 | /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ | ||
369 | if (clp->cl_minorversion != 0) | ||
370 | return SVC_DROP; | ||
331 | /* | 371 | /* |
332 | * It might just be a normal user principal, in which case | 372 | * It might just be a normal user principal, in which case |
333 | * userspace won't bother to tell us the name at all. | 373 | * userspace won't bother to tell us the name at all. |
@@ -345,6 +385,23 @@ static int check_gss_callback_principal(struct nfs_client *clp, | |||
345 | return SVC_OK; | 385 | return SVC_OK; |
346 | } | 386 | } |
347 | 387 | ||
388 | /* pg_authenticate method helper */ | ||
389 | static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp) | ||
390 | { | ||
391 | struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp); | ||
392 | int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0; | ||
393 | |||
394 | dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc); | ||
395 | if (svc_is_backchannel(rqstp)) | ||
396 | /* Sessionid (usually) set after CB_NULL ping */ | ||
397 | return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid, | ||
398 | is_cb_compound); | ||
399 | else | ||
400 | /* No callback identifier in pg_authenticate */ | ||
401 | return nfs4_find_client_no_ident(svc_addr(rqstp)); | ||
402 | } | ||
403 | |||
404 | /* pg_authenticate method for nfsv4 callback threads. */ | ||
348 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 405 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
349 | { | 406 | { |
350 | struct nfs_client *clp; | 407 | struct nfs_client *clp; |
@@ -352,7 +409,7 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp) | |||
352 | int ret = SVC_OK; | 409 | int ret = SVC_OK; |
353 | 410 | ||
354 | /* Don't talk to strangers */ | 411 | /* Don't talk to strangers */ |
355 | clp = nfs_find_client(svc_addr(rqstp), 4); | 412 | clp = nfs_cb_find_client(rqstp); |
356 | if (clp == NULL) | 413 | if (clp == NULL) |
357 | return SVC_DROP; | 414 | return SVC_DROP; |
358 | 415 | ||