1 /* 2 * linux/fs/nfs/callback.c 3 * 4 * Copyright (C) 2004 Trond Myklebust 5 * 6 * NFSv4 callback handling 7 */ 8 9 #include <linux/completion.h> 10 #include <linux/ip.h> 11 #include <linux/module.h> 12 #include <linux/sunrpc/svc.h> 13 #include <linux/sunrpc/svcsock.h> 14 #include <linux/nfs_fs.h> 15 #include <linux/mutex.h> 16 #include <linux/freezer.h> 17 #include <linux/kthread.h> 18 #include <linux/sunrpc/svcauth_gss.h> 19 #include <linux/sunrpc/bc_xprt.h> 20 21 #include <net/inet_sock.h> 22 23 #include "nfs4_fs.h" 24 #include "callback.h" 25 #include "internal.h" 26 27 #define NFSDBG_FACILITY NFSDBG_CALLBACK 28 29 struct nfs_callback_data { 30 unsigned int users; 31 struct svc_serv *serv; 32 struct svc_rqst *rqst; 33 struct task_struct *task; 34 }; 35 36 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; 37 static DEFINE_MUTEX(nfs_callback_mutex); 38 static struct svc_program nfs4_callback_program; 39 40 unsigned int nfs_callback_set_tcpport; 41 unsigned short nfs_callback_tcpport; 42 unsigned short nfs_callback_tcpport6; 43 #define NFS_CALLBACK_MAXPORTNR (65535U) 44 45 static int param_set_portnr(const char *val, const struct kernel_param *kp) 46 { 47 unsigned long num; 48 int ret; 49 50 if (!val) 51 return -EINVAL; 52 ret = strict_strtoul(val, 0, &num); 53 if (ret == -EINVAL || num > NFS_CALLBACK_MAXPORTNR) 54 return -EINVAL; 55 *((unsigned int *)kp->arg) = num; 56 return 0; 57 } 58 static struct kernel_param_ops param_ops_portnr = { 59 .set = param_set_portnr, 60 .get = param_get_uint, 61 }; 62 #define param_check_portnr(name, p) __param_check(name, p, unsigned int); 63 64 module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); 65 66 /* 67 * This is the NFSv4 callback kernel thread. 68 */ 69 static int 70 nfs4_callback_svc(void *vrqstp) 71 { 72 int err, preverr = 0; 73 struct svc_rqst *rqstp = vrqstp; 74 75 set_freezable(); 76 77 while (!kthread_should_stop()) { 78 /* 79 * Listen for a request on the socket 80 */ 81 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); 82 if (err == -EAGAIN || err == -EINTR) { 83 preverr = err; 84 continue; 85 } 86 if (err < 0) { 87 if (err != preverr) { 88 printk(KERN_WARNING "%s: unexpected error " 89 "from svc_recv (%d)\n", __func__, err); 90 preverr = err; 91 } 92 schedule_timeout_uninterruptible(HZ); 93 continue; 94 } 95 preverr = err; 96 svc_process(rqstp); 97 } 98 return 0; 99 } 100 101 /* 102 * Prepare to bring up the NFSv4 callback service 103 */ 104 struct svc_rqst * 105 nfs4_callback_up(struct svc_serv *serv) 106 { 107 int ret; 108 109 ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET, 110 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); 111 if (ret <= 0) 112 goto out_err; 113 nfs_callback_tcpport = ret; 114 dprintk("NFS: Callback listener port = %u (af %u)\n", 115 nfs_callback_tcpport, PF_INET); 116 117 ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6, 118 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); 119 if (ret > 0) { 120 nfs_callback_tcpport6 = ret; 121 dprintk("NFS: Callback listener port = %u (af %u)\n", 122 nfs_callback_tcpport6, PF_INET6); 123 } else if (ret == -EAFNOSUPPORT) 124 ret = 0; 125 else 126 goto out_err; 127 128 return svc_prepare_thread(serv, &serv->sv_pools[0]); 129 130 out_err: 131 if (ret == 0) 132 ret = -ENOMEM; 133 return ERR_PTR(ret); 134 } 135 136 #if defined(CONFIG_NFS_V4_1) 137 /* 138 * The callback service for NFSv4.1 callbacks 139 */ 140 static int 141 nfs41_callback_svc(void *vrqstp) 142 { 143 struct svc_rqst *rqstp = vrqstp; 144 struct svc_serv *serv = rqstp->rq_server; 145 struct rpc_rqst *req; 146 int error; 147 DEFINE_WAIT(wq); 148 149 set_freezable(); 150 151 while (!kthread_should_stop()) { 152 prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); 153 spin_lock_bh(&serv->sv_cb_lock); 154 if (!list_empty(&serv->sv_cb_list)) { 155 req = list_first_entry(&serv->sv_cb_list, 156 struct rpc_rqst, rq_bc_list); 157 list_del(&req->rq_bc_list); 158 spin_unlock_bh(&serv->sv_cb_lock); 159 dprintk("Invoking bc_svc_process()\n"); 160 error = bc_svc_process(serv, req, rqstp); 161 dprintk("bc_svc_process() returned w/ error code= %d\n", 162 error); 163 } else { 164 spin_unlock_bh(&serv->sv_cb_lock); 165 schedule(); 166 } 167 finish_wait(&serv->sv_cb_waitq, &wq); 168 } 169 return 0; 170 } 171 172 /* 173 * Bring up the NFSv4.1 callback service 174 */ 175 struct svc_rqst * 176 nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) 177 { 178 struct svc_rqst *rqstp; 179 int ret; 180 181 /* 182 * Create an svc_sock for the back channel service that shares the 183 * fore channel connection. 184 * Returns the input port (0) and sets the svc_serv bc_xprt on success 185 */ 186 ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0, 187 SVC_SOCK_ANONYMOUS); 188 if (ret < 0) { 189 rqstp = ERR_PTR(ret); 190 goto out; 191 } 192 193 /* 194 * Save the svc_serv in the transport so that it can 195 * be referenced when the session backchannel is initialized 196 */ 197 xprt->bc_serv = serv; 198 199 INIT_LIST_HEAD(&serv->sv_cb_list); 200 spin_lock_init(&serv->sv_cb_lock); 201 init_waitqueue_head(&serv->sv_cb_waitq); 202 rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); 203 if (IS_ERR(rqstp)) { 204 svc_xprt_put(serv->sv_bc_xprt); 205 serv->sv_bc_xprt = NULL; 206 } 207 out: 208 dprintk("--> %s return %ld\n", __func__, 209 IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0); 210 return rqstp; 211 } 212 213 static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, 214 struct svc_serv *serv, struct rpc_xprt *xprt, 215 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) 216 { 217 if (minorversion) { 218 *rqstpp = nfs41_callback_up(serv, xprt); 219 *callback_svc = nfs41_callback_svc; 220 } 221 return minorversion; 222 } 223 224 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, 225 struct nfs_callback_data *cb_info) 226 { 227 if (minorversion) 228 xprt->bc_serv = cb_info->serv; 229 } 230 #else 231 static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, 232 struct svc_serv *serv, struct rpc_xprt *xprt, 233 struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) 234 { 235 return 0; 236 } 237 238 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, 239 struct nfs_callback_data *cb_info) 240 { 241 } 242 #endif /* CONFIG_NFS_V4_1 */ 243 244 /* 245 * Bring up the callback thread if it is not already up. 246 */ 247 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) 248 { 249 struct svc_serv *serv = NULL; 250 struct svc_rqst *rqstp; 251 int (*callback_svc)(void *vrqstp); 252 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 253 char svc_name[12]; 254 int ret = 0; 255 int minorversion_setup; 256 257 mutex_lock(&nfs_callback_mutex); 258 if (cb_info->users++ || cb_info->task != NULL) { 259 nfs_callback_bc_serv(minorversion, xprt, cb_info); 260 goto out; 261 } 262 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); 263 if (!serv) { 264 ret = -ENOMEM; 265 goto out_err; 266 } 267 268 minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, 269 serv, xprt, &rqstp, &callback_svc); 270 if (!minorversion_setup) { 271 /* v4.0 callback setup */ 272 rqstp = nfs4_callback_up(serv); 273 callback_svc = nfs4_callback_svc; 274 } 275 276 if (IS_ERR(rqstp)) { 277 ret = PTR_ERR(rqstp); 278 goto out_err; 279 } 280 281 svc_sock_update_bufs(serv); 282 283 sprintf(svc_name, "nfsv4.%u-svc", minorversion); 284 cb_info->serv = serv; 285 cb_info->rqst = rqstp; 286 cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); 287 if (IS_ERR(cb_info->task)) { 288 ret = PTR_ERR(cb_info->task); 289 svc_exit_thread(cb_info->rqst); 290 cb_info->rqst = NULL; 291 cb_info->task = NULL; 292 goto out_err; 293 } 294 out: 295 /* 296 * svc_create creates the svc_serv with sv_nrthreads == 1, and then 297 * svc_prepare_thread increments that. So we need to call svc_destroy 298 * on both success and failure so that the refcount is 1 when the 299 * thread exits. 300 */ 301 if (serv) 302 svc_destroy(serv); 303 mutex_unlock(&nfs_callback_mutex); 304 return ret; 305 out_err: 306 dprintk("NFS: Couldn't create callback socket or server thread; " 307 "err = %d\n", ret); 308 cb_info->users--; 309 goto out; 310 } 311 312 /* 313 * Kill the callback thread if it's no longer being used. 314 */ 315 void nfs_callback_down(int minorversion) 316 { 317 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 318 319 mutex_lock(&nfs_callback_mutex); 320 cb_info->users--; 321 if (cb_info->users == 0 && cb_info->task != NULL) { 322 kthread_stop(cb_info->task); 323 svc_exit_thread(cb_info->rqst); 324 cb_info->serv = NULL; 325 cb_info->rqst = NULL; 326 cb_info->task = NULL; 327 } 328 mutex_unlock(&nfs_callback_mutex); 329 } 330 331 /* Boolean check of RPC_AUTH_GSS principal */ 332 int 333 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) 334 { 335 struct rpc_clnt *r = clp->cl_rpcclient; 336 char *p = svc_gss_principal(rqstp); 337 338 if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) 339 return 1; 340 341 /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ 342 if (clp->cl_minorversion != 0) 343 return 0; 344 /* 345 * It might just be a normal user principal, in which case 346 * userspace won't bother to tell us the name at all. 347 */ 348 if (p == NULL) 349 return 0; 350 351 /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ 352 353 if (memcmp(p, "nfs@", 4) != 0) 354 return 0; 355 p += 4; 356 if (strcmp(p, r->cl_server) != 0) 357 return 0; 358 return 1; 359 } 360 361 /* 362 * pg_authenticate method for nfsv4 callback threads. 363 * 364 * The authflavor has been negotiated, so an incorrect flavor is a server 365 * bug. Drop packets with incorrect authflavor. 366 * 367 * All other checking done after NFS decoding where the nfs_client can be 368 * found in nfs4_callback_compound 369 */ 370 static int nfs_callback_authenticate(struct svc_rqst *rqstp) 371 { 372 switch (rqstp->rq_authop->flavour) { 373 case RPC_AUTH_NULL: 374 if (rqstp->rq_proc != CB_NULL) 375 return SVC_DROP; 376 break; 377 case RPC_AUTH_GSS: 378 /* No RPC_AUTH_GSS support yet in NFSv4.1 */ 379 if (svc_is_backchannel(rqstp)) 380 return SVC_DROP; 381 } 382 return SVC_OK; 383 } 384 385 /* 386 * Define NFS4 callback program 387 */ 388 static struct svc_version *nfs4_callback_version[] = { 389 [1] = &nfs4_callback_version1, 390 [4] = &nfs4_callback_version4, 391 }; 392 393 static struct svc_stat nfs4_callback_stats; 394 395 static struct svc_program nfs4_callback_program = { 396 .pg_prog = NFS4_CALLBACK, /* RPC service number */ 397 .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */ 398 .pg_vers = nfs4_callback_version, /* version table */ 399 .pg_name = "NFSv4 callback", /* service name */ 400 .pg_class = "nfs", /* authentication class */ 401 .pg_stats = &nfs4_callback_stats, 402 .pg_authenticate = nfs_callback_authenticate, 403 }; 404