linux/fs/nfsd/nfs4callback.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/nfsd/nfs4callback.c
   3 *
   4 *  Copyright (c) 2001 The Regents of the University of Michigan.
   5 *  All rights reserved.
   6 *
   7 *  Kendrick Smith <kmsmith@umich.edu>
   8 *  Andy Adamson <andros@umich.edu>
   9 *
  10 *  Redistribution and use in source and binary forms, with or without
  11 *  modification, are permitted provided that the following conditions
  12 *  are met:
  13 *
  14 *  1. Redistributions of source code must retain the above copyright
  15 *     notice, this list of conditions and the following disclaimer.
  16 *  2. Redistributions in binary form must reproduce the above copyright
  17 *     notice, this list of conditions and the following disclaimer in the
  18 *     documentation and/or other materials provided with the distribution.
  19 *  3. Neither the name of the University nor the names of its
  20 *     contributors may be used to endorse or promote products derived
  21 *     from this software without specific prior written permission.
  22 *
  23 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  24 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  30 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34 */
  35
  36#include <linux/module.h>
  37#include <linux/list.h>
  38#include <linux/inet.h>
  39#include <linux/errno.h>
  40#include <linux/delay.h>
  41#include <linux/sched.h>
  42#include <linux/kthread.h>
  43#include <linux/sunrpc/xdr.h>
  44#include <linux/sunrpc/svc.h>
  45#include <linux/sunrpc/clnt.h>
  46#include <linux/nfsd/nfsd.h>
  47#include <linux/nfsd/state.h>
  48#include <linux/sunrpc/sched.h>
  49#include <linux/nfs4.h>
  50
  51#define NFSDDBG_FACILITY                NFSDDBG_PROC
  52
  53#define NFSPROC4_CB_NULL 0
  54#define NFSPROC4_CB_COMPOUND 1
  55
  56/* declarations */
  57static const struct rpc_call_ops nfs4_cb_null_ops;
  58
  59/* Index of predefined Linux callback client operations */
  60
  61enum {
  62        NFSPROC4_CLNT_CB_NULL = 0,
  63        NFSPROC4_CLNT_CB_RECALL,
  64};
  65
  66enum nfs_cb_opnum4 {
  67        OP_CB_RECALL            = 4,
  68};
  69
  70#define NFS4_MAXTAGLEN          20
  71
  72#define NFS4_enc_cb_null_sz             0
  73#define NFS4_dec_cb_null_sz             0
  74#define cb_compound_enc_hdr_sz          4
  75#define cb_compound_dec_hdr_sz          (3 + (NFS4_MAXTAGLEN >> 2))
  76#define op_enc_sz                       1
  77#define op_dec_sz                       2
  78#define enc_nfs4_fh_sz                  (1 + (NFS4_FHSIZE >> 2))
  79#define enc_stateid_sz                  (NFS4_STATEID_SIZE >> 2)
  80#define NFS4_enc_cb_recall_sz           (cb_compound_enc_hdr_sz +       \
  81                                        1 + enc_stateid_sz +            \
  82                                        enc_nfs4_fh_sz)
  83
  84#define NFS4_dec_cb_recall_sz           (cb_compound_dec_hdr_sz  +      \
  85                                        op_dec_sz)
  86
  87/*
  88* Generic encode routines from fs/nfs/nfs4xdr.c
  89*/
  90static inline __be32 *
  91xdr_writemem(__be32 *p, const void *ptr, int nbytes)
  92{
  93        int tmp = XDR_QUADLEN(nbytes);
  94        if (!tmp)
  95                return p;
  96        p[tmp-1] = 0;
  97        memcpy(p, ptr, nbytes);
  98        return p + tmp;
  99}
 100
 101#define WRITE32(n)               *p++ = htonl(n)
 102#define WRITEMEM(ptr,nbytes)     do {                           \
 103        p = xdr_writemem(p, ptr, nbytes);                       \
 104} while (0)
 105#define RESERVE_SPACE(nbytes)   do {                            \
 106        p = xdr_reserve_space(xdr, nbytes);                     \
 107        if (!p) dprintk("NFSD: RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __func__); \
 108        BUG_ON(!p);                                             \
 109} while (0)
 110
 111/*
 112 * Generic decode routines from fs/nfs/nfs4xdr.c
 113 */
 114#define DECODE_TAIL                             \
 115        status = 0;                             \
 116out:                                            \
 117        return status;                          \
 118xdr_error:                                      \
 119        dprintk("NFSD: xdr error! (%s:%d)\n", __FILE__, __LINE__); \
 120        status = -EIO;                          \
 121        goto out
 122
 123#define READ32(x)         (x) = ntohl(*p++)
 124#define READ64(x)         do {                  \
 125        (x) = (u64)ntohl(*p++) << 32;           \
 126        (x) |= ntohl(*p++);                     \
 127} while (0)
 128#define READTIME(x)       do {                  \
 129        p++;                                    \
 130        (x.tv_sec) = ntohl(*p++);               \
 131        (x.tv_nsec) = ntohl(*p++);              \
 132} while (0)
 133#define READ_BUF(nbytes)  do { \
 134        p = xdr_inline_decode(xdr, nbytes); \
 135        if (!p) { \
 136                dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \
 137                        __func__, __LINE__); \
 138                return -EIO; \
 139        } \
 140} while (0)
 141
 142struct nfs4_cb_compound_hdr {
 143        int             status;
 144        u32             ident;
 145        u32             nops;
 146        u32             taglen;
 147        char *          tag;
 148};
 149
 150static struct {
 151int stat;
 152int errno;
 153} nfs_cb_errtbl[] = {
 154        { NFS4_OK,              0               },
 155        { NFS4ERR_PERM,         EPERM           },
 156        { NFS4ERR_NOENT,        ENOENT          },
 157        { NFS4ERR_IO,           EIO             },
 158        { NFS4ERR_NXIO,         ENXIO           },
 159        { NFS4ERR_ACCESS,       EACCES          },
 160        { NFS4ERR_EXIST,        EEXIST          },
 161        { NFS4ERR_XDEV,         EXDEV           },
 162        { NFS4ERR_NOTDIR,       ENOTDIR         },
 163        { NFS4ERR_ISDIR,        EISDIR          },
 164        { NFS4ERR_INVAL,        EINVAL          },
 165        { NFS4ERR_FBIG,         EFBIG           },
 166        { NFS4ERR_NOSPC,        ENOSPC          },
 167        { NFS4ERR_ROFS,         EROFS           },
 168        { NFS4ERR_MLINK,        EMLINK          },
 169        { NFS4ERR_NAMETOOLONG,  ENAMETOOLONG    },
 170        { NFS4ERR_NOTEMPTY,     ENOTEMPTY       },
 171        { NFS4ERR_DQUOT,        EDQUOT          },
 172        { NFS4ERR_STALE,        ESTALE          },
 173        { NFS4ERR_BADHANDLE,    EBADHANDLE      },
 174        { NFS4ERR_BAD_COOKIE,   EBADCOOKIE      },
 175        { NFS4ERR_NOTSUPP,      ENOTSUPP        },
 176        { NFS4ERR_TOOSMALL,     ETOOSMALL       },
 177        { NFS4ERR_SERVERFAULT,  ESERVERFAULT    },
 178        { NFS4ERR_BADTYPE,      EBADTYPE        },
 179        { NFS4ERR_LOCKED,       EAGAIN          },
 180        { NFS4ERR_RESOURCE,     EREMOTEIO       },
 181        { NFS4ERR_SYMLINK,      ELOOP           },
 182        { NFS4ERR_OP_ILLEGAL,   EOPNOTSUPP      },
 183        { NFS4ERR_DEADLOCK,     EDEADLK         },
 184        { -1,                   EIO             }
 185};
 186
 187static int
 188nfs_cb_stat_to_errno(int stat)
 189{
 190        int i;
 191        for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) {
 192                if (nfs_cb_errtbl[i].stat == stat)
 193                        return nfs_cb_errtbl[i].errno;
 194        }
 195        /* If we cannot translate the error, the recovery routines should
 196        * handle it.
 197        * Note: remaining NFSv4 error codes have values > 10000, so should
 198        * not conflict with native Linux error codes.
 199        */
 200        return stat;
 201}
 202
 203/*
 204 * XDR encode
 205 */
 206
 207static int
 208encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
 209{
 210        __be32 * p;
 211
 212        RESERVE_SPACE(16);
 213        WRITE32(0);            /* tag length is always 0 */
 214        WRITE32(NFS4_MINOR_VERSION);
 215        WRITE32(hdr->ident);
 216        WRITE32(hdr->nops);
 217        return 0;
 218}
 219
 220static int
 221encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
 222{
 223        __be32 *p;
 224        int len = cb_rec->cbr_fhlen;
 225
 226        RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
 227        WRITE32(OP_CB_RECALL);
 228        WRITE32(cb_rec->cbr_stateid.si_generation);
 229        WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
 230        WRITE32(cb_rec->cbr_trunc);
 231        WRITE32(len);
 232        WRITEMEM(cb_rec->cbr_fhval, len);
 233        return 0;
 234}
 235
 236static int
 237nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
 238{
 239        struct xdr_stream xdrs, *xdr = &xdrs;
 240
 241        xdr_init_encode(&xdrs, &req->rq_snd_buf, p);
 242        RESERVE_SPACE(0);
 243        return 0;
 244}
 245
 246static int
 247nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args)
 248{
 249        struct xdr_stream xdr;
 250        struct nfs4_cb_compound_hdr hdr = {
 251                .ident = args->cbr_ident,
 252                .nops   = 1,
 253        };
 254
 255        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 256        encode_cb_compound_hdr(&xdr, &hdr);
 257        return (encode_cb_recall(&xdr, args));
 258}
 259
 260
 261static int
 262decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
 263        __be32 *p;
 264
 265        READ_BUF(8);
 266        READ32(hdr->status);
 267        READ32(hdr->taglen);
 268        READ_BUF(hdr->taglen + 4);
 269        hdr->tag = (char *)p;
 270        p += XDR_QUADLEN(hdr->taglen);
 271        READ32(hdr->nops);
 272        return 0;
 273}
 274
 275static int
 276decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 277{
 278        __be32 *p;
 279        u32 op;
 280        int32_t nfserr;
 281
 282        READ_BUF(8);
 283        READ32(op);
 284        if (op != expected) {
 285                dprintk("NFSD: decode_cb_op_hdr: Callback server returned "
 286                         " operation %d but we issued a request for %d\n",
 287                         op, expected);
 288                return -EIO;
 289        }
 290        READ32(nfserr);
 291        if (nfserr != NFS_OK)
 292                return -nfs_cb_stat_to_errno(nfserr);
 293        return 0;
 294}
 295
 296static int
 297nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
 298{
 299        return 0;
 300}
 301
 302static int
 303nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p)
 304{
 305        struct xdr_stream xdr;
 306        struct nfs4_cb_compound_hdr hdr;
 307        int status;
 308
 309        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
 310        status = decode_cb_compound_hdr(&xdr, &hdr);
 311        if (status)
 312                goto out;
 313        status = decode_cb_op_hdr(&xdr, OP_CB_RECALL);
 314out:
 315        return status;
 316}
 317
 318/*
 319 * RPC procedure tables
 320 */
 321#define PROC(proc, call, argtype, restype)                              \
 322[NFSPROC4_CLNT_##proc] = {                                              \
 323        .p_proc   = NFSPROC4_CB_##call,                                 \
 324        .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,                    \
 325        .p_decode = (kxdrproc_t) nfs4_xdr_##restype,                    \
 326        .p_arglen = NFS4_##argtype##_sz,                                \
 327        .p_replen = NFS4_##restype##_sz,                                \
 328        .p_statidx = NFSPROC4_CB_##call,                                \
 329        .p_name   = #proc,                                              \
 330}
 331
 332static struct rpc_procinfo     nfs4_cb_procedures[] = {
 333    PROC(CB_NULL,      NULL,     enc_cb_null,     dec_cb_null),
 334    PROC(CB_RECALL,    COMPOUND,   enc_cb_recall,      dec_cb_recall),
 335};
 336
 337static struct rpc_version       nfs_cb_version4 = {
 338        .number                 = 1,
 339        .nrprocs                = ARRAY_SIZE(nfs4_cb_procedures),
 340        .procs                  = nfs4_cb_procedures
 341};
 342
 343static struct rpc_version *     nfs_cb_version[] = {
 344        NULL,
 345        &nfs_cb_version4,
 346};
 347
 348static struct rpc_program cb_program;
 349
 350static struct rpc_stat cb_stats = {
 351                .program        = &cb_program
 352};
 353
 354#define NFS4_CALLBACK 0x40000000
 355static struct rpc_program cb_program = {
 356                .name           = "nfs4_cb",
 357                .number         = NFS4_CALLBACK,
 358                .nrvers         = ARRAY_SIZE(nfs_cb_version),
 359                .version        = nfs_cb_version,
 360                .stats          = &cb_stats,
 361};
 362
 363/* Reference counting, callback cleanup, etc., all look racy as heck.
 364 * And why is cb_set an atomic? */
 365
 366static int do_probe_callback(void *data)
 367{
 368        struct nfs4_client *clp = data;
 369        struct sockaddr_in      addr;
 370        struct nfs4_callback    *cb = &clp->cl_callback;
 371        struct rpc_timeout      timeparms = {
 372                .to_initval     = (NFSD_LEASE_TIME/4) * HZ,
 373                .to_retries     = 5,
 374                .to_maxval      = (NFSD_LEASE_TIME/2) * HZ,
 375                .to_exponential = 1,
 376        };
 377        struct rpc_create_args args = {
 378                .protocol       = IPPROTO_TCP,
 379                .address        = (struct sockaddr *)&addr,
 380                .addrsize       = sizeof(addr),
 381                .timeout        = &timeparms,
 382                .program        = &cb_program,
 383                .prognumber     = cb->cb_prog,
 384                .version        = nfs_cb_version[1]->number,
 385                .authflavor     = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
 386                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
 387        };
 388        struct rpc_message msg = {
 389                .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
 390                .rpc_argp       = clp,
 391        };
 392        struct rpc_clnt *client;
 393        int status;
 394
 395        /* Initialize address */
 396        memset(&addr, 0, sizeof(addr));
 397        addr.sin_family = AF_INET;
 398        addr.sin_port = htons(cb->cb_port);
 399        addr.sin_addr.s_addr = htonl(cb->cb_addr);
 400
 401        /* Create RPC client */
 402        client = rpc_create(&args);
 403        if (IS_ERR(client)) {
 404                dprintk("NFSD: couldn't create callback client\n");
 405                status = PTR_ERR(client);
 406                goto out_err;
 407        }
 408
 409        status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
 410
 411        if (status)
 412                goto out_release_client;
 413
 414        cb->cb_client = client;
 415        atomic_set(&cb->cb_set, 1);
 416        put_nfs4_client(clp);
 417        return 0;
 418out_release_client:
 419        rpc_shutdown_client(client);
 420out_err:
 421        dprintk("NFSD: warning: no callback path to client %.*s\n",
 422                (int)clp->cl_name.len, clp->cl_name.data);
 423        put_nfs4_client(clp);
 424        return status;
 425}
 426
 427/*
 428 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
 429 */
 430void
 431nfsd4_probe_callback(struct nfs4_client *clp)
 432{
 433        struct task_struct *t;
 434
 435        BUG_ON(atomic_read(&clp->cl_callback.cb_set));
 436
 437        /* the task holds a reference to the nfs4_client struct */
 438        atomic_inc(&clp->cl_count);
 439
 440        t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
 441
 442        if (IS_ERR(t))
 443                atomic_dec(&clp->cl_count);
 444
 445        return;
 446}
 447
 448/*
 449 * called with dp->dl_count inc'ed.
 450 * nfs4_lock_state() may or may not have been called.
 451 */
 452void
 453nfsd4_cb_recall(struct nfs4_delegation *dp)
 454{
 455        struct nfs4_client *clp = dp->dl_client;
 456        struct rpc_clnt *clnt = clp->cl_callback.cb_client;
 457        struct nfs4_cb_recall *cbr = &dp->dl_recall;
 458        struct rpc_message msg = {
 459                .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
 460                .rpc_argp = cbr,
 461        };
 462        int retries = 1;
 463        int status = 0;
 464
 465        cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
 466        cbr->cbr_dp = dp;
 467
 468        status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
 469        while (retries--) {
 470                switch (status) {
 471                        case -EIO:
 472                                /* Network partition? */
 473                                atomic_set(&clp->cl_callback.cb_set, 0);
 474                        case -EBADHANDLE:
 475                        case -NFS4ERR_BAD_STATEID:
 476                                /* Race: client probably got cb_recall
 477                                 * before open reply granting delegation */
 478                                break;
 479                        default:
 480                                goto out_put_cred;
 481                }
 482                ssleep(2);
 483                status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
 484        }
 485out_put_cred:
 486        /*
 487         * Success or failure, now we're either waiting for lease expiration
 488         * or deleg_return.
 489         */
 490        put_nfs4_client(clp);
 491        nfs4_put_delegation(dp);
 492        return;
 493}
 494
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.