0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/completion.h>
0011 #include <linux/ip.h>
0012 #include <linux/module.h>
0013 #include <linux/sched/signal.h>
0014 #include <linux/sunrpc/svc.h>
0015 #include <linux/sunrpc/svcsock.h>
0016 #include <linux/nfs_fs.h>
0017 #include <linux/errno.h>
0018 #include <linux/mutex.h>
0019 #include <linux/freezer.h>
0020 #include <linux/sunrpc/svcauth_gss.h>
0021 #include <linux/sunrpc/bc_xprt.h>
0022
0023 #include <net/inet_sock.h>
0024
0025 #include "nfs4_fs.h"
0026 #include "callback.h"
0027 #include "internal.h"
0028 #include "netns.h"
0029
0030 #define NFSDBG_FACILITY NFSDBG_CALLBACK
0031
0032 struct nfs_callback_data {
0033 unsigned int users;
0034 struct svc_serv *serv;
0035 };
0036
0037 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
0038 static DEFINE_MUTEX(nfs_callback_mutex);
0039 static struct svc_program nfs4_callback_program;
0040
0041 static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
0042 {
0043 const struct cred *cred = current_cred();
0044 int ret;
0045 struct nfs_net *nn = net_generic(net, nfs_net_id);
0046
0047 ret = svc_xprt_create(serv, "tcp", net, PF_INET,
0048 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
0049 cred);
0050 if (ret <= 0)
0051 goto out_err;
0052 nn->nfs_callback_tcpport = ret;
0053 dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
0054 nn->nfs_callback_tcpport, PF_INET, net->ns.inum);
0055
0056 ret = svc_xprt_create(serv, "tcp", net, PF_INET6,
0057 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
0058 cred);
0059 if (ret > 0) {
0060 nn->nfs_callback_tcpport6 = ret;
0061 dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
0062 nn->nfs_callback_tcpport6, PF_INET6, net->ns.inum);
0063 } else if (ret != -EAFNOSUPPORT)
0064 goto out_err;
0065 return 0;
0066
0067 out_err:
0068 return (ret) ? ret : -ENOMEM;
0069 }
0070
0071
0072
0073
0074 static int
0075 nfs4_callback_svc(void *vrqstp)
0076 {
0077 int err;
0078 struct svc_rqst *rqstp = vrqstp;
0079
0080 set_freezable();
0081
0082 while (!kthread_freezable_should_stop(NULL)) {
0083
0084 if (signal_pending(current))
0085 flush_signals(current);
0086
0087
0088
0089 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
0090 if (err == -EAGAIN || err == -EINTR)
0091 continue;
0092 svc_process(rqstp);
0093 }
0094
0095 svc_exit_thread(rqstp);
0096 return 0;
0097 }
0098
0099 #if defined(CONFIG_NFS_V4_1)
0100
0101
0102
0103 static int
0104 nfs41_callback_svc(void *vrqstp)
0105 {
0106 struct svc_rqst *rqstp = vrqstp;
0107 struct svc_serv *serv = rqstp->rq_server;
0108 struct rpc_rqst *req;
0109 int error;
0110 DEFINE_WAIT(wq);
0111
0112 set_freezable();
0113
0114 while (!kthread_freezable_should_stop(NULL)) {
0115
0116 if (signal_pending(current))
0117 flush_signals(current);
0118
0119 prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
0120 spin_lock_bh(&serv->sv_cb_lock);
0121 if (!list_empty(&serv->sv_cb_list)) {
0122 req = list_first_entry(&serv->sv_cb_list,
0123 struct rpc_rqst, rq_bc_list);
0124 list_del(&req->rq_bc_list);
0125 spin_unlock_bh(&serv->sv_cb_lock);
0126 finish_wait(&serv->sv_cb_waitq, &wq);
0127 dprintk("Invoking bc_svc_process()\n");
0128 error = bc_svc_process(serv, req, rqstp);
0129 dprintk("bc_svc_process() returned w/ error code= %d\n",
0130 error);
0131 } else {
0132 spin_unlock_bh(&serv->sv_cb_lock);
0133 if (!kthread_should_stop())
0134 schedule();
0135 finish_wait(&serv->sv_cb_waitq, &wq);
0136 }
0137 }
0138
0139 svc_exit_thread(rqstp);
0140 return 0;
0141 }
0142
0143 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
0144 struct svc_serv *serv)
0145 {
0146 if (minorversion)
0147
0148
0149
0150
0151 xprt->bc_serv = serv;
0152 }
0153 #else
0154 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
0155 struct svc_serv *serv)
0156 {
0157 }
0158 #endif
0159
0160 static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
0161 struct svc_serv *serv)
0162 {
0163 int nrservs = nfs_callback_nr_threads;
0164 int ret;
0165
0166 nfs_callback_bc_serv(minorversion, xprt, serv);
0167
0168 if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS)
0169 nrservs = NFS4_MIN_NR_CALLBACK_THREADS;
0170
0171 if (serv->sv_nrthreads == nrservs)
0172 return 0;
0173
0174 ret = svc_set_num_threads(serv, NULL, nrservs);
0175 if (ret) {
0176 svc_set_num_threads(serv, NULL, 0);
0177 return ret;
0178 }
0179 dprintk("nfs_callback_up: service started\n");
0180 return 0;
0181 }
0182
0183 static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
0184 {
0185 struct nfs_net *nn = net_generic(net, nfs_net_id);
0186
0187 if (--nn->cb_users[minorversion])
0188 return;
0189
0190 dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum);
0191 svc_xprt_destroy_all(serv, net);
0192 }
0193
0194 static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
0195 struct net *net, struct rpc_xprt *xprt)
0196 {
0197 struct nfs_net *nn = net_generic(net, nfs_net_id);
0198 int ret;
0199
0200 if (nn->cb_users[minorversion]++)
0201 return 0;
0202
0203 dprintk("NFS: create per-net callback data; net=%x\n", net->ns.inum);
0204
0205 ret = svc_bind(serv, net);
0206 if (ret < 0) {
0207 printk(KERN_WARNING "NFS: bind callback service failed\n");
0208 goto err_bind;
0209 }
0210
0211 ret = 0;
0212 if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
0213 ret = nfs4_callback_up_net(serv, net);
0214 else if (xprt->ops->bc_setup)
0215 set_bc_enabled(serv);
0216 else
0217 ret = -EPROTONOSUPPORT;
0218
0219 if (ret < 0) {
0220 printk(KERN_ERR "NFS: callback service start failed\n");
0221 goto err_socks;
0222 }
0223 return 0;
0224
0225 err_socks:
0226 svc_rpcb_cleanup(serv, net);
0227 err_bind:
0228 nn->cb_users[minorversion]--;
0229 dprintk("NFS: Couldn't create callback socket: err = %d; "
0230 "net = %x\n", ret, net->ns.inum);
0231 return ret;
0232 }
0233
0234 static struct svc_serv *nfs_callback_create_svc(int minorversion)
0235 {
0236 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
0237 int (*threadfn)(void *data);
0238 struct svc_serv *serv;
0239
0240
0241
0242
0243 if (cb_info->serv)
0244 return svc_get(cb_info->serv);
0245
0246
0247
0248
0249
0250 if (cb_info->users)
0251 printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
0252 cb_info->users);
0253
0254 threadfn = nfs4_callback_svc;
0255 #if defined(CONFIG_NFS_V4_1)
0256 if (minorversion)
0257 threadfn = nfs41_callback_svc;
0258 #else
0259 if (minorversion)
0260 return ERR_PTR(-ENOTSUPP);
0261 #endif
0262 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
0263 threadfn);
0264 if (!serv) {
0265 printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
0266 return ERR_PTR(-ENOMEM);
0267 }
0268 cb_info->serv = serv;
0269
0270
0271
0272 serv->sv_maxconn = 1024;
0273 dprintk("nfs_callback_create_svc: service created\n");
0274 return serv;
0275 }
0276
0277
0278
0279
0280 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
0281 {
0282 struct svc_serv *serv;
0283 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
0284 int ret;
0285 struct net *net = xprt->xprt_net;
0286
0287 mutex_lock(&nfs_callback_mutex);
0288
0289 serv = nfs_callback_create_svc(minorversion);
0290 if (IS_ERR(serv)) {
0291 ret = PTR_ERR(serv);
0292 goto err_create;
0293 }
0294
0295 ret = nfs_callback_up_net(minorversion, serv, net, xprt);
0296 if (ret < 0)
0297 goto err_net;
0298
0299 ret = nfs_callback_start_svc(minorversion, xprt, serv);
0300 if (ret < 0)
0301 goto err_start;
0302
0303 cb_info->users++;
0304 err_net:
0305 if (!cb_info->users)
0306 cb_info->serv = NULL;
0307 svc_put(serv);
0308 err_create:
0309 mutex_unlock(&nfs_callback_mutex);
0310 return ret;
0311
0312 err_start:
0313 nfs_callback_down_net(minorversion, serv, net);
0314 dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
0315 goto err_net;
0316 }
0317
0318
0319
0320
0321 void nfs_callback_down(int minorversion, struct net *net)
0322 {
0323 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
0324 struct svc_serv *serv;
0325
0326 mutex_lock(&nfs_callback_mutex);
0327 serv = cb_info->serv;
0328 nfs_callback_down_net(minorversion, serv, net);
0329 cb_info->users--;
0330 if (cb_info->users == 0) {
0331 svc_get(serv);
0332 svc_set_num_threads(serv, NULL, 0);
0333 svc_put(serv);
0334 dprintk("nfs_callback_down: service destroyed\n");
0335 cb_info->serv = NULL;
0336 }
0337 mutex_unlock(&nfs_callback_mutex);
0338 }
0339
0340
0341 int
0342 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
0343 {
0344 char *p = rqstp->rq_cred.cr_principal;
0345
0346 if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
0347 return 1;
0348
0349
0350 if (clp->cl_minorversion != 0)
0351 return 0;
0352
0353
0354
0355
0356 if (p == NULL)
0357 return 0;
0358
0359
0360
0361
0362
0363 if (clp->cl_acceptor)
0364 return !strcmp(p, clp->cl_acceptor);
0365
0366
0367
0368
0369
0370
0371
0372
0373 if (memcmp(p, "nfs@", 4) != 0)
0374 return 0;
0375 p += 4;
0376 if (strcmp(p, clp->cl_hostname) != 0)
0377 return 0;
0378 return 1;
0379 }
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
0391 {
0392 rqstp->rq_auth_stat = rpc_autherr_badcred;
0393
0394 switch (rqstp->rq_authop->flavour) {
0395 case RPC_AUTH_NULL:
0396 if (rqstp->rq_proc != CB_NULL)
0397 return SVC_DENIED;
0398 break;
0399 case RPC_AUTH_GSS:
0400
0401 if (svc_is_backchannel(rqstp))
0402 return SVC_DENIED;
0403 }
0404
0405 rqstp->rq_auth_stat = rpc_auth_ok;
0406 return SVC_OK;
0407 }
0408
0409
0410
0411
0412 static const struct svc_version *nfs4_callback_version[] = {
0413 [1] = &nfs4_callback_version1,
0414 [4] = &nfs4_callback_version4,
0415 };
0416
0417 static struct svc_stat nfs4_callback_stats;
0418
0419 static struct svc_program nfs4_callback_program = {
0420 .pg_prog = NFS4_CALLBACK,
0421 .pg_nvers = ARRAY_SIZE(nfs4_callback_version),
0422 .pg_vers = nfs4_callback_version,
0423 .pg_name = "NFSv4 callback",
0424 .pg_class = "nfs",
0425 .pg_stats = &nfs4_callback_stats,
0426 .pg_authenticate = nfs_callback_authenticate,
0427 .pg_init_request = svc_generic_init_request,
0428 .pg_rpcbind_set = svc_generic_rpcbind_set,
0429 };