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/sunrpc/svcsock.h>
  47#include <linux/nfsd/nfsd.h>
  48#include <linux/nfsd/state.h>
  49#include <linux/sunrpc/sched.h>
  50#include <linux/nfs4.h>
  51#include <linux/sunrpc/xprtsock.h>
  52
  53#define NFSDDBG_FACILITY                NFSDDBG_PROC
  54
  55#define NFSPROC4_CB_NULL 0
  56#define NFSPROC4_CB_COMPOUND 1
  57#define NFS4_STATEID_SIZE 16
  58
  59/* Index of predefined Linux callback client operations */
  60
  61enum {
  62        NFSPROC4_CLNT_CB_NULL = 0,
  63        NFSPROC4_CLNT_CB_RECALL,
  64        NFSPROC4_CLNT_CB_SEQUENCE,
  65};
  66
  67enum nfs_cb_opnum4 {
  68        OP_CB_RECALL            = 4,
  69        OP_CB_SEQUENCE          = 11,
  70};
  71
  72#define NFS4_MAXTAGLEN          20
  73
  74#define NFS4_enc_cb_null_sz             0
  75#define NFS4_dec_cb_null_sz             0
  76#define cb_compound_enc_hdr_sz          4
  77#define cb_compound_dec_hdr_sz          (3 + (NFS4_MAXTAGLEN >> 2))
  78#define sessionid_sz                    (NFS4_MAX_SESSIONID_LEN >> 2)
  79#define cb_sequence_enc_sz              (sessionid_sz + 4 +             \
  80                                        1 /* no referring calls list yet */)
  81#define cb_sequence_dec_sz              (op_dec_sz + sessionid_sz + 4)
  82
  83#define op_enc_sz                       1
  84#define op_dec_sz                       2
  85#define enc_nfs4_fh_sz                  (1 + (NFS4_FHSIZE >> 2))
  86#define enc_stateid_sz                  (NFS4_STATEID_SIZE >> 2)
  87#define NFS4_enc_cb_recall_sz           (cb_compound_enc_hdr_sz +       \
  88                                        cb_sequence_enc_sz +            \
  89                                        1 + enc_stateid_sz +            \
  90                                        enc_nfs4_fh_sz)
  91
  92#define NFS4_dec_cb_recall_sz           (cb_compound_dec_hdr_sz  +      \
  93                                        cb_sequence_dec_sz +            \
  94                                        op_dec_sz)
  95
  96struct nfs4_rpc_args {
  97        void                            *args_op;
  98        struct nfsd4_cb_sequence        args_seq;
  99};
 100
 101/*
 102* Generic encode routines from fs/nfs/nfs4xdr.c
 103*/
 104static inline __be32 *
 105xdr_writemem(__be32 *p, const void *ptr, int nbytes)
 106{
 107        int tmp = XDR_QUADLEN(nbytes);
 108        if (!tmp)
 109                return p;
 110        p[tmp-1] = 0;
 111        memcpy(p, ptr, nbytes);
 112        return p + tmp;
 113}
 114
 115#define WRITE32(n)               *p++ = htonl(n)
 116#define WRITEMEM(ptr,nbytes)     do {                           \
 117        p = xdr_writemem(p, ptr, nbytes);                       \
 118} while (0)
 119#define RESERVE_SPACE(nbytes)   do {                            \
 120        p = xdr_reserve_space(xdr, nbytes);                     \
 121        if (!p) dprintk("NFSD: RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __func__); \
 122        BUG_ON(!p);                                             \
 123} while (0)
 124
 125/*
 126 * Generic decode routines from fs/nfs/nfs4xdr.c
 127 */
 128#define DECODE_TAIL                             \
 129        status = 0;                             \
 130out:                                            \
 131        return status;                          \
 132xdr_error:                                      \
 133        dprintk("NFSD: xdr error! (%s:%d)\n", __FILE__, __LINE__); \
 134        status = -EIO;                          \
 135        goto out
 136
 137#define READ32(x)         (x) = ntohl(*p++)
 138#define READ64(x)         do {                  \
 139        (x) = (u64)ntohl(*p++) << 32;           \
 140        (x) |= ntohl(*p++);                     \
 141} while (0)
 142#define READTIME(x)       do {                  \
 143        p++;                                    \
 144        (x.tv_sec) = ntohl(*p++);               \
 145        (x.tv_nsec) = ntohl(*p++);              \
 146} while (0)
 147#define READ_BUF(nbytes)  do { \
 148        p = xdr_inline_decode(xdr, nbytes); \
 149        if (!p) { \
 150                dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \
 151                        __func__, __LINE__); \
 152                return -EIO; \
 153        } \
 154} while (0)
 155
 156struct nfs4_cb_compound_hdr {
 157        /* args */
 158        u32             ident;  /* minorversion 0 only */
 159        u32             nops;
 160        __be32          *nops_p;
 161        u32             minorversion;
 162        /* res */
 163        int             status;
 164        u32             taglen;
 165        char            *tag;
 166};
 167
 168static struct {
 169int stat;
 170int errno;
 171} nfs_cb_errtbl[] = {
 172        { NFS4_OK,              0               },
 173        { NFS4ERR_PERM,         EPERM           },
 174        { NFS4ERR_NOENT,        ENOENT          },
 175        { NFS4ERR_IO,           EIO             },
 176        { NFS4ERR_NXIO,         ENXIO           },
 177        { NFS4ERR_ACCESS,       EACCES          },
 178        { NFS4ERR_EXIST,        EEXIST          },
 179        { NFS4ERR_XDEV,         EXDEV           },
 180        { NFS4ERR_NOTDIR,       ENOTDIR         },
 181        { NFS4ERR_ISDIR,        EISDIR          },
 182        { NFS4ERR_INVAL,        EINVAL          },
 183        { NFS4ERR_FBIG,         EFBIG           },
 184        { NFS4ERR_NOSPC,        ENOSPC          },
 185        { NFS4ERR_ROFS,         EROFS           },
 186        { NFS4ERR_MLINK,        EMLINK          },
 187        { NFS4ERR_NAMETOOLONG,  ENAMETOOLONG    },
 188        { NFS4ERR_NOTEMPTY,     ENOTEMPTY       },
 189        { NFS4ERR_DQUOT,        EDQUOT          },
 190        { NFS4ERR_STALE,        ESTALE          },
 191        { NFS4ERR_BADHANDLE,    EBADHANDLE      },
 192        { NFS4ERR_BAD_COOKIE,   EBADCOOKIE      },
 193        { NFS4ERR_NOTSUPP,      ENOTSUPP        },
 194        { NFS4ERR_TOOSMALL,     ETOOSMALL       },
 195        { NFS4ERR_SERVERFAULT,  ESERVERFAULT    },
 196        { NFS4ERR_BADTYPE,      EBADTYPE        },
 197        { NFS4ERR_LOCKED,       EAGAIN          },
 198        { NFS4ERR_RESOURCE,     EREMOTEIO       },
 199        { NFS4ERR_SYMLINK,      ELOOP           },
 200        { NFS4ERR_OP_ILLEGAL,   EOPNOTSUPP      },
 201        { NFS4ERR_DEADLOCK,     EDEADLK         },
 202        { -1,                   EIO             }
 203};
 204
 205static int
 206nfs_cb_stat_to_errno(int stat)
 207{
 208        int i;
 209        for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) {
 210                if (nfs_cb_errtbl[i].stat == stat)
 211                        return nfs_cb_errtbl[i].errno;
 212        }
 213        /* If we cannot translate the error, the recovery routines should
 214        * handle it.
 215        * Note: remaining NFSv4 error codes have values > 10000, so should
 216        * not conflict with native Linux error codes.
 217        */
 218        return stat;
 219}
 220
 221/*
 222 * XDR encode
 223 */
 224
 225static void
 226encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
 227{
 228        __be32 * p;
 229
 230        RESERVE_SPACE(16);
 231        WRITE32(0);            /* tag length is always 0 */
 232        WRITE32(hdr->minorversion);
 233        WRITE32(hdr->ident);
 234        hdr->nops_p = p;
 235        WRITE32(hdr->nops);
 236}
 237
 238static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr)
 239{
 240        *hdr->nops_p = htonl(hdr->nops);
 241}
 242
 243static void
 244encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
 245                struct nfs4_cb_compound_hdr *hdr)
 246{
 247        __be32 *p;
 248        int len = dp->dl_fh.fh_size;
 249
 250        RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len);
 251        WRITE32(OP_CB_RECALL);
 252        WRITE32(dp->dl_stateid.si_generation);
 253        WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t));
 254        WRITE32(0); /* truncate optimization not implemented */
 255        WRITE32(len);
 256        WRITEMEM(&dp->dl_fh.fh_base, len);
 257        hdr->nops++;
 258}
 259
 260static void
 261encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args,
 262                   struct nfs4_cb_compound_hdr *hdr)
 263{
 264        __be32 *p;
 265
 266        if (hdr->minorversion == 0)
 267                return;
 268
 269        RESERVE_SPACE(1 + NFS4_MAX_SESSIONID_LEN + 20);
 270
 271        WRITE32(OP_CB_SEQUENCE);
 272        WRITEMEM(args->cbs_clp->cl_sessionid.data, NFS4_MAX_SESSIONID_LEN);
 273        WRITE32(args->cbs_clp->cl_cb_seq_nr);
 274        WRITE32(0);             /* slotid, always 0 */
 275        WRITE32(0);             /* highest slotid always 0 */
 276        WRITE32(0);             /* cachethis always 0 */
 277        WRITE32(0); /* FIXME: support referring_call_lists */
 278        hdr->nops++;
 279}
 280
 281static int
 282nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
 283{
 284        struct xdr_stream xdrs, *xdr = &xdrs;
 285
 286        xdr_init_encode(&xdrs, &req->rq_snd_buf, p);
 287        RESERVE_SPACE(0);
 288        return 0;
 289}
 290
 291static int
 292nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
 293                struct nfs4_rpc_args *rpc_args)
 294{
 295        struct xdr_stream xdr;
 296        struct nfs4_delegation *args = rpc_args->args_op;
 297        struct nfs4_cb_compound_hdr hdr = {
 298                .ident = args->dl_ident,
 299                .minorversion = rpc_args->args_seq.cbs_minorversion,
 300        };
 301
 302        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 303        encode_cb_compound_hdr(&xdr, &hdr);
 304        encode_cb_sequence(&xdr, &rpc_args->args_seq, &hdr);
 305        encode_cb_recall(&xdr, args, &hdr);
 306        encode_cb_nops(&hdr);
 307        return 0;
 308}
 309
 310
 311static int
 312decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
 313        __be32 *p;
 314
 315        READ_BUF(8);
 316        READ32(hdr->status);
 317        READ32(hdr->taglen);
 318        READ_BUF(hdr->taglen + 4);
 319        hdr->tag = (char *)p;
 320        p += XDR_QUADLEN(hdr->taglen);
 321        READ32(hdr->nops);
 322        return 0;
 323}
 324
 325static int
 326decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 327{
 328        __be32 *p;
 329        u32 op;
 330        int32_t nfserr;
 331
 332        READ_BUF(8);
 333        READ32(op);
 334        if (op != expected) {
 335                dprintk("NFSD: decode_cb_op_hdr: Callback server returned "
 336                         " operation %d but we issued a request for %d\n",
 337                         op, expected);
 338                return -EIO;
 339        }
 340        READ32(nfserr);
 341        if (nfserr != NFS_OK)
 342                return -nfs_cb_stat_to_errno(nfserr);
 343        return 0;
 344}
 345
 346/*
 347 * Our current back channel implmentation supports a single backchannel
 348 * with a single slot.
 349 */
 350static int
 351decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res,
 352                   struct rpc_rqst *rqstp)
 353{
 354        struct nfs4_sessionid id;
 355        int status;
 356        u32 dummy;
 357        __be32 *p;
 358
 359        if (res->cbs_minorversion == 0)
 360                return 0;
 361
 362        status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE);
 363        if (status)
 364                return status;
 365
 366        /*
 367         * If the server returns different values for sessionID, slotID or
 368         * sequence number, the server is looney tunes.
 369         */
 370        status = -ESERVERFAULT;
 371
 372        READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
 373        memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
 374        p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN);
 375        if (memcmp(id.data, res->cbs_clp->cl_sessionid.data,
 376                   NFS4_MAX_SESSIONID_LEN)) {
 377                dprintk("%s Invalid session id\n", __func__);
 378                goto out;
 379        }
 380        READ32(dummy);
 381        if (dummy != res->cbs_clp->cl_cb_seq_nr) {
 382                dprintk("%s Invalid sequence number\n", __func__);
 383                goto out;
 384        }
 385        READ32(dummy);  /* slotid must be 0 */
 386        if (dummy != 0) {
 387                dprintk("%s Invalid slotid\n", __func__);
 388                goto out;
 389        }
 390        /* FIXME: process highest slotid and target highest slotid */
 391        status = 0;
 392out:
 393        return status;
 394}
 395
 396
 397static int
 398nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
 399{
 400        return 0;
 401}
 402
 403static int
 404nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p,
 405                struct nfsd4_cb_sequence *seq)
 406{
 407        struct xdr_stream xdr;
 408        struct nfs4_cb_compound_hdr hdr;
 409        int status;
 410
 411        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
 412        status = decode_cb_compound_hdr(&xdr, &hdr);
 413        if (status)
 414                goto out;
 415        if (seq) {
 416                status = decode_cb_sequence(&xdr, seq, rqstp);
 417                if (status)
 418                        goto out;
 419        }
 420        status = decode_cb_op_hdr(&xdr, OP_CB_RECALL);
 421out:
 422        return status;
 423}
 424
 425/*
 426 * RPC procedure tables
 427 */
 428#define PROC(proc, call, argtype, restype)                              \
 429[NFSPROC4_CLNT_##proc] = {                                              \
 430        .p_proc   = NFSPROC4_CB_##call,                                 \
 431        .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,                    \
 432        .p_decode = (kxdrproc_t) nfs4_xdr_##restype,                    \
 433        .p_arglen = NFS4_##argtype##_sz,                                \
 434        .p_replen = NFS4_##restype##_sz,                                \
 435        .p_statidx = NFSPROC4_CB_##call,                                \
 436        .p_name   = #proc,                                              \
 437}
 438
 439static struct rpc_procinfo     nfs4_cb_procedures[] = {
 440    PROC(CB_NULL,      NULL,     enc_cb_null,     dec_cb_null),
 441    PROC(CB_RECALL,    COMPOUND,   enc_cb_recall,      dec_cb_recall),
 442};
 443
 444static struct rpc_version       nfs_cb_version4 = {
 445        .number                 = 1,
 446        .nrprocs                = ARRAY_SIZE(nfs4_cb_procedures),
 447        .procs                  = nfs4_cb_procedures
 448};
 449
 450static struct rpc_version *     nfs_cb_version[] = {
 451        NULL,
 452        &nfs_cb_version4,
 453};
 454
 455static struct rpc_program cb_program;
 456
 457static struct rpc_stat cb_stats = {
 458                .program        = &cb_program
 459};
 460
 461#define NFS4_CALLBACK 0x40000000
 462static struct rpc_program cb_program = {
 463                .name           = "nfs4_cb",
 464                .number         = NFS4_CALLBACK,
 465                .nrvers         = ARRAY_SIZE(nfs_cb_version),
 466                .version        = nfs_cb_version,
 467                .stats          = &cb_stats,
 468                .pipe_dir_name  = "/nfsd4_cb",
 469};
 470
 471static int max_cb_time(void)
 472{
 473        return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ;
 474}
 475
 476/* Reference counting, callback cleanup, etc., all look racy as heck.
 477 * And why is cb_set an atomic? */
 478
 479int setup_callback_client(struct nfs4_client *clp)
 480{
 481        struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
 482        struct rpc_timeout      timeparms = {
 483                .to_initval     = max_cb_time(),
 484                .to_retries     = 0,
 485        };
 486        struct rpc_create_args args = {
 487                .protocol       = XPRT_TRANSPORT_TCP,
 488                .address        = (struct sockaddr *) &cb->cb_addr,
 489                .addrsize       = cb->cb_addrlen,
 490                .timeout        = &timeparms,
 491                .program        = &cb_program,
 492                .prognumber     = cb->cb_prog,
 493                .version        = nfs_cb_version[1]->number,
 494                .authflavor     = clp->cl_flavor,
 495                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
 496                .client_name    = clp->cl_principal,
 497        };
 498        struct rpc_clnt *client;
 499
 500        if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
 501                return -EINVAL;
 502        if (cb->cb_minorversion) {
 503                args.bc_xprt = clp->cl_cb_xprt;
 504                args.protocol = XPRT_TRANSPORT_BC_TCP;
 505        }
 506        /* Create RPC client */
 507        client = rpc_create(&args);
 508        if (IS_ERR(client)) {
 509                dprintk("NFSD: couldn't create callback client: %ld\n",
 510                        PTR_ERR(client));
 511                return PTR_ERR(client);
 512        }
 513        cb->cb_client = client;
 514        return 0;
 515
 516}
 517
 518static void warn_no_callback_path(struct nfs4_client *clp, int reason)
 519{
 520        dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
 521                (int)clp->cl_name.len, clp->cl_name.data, reason);
 522}
 523
 524static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
 525{
 526        struct nfs4_client *clp = calldata;
 527
 528        if (task->tk_status)
 529                warn_no_callback_path(clp, task->tk_status);
 530        else
 531                atomic_set(&clp->cl_cb_conn.cb_set, 1);
 532        put_nfs4_client(clp);
 533}
 534
 535static const struct rpc_call_ops nfsd4_cb_probe_ops = {
 536        .rpc_call_done = nfsd4_cb_probe_done,
 537};
 538
 539static struct rpc_cred *callback_cred;
 540
 541int set_callback_cred(void)
 542{
 543        callback_cred = rpc_lookup_machine_cred();
 544        if (!callback_cred)
 545                return -ENOMEM;
 546        return 0;
 547}
 548
 549
 550void do_probe_callback(struct nfs4_client *clp)
 551{
 552        struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
 553        struct rpc_message msg = {
 554                .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
 555                .rpc_argp       = clp,
 556                .rpc_cred       = callback_cred
 557        };
 558        int status;
 559
 560        status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT,
 561                                &nfsd4_cb_probe_ops, (void *)clp);
 562        if (status) {
 563                warn_no_callback_path(clp, status);
 564                put_nfs4_client(clp);
 565        }
 566}
 567
 568/*
 569 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
 570 */
 571void
 572nfsd4_probe_callback(struct nfs4_client *clp)
 573{
 574        int status;
 575
 576        BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set));
 577
 578        status = setup_callback_client(clp);
 579        if (status) {
 580                warn_no_callback_path(clp, status);
 581                return;
 582        }
 583
 584        /* the task holds a reference to the nfs4_client struct */
 585        atomic_inc(&clp->cl_count);
 586
 587        do_probe_callback(clp);
 588}
 589
 590/*
 591 * There's currently a single callback channel slot.
 592 * If the slot is available, then mark it busy.  Otherwise, set the
 593 * thread for sleeping on the callback RPC wait queue.
 594 */
 595static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
 596                struct rpc_task *task)
 597{
 598        struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
 599        u32 *ptr = (u32 *)clp->cl_sessionid.data;
 600        int status = 0;
 601
 602        dprintk("%s: %u:%u:%u:%u\n", __func__,
 603                ptr[0], ptr[1], ptr[2], ptr[3]);
 604
 605        if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
 606                rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
 607                dprintk("%s slot is busy\n", __func__);
 608                status = -EAGAIN;
 609                goto out;
 610        }
 611
 612        /*
 613         * We'll need the clp during XDR encoding and decoding,
 614         * and the sequence during decoding to verify the reply
 615         */
 616        args->args_seq.cbs_clp = clp;
 617        task->tk_msg.rpc_resp = &args->args_seq;
 618
 619out:
 620        dprintk("%s status=%d\n", __func__, status);
 621        return status;
 622}
 623
 624/*
 625 * TODO: cb_sequence should support referring call lists, cachethis, multiple
 626 * slots, and mark callback channel down on communication errors.
 627 */
 628static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
 629{
 630        struct nfs4_delegation *dp = calldata;
 631        struct nfs4_client *clp = dp->dl_client;
 632        struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
 633        u32 minorversion = clp->cl_cb_conn.cb_minorversion;
 634        int status = 0;
 635
 636        args->args_seq.cbs_minorversion = minorversion;
 637        if (minorversion) {
 638                status = nfsd41_cb_setup_sequence(clp, task);
 639                if (status) {
 640                        if (status != -EAGAIN) {
 641                                /* terminate rpc task */
 642                                task->tk_status = status;
 643                                task->tk_action = NULL;
 644                        }
 645                        return;
 646                }
 647        }
 648        rpc_call_start(task);
 649}
 650
 651static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
 652{
 653        struct nfs4_delegation *dp = calldata;
 654        struct nfs4_client *clp = dp->dl_client;
 655
 656        dprintk("%s: minorversion=%d\n", __func__,
 657                clp->cl_cb_conn.cb_minorversion);
 658
 659        if (clp->cl_cb_conn.cb_minorversion) {
 660                /* No need for lock, access serialized in nfsd4_cb_prepare */
 661                ++clp->cl_cb_seq_nr;
 662                clear_bit(0, &clp->cl_cb_slot_busy);
 663                rpc_wake_up_next(&clp->cl_cb_waitq);
 664                dprintk("%s: freed slot, new seqid=%d\n", __func__,
 665                        clp->cl_cb_seq_nr);
 666
 667                /* We're done looking into the sequence information */
 668                task->tk_msg.rpc_resp = NULL;
 669        }
 670}
 671
 672static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
 673{
 674        struct nfs4_delegation *dp = calldata;
 675        struct nfs4_client *clp = dp->dl_client;
 676
 677        nfsd4_cb_done(task, calldata);
 678
 679        switch (task->tk_status) {
 680        case -EIO:
 681                /* Network partition? */
 682                atomic_set(&clp->cl_cb_conn.cb_set, 0);
 683                warn_no_callback_path(clp, task->tk_status);
 684        case -EBADHANDLE:
 685        case -NFS4ERR_BAD_STATEID:
 686                /* Race: client probably got cb_recall
 687                 * before open reply granting delegation */
 688                break;
 689        default:
 690                /* success, or error we can't handle */
 691                goto done;
 692        }
 693        if (dp->dl_retries--) {
 694                rpc_delay(task, 2*HZ);
 695                task->tk_status = 0;
 696                rpc_restart_call(task);
 697                return;
 698        } else {
 699                atomic_set(&clp->cl_cb_conn.cb_set, 0);
 700                warn_no_callback_path(clp, task->tk_status);
 701        }
 702done:
 703        kfree(task->tk_msg.rpc_argp);
 704}
 705
 706static void nfsd4_cb_recall_release(void *calldata)
 707{
 708        struct nfs4_delegation *dp = calldata;
 709        struct nfs4_client *clp = dp->dl_client;
 710
 711        nfs4_put_delegation(dp);
 712        put_nfs4_client(clp);
 713}
 714
 715static const struct rpc_call_ops nfsd4_cb_recall_ops = {
 716        .rpc_call_prepare = nfsd4_cb_prepare,
 717        .rpc_call_done = nfsd4_cb_recall_done,
 718        .rpc_release = nfsd4_cb_recall_release,
 719};
 720
 721/*
 722 * called with dp->dl_count inc'ed.
 723 */
 724void
 725nfsd4_cb_recall(struct nfs4_delegation *dp)
 726{
 727        struct nfs4_client *clp = dp->dl_client;
 728        struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client;
 729        struct nfs4_rpc_args *args;
 730        struct rpc_message msg = {
 731                .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
 732                .rpc_cred = callback_cred
 733        };
 734        int status = -ENOMEM;
 735
 736        args = kzalloc(sizeof(*args), GFP_KERNEL);
 737        if (!args)
 738                goto out;
 739        args->args_op = dp;
 740        msg.rpc_argp = args;
 741        dp->dl_retries = 1;
 742        status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
 743                                &nfsd4_cb_recall_ops, dp);
 744out:
 745        if (status) {
 746                kfree(args);
 747                put_nfs4_client(clp);
 748                nfs4_put_delegation(dp);
 749        }
 750}
 751