linux/fs/nfs/callback.c
<<
>>
Prefs
   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/sched/signal.h>
  13#include <linux/sunrpc/svc.h>
  14#include <linux/sunrpc/svcsock.h>
  15#include <linux/nfs_fs.h>
  16#include <linux/errno.h>
  17#include <linux/mutex.h>
  18#include <linux/freezer.h>
  19#include <linux/kthread.h>
  20#include <linux/sunrpc/svcauth_gss.h>
  21#include <linux/sunrpc/bc_xprt.h>
  22
  23#include <net/inet_sock.h>
  24
  25#include "nfs4_fs.h"
  26#include "callback.h"
  27#include "internal.h"
  28#include "netns.h"
  29
  30#define NFSDBG_FACILITY NFSDBG_CALLBACK
  31
  32struct nfs_callback_data {
  33        unsigned int users;
  34        struct svc_serv *serv;
  35};
  36
  37static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
  38static DEFINE_MUTEX(nfs_callback_mutex);
  39static struct svc_program nfs4_callback_program;
  40
  41static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
  42{
  43        int ret;
  44        struct nfs_net *nn = net_generic(net, nfs_net_id);
  45
  46        ret = svc_create_xprt(serv, "tcp", net, PF_INET,
  47                                nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
  48        if (ret <= 0)
  49                goto out_err;
  50        nn->nfs_callback_tcpport = ret;
  51        dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
  52                        nn->nfs_callback_tcpport, PF_INET, net);
  53
  54        ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
  55                                nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
  56        if (ret > 0) {
  57                nn->nfs_callback_tcpport6 = ret;
  58                dprintk("NFS: Callback listener port = %u (af %u, net %p)\n",
  59                                nn->nfs_callback_tcpport6, PF_INET6, net);
  60        } else if (ret != -EAFNOSUPPORT)
  61                goto out_err;
  62        return 0;
  63
  64out_err:
  65        return (ret) ? ret : -ENOMEM;
  66}
  67
  68/*
  69 * This is the NFSv4 callback kernel thread.
  70 */
  71static int
  72nfs4_callback_svc(void *vrqstp)
  73{
  74        int err;
  75        struct svc_rqst *rqstp = vrqstp;
  76
  77        set_freezable();
  78
  79        while (!kthread_freezable_should_stop(NULL)) {
  80
  81                if (signal_pending(current))
  82                        flush_signals(current);
  83                /*
  84                 * Listen for a request on the socket
  85                 */
  86                err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
  87                if (err == -EAGAIN || err == -EINTR)
  88                        continue;
  89                svc_process(rqstp);
  90        }
  91        svc_exit_thread(rqstp);
  92        module_put_and_exit(0);
  93        return 0;
  94}
  95
  96#if defined(CONFIG_NFS_V4_1)
  97/*
  98 * The callback service for NFSv4.1 callbacks
  99 */
 100static int
 101nfs41_callback_svc(void *vrqstp)
 102{
 103        struct svc_rqst *rqstp = vrqstp;
 104        struct svc_serv *serv = rqstp->rq_server;
 105        struct rpc_rqst *req;
 106        int error;
 107        DEFINE_WAIT(wq);
 108
 109        set_freezable();
 110
 111        while (!kthread_freezable_should_stop(NULL)) {
 112
 113                if (signal_pending(current))
 114                        flush_signals(current);
 115
 116                prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
 117                spin_lock_bh(&serv->sv_cb_lock);
 118                if (!list_empty(&serv->sv_cb_list)) {
 119                        req = list_first_entry(&serv->sv_cb_list,
 120                                        struct rpc_rqst, rq_bc_list);
 121                        list_del(&req->rq_bc_list);
 122                        spin_unlock_bh(&serv->sv_cb_lock);
 123                        finish_wait(&serv->sv_cb_waitq, &wq);
 124                        dprintk("Invoking bc_svc_process()\n");
 125                        error = bc_svc_process(serv, req, rqstp);
 126                        dprintk("bc_svc_process() returned w/ error code= %d\n",
 127                                error);
 128                } else {
 129                        spin_unlock_bh(&serv->sv_cb_lock);
 130                        if (!kthread_should_stop())
 131                                schedule();
 132                        finish_wait(&serv->sv_cb_waitq, &wq);
 133                }
 134        }
 135        svc_exit_thread(rqstp);
 136        module_put_and_exit(0);
 137        return 0;
 138}
 139
 140static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
 141                struct svc_serv *serv)
 142{
 143        if (minorversion)
 144                /*
 145                 * Save the svc_serv in the transport so that it can
 146                 * be referenced when the session backchannel is initialized
 147                 */
 148                xprt->bc_serv = serv;
 149}
 150#else
 151static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
 152                struct svc_serv *serv)
 153{
 154}
 155#endif /* CONFIG_NFS_V4_1 */
 156
 157static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
 158                                  struct svc_serv *serv)
 159{
 160        int nrservs = nfs_callback_nr_threads;
 161        int ret;
 162
 163        nfs_callback_bc_serv(minorversion, xprt, serv);
 164
 165        if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS)
 166                nrservs = NFS4_MIN_NR_CALLBACK_THREADS;
 167
 168        if (serv->sv_nrthreads-1 == nrservs)
 169                return 0;
 170
 171        ret = serv->sv_ops->svo_setup(serv, NULL, nrservs);
 172        if (ret) {
 173                serv->sv_ops->svo_setup(serv, NULL, 0);
 174                return ret;
 175        }
 176        dprintk("nfs_callback_up: service started\n");
 177        return 0;
 178}
 179
 180static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
 181{
 182        struct nfs_net *nn = net_generic(net, nfs_net_id);
 183
 184        if (--nn->cb_users[minorversion])
 185                return;
 186
 187        dprintk("NFS: destroy per-net callback data; net=%p\n", net);
 188        svc_shutdown_net(serv, net);
 189}
 190
 191static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
 192                               struct net *net, struct rpc_xprt *xprt)
 193{
 194        struct nfs_net *nn = net_generic(net, nfs_net_id);
 195        int ret;
 196
 197        if (nn->cb_users[minorversion]++)
 198                return 0;
 199
 200        dprintk("NFS: create per-net callback data; net=%p\n", net);
 201
 202        ret = svc_bind(serv, net);
 203        if (ret < 0) {
 204                printk(KERN_WARNING "NFS: bind callback service failed\n");
 205                goto err_bind;
 206        }
 207
 208        ret = -EPROTONOSUPPORT;
 209        if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
 210                ret = nfs4_callback_up_net(serv, net);
 211        else if (xprt->ops->bc_up)
 212                ret = xprt->ops->bc_up(serv, net);
 213
 214        if (ret < 0) {
 215                printk(KERN_ERR "NFS: callback service start failed\n");
 216                goto err_socks;
 217        }
 218        return 0;
 219
 220err_socks:
 221        svc_rpcb_cleanup(serv, net);
 222err_bind:
 223        nn->cb_users[minorversion]--;
 224        dprintk("NFS: Couldn't create callback socket: err = %d; "
 225                        "net = %p\n", ret, net);
 226        return ret;
 227}
 228
 229static struct svc_serv_ops nfs40_cb_sv_ops = {
 230        .svo_function           = nfs4_callback_svc,
 231        .svo_enqueue_xprt       = svc_xprt_do_enqueue,
 232        .svo_setup              = svc_set_num_threads_sync,
 233        .svo_module             = THIS_MODULE,
 234};
 235#if defined(CONFIG_NFS_V4_1)
 236static struct svc_serv_ops nfs41_cb_sv_ops = {
 237        .svo_function           = nfs41_callback_svc,
 238        .svo_enqueue_xprt       = svc_xprt_do_enqueue,
 239        .svo_setup              = svc_set_num_threads_sync,
 240        .svo_module             = THIS_MODULE,
 241};
 242
 243static struct svc_serv_ops *nfs4_cb_sv_ops[] = {
 244        [0] = &nfs40_cb_sv_ops,
 245        [1] = &nfs41_cb_sv_ops,
 246};
 247#else
 248static struct svc_serv_ops *nfs4_cb_sv_ops[] = {
 249        [0] = &nfs40_cb_sv_ops,
 250        [1] = NULL,
 251};
 252#endif
 253
 254static struct svc_serv *nfs_callback_create_svc(int minorversion)
 255{
 256        struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 257        struct svc_serv *serv;
 258        struct svc_serv_ops *sv_ops;
 259
 260        /*
 261         * Check whether we're already up and running.
 262         */
 263        if (cb_info->serv) {
 264                /*
 265                 * Note: increase service usage, because later in case of error
 266                 * svc_destroy() will be called.
 267                 */
 268                svc_get(cb_info->serv);
 269                return cb_info->serv;
 270        }
 271
 272        switch (minorversion) {
 273        case 0:
 274                sv_ops = nfs4_cb_sv_ops[0];
 275                break;
 276        default:
 277                sv_ops = nfs4_cb_sv_ops[1];
 278        }
 279
 280        if (sv_ops == NULL)
 281                return ERR_PTR(-ENOTSUPP);
 282
 283        /*
 284         * Sanity check: if there's no task,
 285         * we should be the first user ...
 286         */
 287        if (cb_info->users)
 288                printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
 289                        cb_info->users);
 290
 291        serv = svc_create_pooled(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, sv_ops);
 292        if (!serv) {
 293                printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
 294                return ERR_PTR(-ENOMEM);
 295        }
 296        cb_info->serv = serv;
 297        /* As there is only one thread we need to over-ride the
 298         * default maximum of 80 connections
 299         */
 300        serv->sv_maxconn = 1024;
 301        dprintk("nfs_callback_create_svc: service created\n");
 302        return serv;
 303}
 304
 305/*
 306 * Bring up the callback thread if it is not already up.
 307 */
 308int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
 309{
 310        struct svc_serv *serv;
 311        struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 312        int ret;
 313        struct net *net = xprt->xprt_net;
 314
 315        mutex_lock(&nfs_callback_mutex);
 316
 317        serv = nfs_callback_create_svc(minorversion);
 318        if (IS_ERR(serv)) {
 319                ret = PTR_ERR(serv);
 320                goto err_create;
 321        }
 322
 323        ret = nfs_callback_up_net(minorversion, serv, net, xprt);
 324        if (ret < 0)
 325                goto err_net;
 326
 327        ret = nfs_callback_start_svc(minorversion, xprt, serv);
 328        if (ret < 0)
 329                goto err_start;
 330
 331        cb_info->users++;
 332        /*
 333         * svc_create creates the svc_serv with sv_nrthreads == 1, and then
 334         * svc_prepare_thread increments that. So we need to call svc_destroy
 335         * on both success and failure so that the refcount is 1 when the
 336         * thread exits.
 337         */
 338err_net:
 339        if (!cb_info->users)
 340                cb_info->serv = NULL;
 341        svc_destroy(serv);
 342err_create:
 343        mutex_unlock(&nfs_callback_mutex);
 344        return ret;
 345
 346err_start:
 347        nfs_callback_down_net(minorversion, serv, net);
 348        dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
 349        goto err_net;
 350}
 351
 352/*
 353 * Kill the callback thread if it's no longer being used.
 354 */
 355void nfs_callback_down(int minorversion, struct net *net)
 356{
 357        struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 358        struct svc_serv *serv;
 359
 360        mutex_lock(&nfs_callback_mutex);
 361        serv = cb_info->serv;
 362        nfs_callback_down_net(minorversion, serv, net);
 363        cb_info->users--;
 364        if (cb_info->users == 0) {
 365                svc_get(serv);
 366                serv->sv_ops->svo_setup(serv, NULL, 0);
 367                svc_destroy(serv);
 368                dprintk("nfs_callback_down: service destroyed\n");
 369                cb_info->serv = NULL;
 370        }
 371        mutex_unlock(&nfs_callback_mutex);
 372}
 373
 374/* Boolean check of RPC_AUTH_GSS principal */
 375int
 376check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 377{
 378        char *p = rqstp->rq_cred.cr_principal;
 379
 380        if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
 381                return 1;
 382
 383        /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
 384        if (clp->cl_minorversion != 0)
 385                return 0;
 386        /*
 387         * It might just be a normal user principal, in which case
 388         * userspace won't bother to tell us the name at all.
 389         */
 390        if (p == NULL)
 391                return 0;
 392
 393        /*
 394         * Did we get the acceptor from userland during the SETCLIENID
 395         * negotiation?
 396         */
 397        if (clp->cl_acceptor)
 398                return !strcmp(p, clp->cl_acceptor);
 399
 400        /*
 401         * Otherwise try to verify it using the cl_hostname. Note that this
 402         * doesn't work if a non-canonical hostname was used in the devname.
 403         */
 404
 405        /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
 406
 407        if (memcmp(p, "nfs@", 4) != 0)
 408                return 0;
 409        p += 4;
 410        if (strcmp(p, clp->cl_hostname) != 0)
 411                return 0;
 412        return 1;
 413}
 414
 415/*
 416 * pg_authenticate method for nfsv4 callback threads.
 417 *
 418 * The authflavor has been negotiated, so an incorrect flavor is a server
 419 * bug. Deny packets with incorrect authflavor.
 420 *
 421 * All other checking done after NFS decoding where the nfs_client can be
 422 * found in nfs4_callback_compound
 423 */
 424static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 425{
 426        switch (rqstp->rq_authop->flavour) {
 427        case RPC_AUTH_NULL:
 428                if (rqstp->rq_proc != CB_NULL)
 429                        return SVC_DENIED;
 430                break;
 431        case RPC_AUTH_GSS:
 432                /* No RPC_AUTH_GSS support yet in NFSv4.1 */
 433                 if (svc_is_backchannel(rqstp))
 434                        return SVC_DENIED;
 435        }
 436        return SVC_OK;
 437}
 438
 439/*
 440 * Define NFS4 callback program
 441 */
 442static struct svc_version *nfs4_callback_version[] = {
 443        [1] = &nfs4_callback_version1,
 444        [4] = &nfs4_callback_version4,
 445};
 446
 447static struct svc_stat nfs4_callback_stats;
 448
 449static struct svc_program nfs4_callback_program = {
 450        .pg_prog = NFS4_CALLBACK,                       /* RPC service number */
 451        .pg_nvers = ARRAY_SIZE(nfs4_callback_version),  /* Number of entries */
 452        .pg_vers = nfs4_callback_version,               /* version table */
 453        .pg_name = "NFSv4 callback",                    /* service name */
 454        .pg_class = "nfs",                              /* authentication class */
 455        .pg_stats = &nfs4_callback_stats,
 456        .pg_authenticate = nfs_callback_authenticate,
 457};
 458