linux/fs/nfs/callback_proc.c
<<
>>
Prefs
   1/*
   2 * linux/fs/nfs/callback_proc.c
   3 *
   4 * Copyright (C) 2004 Trond Myklebust
   5 *
   6 * NFSv4 callback procedures
   7 */
   8#include <linux/nfs4.h>
   9#include <linux/nfs_fs.h>
  10#include <linux/slab.h>
  11#include <linux/rcupdate.h>
  12#include "nfs4_fs.h"
  13#include "callback.h"
  14#include "delegation.h"
  15#include "internal.h"
  16#include "pnfs.h"
  17#include "nfs4session.h"
  18#include "nfs4trace.h"
  19
  20#define NFSDBG_FACILITY NFSDBG_CALLBACK
  21
  22__be32 nfs4_callback_getattr(struct cb_getattrargs *args,
  23                             struct cb_getattrres *res,
  24                             struct cb_process_state *cps)
  25{
  26        struct nfs_delegation *delegation;
  27        struct nfs_inode *nfsi;
  28        struct inode *inode;
  29
  30        res->status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
  31        if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
  32                goto out;
  33
  34        res->bitmap[0] = res->bitmap[1] = 0;
  35        res->status = htonl(NFS4ERR_BADHANDLE);
  36
  37        dprintk_rcu("NFS: GETATTR callback request from %s\n",
  38                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
  39
  40        inode = nfs_delegation_find_inode(cps->clp, &args->fh);
  41        if (inode == NULL) {
  42                trace_nfs4_cb_getattr(cps->clp, &args->fh, NULL,
  43                                -ntohl(res->status));
  44                goto out;
  45        }
  46        nfsi = NFS_I(inode);
  47        rcu_read_lock();
  48        delegation = rcu_dereference(nfsi->delegation);
  49        if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
  50                goto out_iput;
  51        res->size = i_size_read(inode);
  52        res->change_attr = delegation->change_attr;
  53        if (nfsi->nrequests != 0)
  54                res->change_attr++;
  55        res->ctime = inode->i_ctime;
  56        res->mtime = inode->i_mtime;
  57        res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
  58                args->bitmap[0];
  59        res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
  60                args->bitmap[1];
  61        res->status = 0;
  62out_iput:
  63        rcu_read_unlock();
  64        trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status));
  65        iput(inode);
  66out:
  67        dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
  68        return res->status;
  69}
  70
  71__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
  72                            struct cb_process_state *cps)
  73{
  74        struct inode *inode;
  75        __be32 res;
  76        
  77        res = htonl(NFS4ERR_OP_NOT_IN_SESSION);
  78        if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
  79                goto out;
  80
  81        dprintk_rcu("NFS: RECALL callback request from %s\n",
  82                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
  83
  84        res = htonl(NFS4ERR_BADHANDLE);
  85        inode = nfs_delegation_find_inode(cps->clp, &args->fh);
  86        if (inode == NULL) {
  87                trace_nfs4_cb_recall(cps->clp, &args->fh, NULL,
  88                                &args->stateid, -ntohl(res));
  89                goto out;
  90        }
  91        /* Set up a helper thread to actually return the delegation */
  92        switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
  93        case 0:
  94                res = 0;
  95                break;
  96        case -ENOENT:
  97                res = htonl(NFS4ERR_BAD_STATEID);
  98                break;
  99        default:
 100                res = htonl(NFS4ERR_RESOURCE);
 101        }
 102        trace_nfs4_cb_recall(cps->clp, &args->fh, inode,
 103                        &args->stateid, -ntohl(res));
 104        iput(inode);
 105out:
 106        dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
 107        return res;
 108}
 109
 110#if defined(CONFIG_NFS_V4_1)
 111
 112/*
 113 * Lookup a layout inode by stateid
 114 *
 115 * Note: returns a refcount on the inode and superblock
 116 */
 117static struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp,
 118                const nfs4_stateid *stateid)
 119{
 120        struct nfs_server *server;
 121        struct inode *inode;
 122        struct pnfs_layout_hdr *lo;
 123
 124restart:
 125        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 126                list_for_each_entry(lo, &server->layouts, plh_layouts) {
 127                        if (stateid != NULL &&
 128                            !nfs4_stateid_match_other(stateid, &lo->plh_stateid))
 129                                continue;
 130                        inode = igrab(lo->plh_inode);
 131                        if (!inode)
 132                                continue;
 133                        if (!nfs_sb_active(inode->i_sb)) {
 134                                rcu_read_lock();
 135                                spin_unlock(&clp->cl_lock);
 136                                iput(inode);
 137                                spin_lock(&clp->cl_lock);
 138                                goto restart;
 139                        }
 140                        return inode;
 141                }
 142        }
 143
 144        return NULL;
 145}
 146
 147/*
 148 * Lookup a layout inode by filehandle.
 149 *
 150 * Note: returns a refcount on the inode and superblock
 151 *
 152 */
 153static struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp,
 154                const struct nfs_fh *fh)
 155{
 156        struct nfs_server *server;
 157        struct nfs_inode *nfsi;
 158        struct inode *inode;
 159        struct pnfs_layout_hdr *lo;
 160
 161restart:
 162        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
 163                list_for_each_entry(lo, &server->layouts, plh_layouts) {
 164                        nfsi = NFS_I(lo->plh_inode);
 165                        if (nfs_compare_fh(fh, &nfsi->fh))
 166                                continue;
 167                        if (nfsi->layout != lo)
 168                                continue;
 169                        inode = igrab(lo->plh_inode);
 170                        if (!inode)
 171                                continue;
 172                        if (!nfs_sb_active(inode->i_sb)) {
 173                                rcu_read_lock();
 174                                spin_unlock(&clp->cl_lock);
 175                                iput(inode);
 176                                spin_lock(&clp->cl_lock);
 177                                goto restart;
 178                        }
 179                        return inode;
 180                }
 181        }
 182
 183        return NULL;
 184}
 185
 186static struct inode *nfs_layout_find_inode(struct nfs_client *clp,
 187                const struct nfs_fh *fh,
 188                const nfs4_stateid *stateid)
 189{
 190        struct inode *inode;
 191
 192        spin_lock(&clp->cl_lock);
 193        rcu_read_lock();
 194        inode = nfs_layout_find_inode_by_stateid(clp, stateid);
 195        if (!inode)
 196                inode = nfs_layout_find_inode_by_fh(clp, fh);
 197        rcu_read_unlock();
 198        spin_unlock(&clp->cl_lock);
 199
 200        return inode;
 201}
 202
 203/*
 204 * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing)
 205 */
 206static u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo,
 207                                        const nfs4_stateid *new)
 208{
 209        u32 oldseq, newseq;
 210
 211        /* Is the stateid still not initialised? */
 212        if (!pnfs_layout_is_valid(lo))
 213                return NFS4ERR_DELAY;
 214
 215        /* Mismatched stateid? */
 216        if (!nfs4_stateid_match_other(&lo->plh_stateid, new))
 217                return NFS4ERR_BAD_STATEID;
 218
 219        newseq = be32_to_cpu(new->seqid);
 220        /* Are we already in a layout recall situation? */
 221        if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) &&
 222            lo->plh_return_seq != 0) {
 223                if (newseq < lo->plh_return_seq)
 224                        return NFS4ERR_OLD_STATEID;
 225                if (newseq > lo->plh_return_seq)
 226                        return NFS4ERR_DELAY;
 227                goto out;
 228        }
 229
 230        /* Check that the stateid matches what we think it should be. */
 231        oldseq = be32_to_cpu(lo->plh_stateid.seqid);
 232        if (newseq > oldseq + 1)
 233                return NFS4ERR_DELAY;
 234        /* Crazy server! */
 235        if (newseq <= oldseq)
 236                return NFS4ERR_OLD_STATEID;
 237out:
 238        return NFS_OK;
 239}
 240
 241static u32 initiate_file_draining(struct nfs_client *clp,
 242                                  struct cb_layoutrecallargs *args)
 243{
 244        struct inode *ino;
 245        struct pnfs_layout_hdr *lo;
 246        u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
 247        LIST_HEAD(free_me_list);
 248
 249        ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid);
 250        if (!ino)
 251                goto out;
 252
 253        pnfs_layoutcommit_inode(ino, false);
 254
 255
 256        spin_lock(&ino->i_lock);
 257        lo = NFS_I(ino)->layout;
 258        if (!lo) {
 259                spin_unlock(&ino->i_lock);
 260                goto out;
 261        }
 262        pnfs_get_layout_hdr(lo);
 263        rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid);
 264        if (rv != NFS_OK)
 265                goto unlock;
 266        pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
 267
 268        /*
 269         * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return)
 270         */
 271        if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
 272                rv = NFS4ERR_DELAY;
 273                goto unlock;
 274        }
 275
 276        if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
 277                                &args->cbl_range,
 278                                be32_to_cpu(args->cbl_stateid.seqid))) {
 279                rv = NFS4_OK;
 280                goto unlock;
 281        }
 282
 283        /* Embrace your forgetfulness! */
 284        rv = NFS4ERR_NOMATCHING_LAYOUT;
 285
 286        if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
 287                NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
 288                        &args->cbl_range);
 289        }
 290unlock:
 291        spin_unlock(&ino->i_lock);
 292        pnfs_free_lseg_list(&free_me_list);
 293        /* Free all lsegs that are attached to commit buckets */
 294        nfs_commit_inode(ino, 0);
 295        pnfs_put_layout_hdr(lo);
 296out:
 297        trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
 298                        &args->cbl_stateid, -rv);
 299        nfs_iput_and_deactive(ino);
 300        return rv;
 301}
 302
 303static u32 initiate_bulk_draining(struct nfs_client *clp,
 304                                  struct cb_layoutrecallargs *args)
 305{
 306        int stat;
 307
 308        if (args->cbl_recall_type == RETURN_FSID)
 309                stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true);
 310        else
 311                stat = pnfs_destroy_layouts_byclid(clp, true);
 312        if (stat != 0)
 313                return NFS4ERR_DELAY;
 314        return NFS4ERR_NOMATCHING_LAYOUT;
 315}
 316
 317static u32 do_callback_layoutrecall(struct nfs_client *clp,
 318                                    struct cb_layoutrecallargs *args)
 319{
 320        u32 res;
 321
 322        dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type);
 323        if (args->cbl_recall_type == RETURN_FILE)
 324                res = initiate_file_draining(clp, args);
 325        else
 326                res = initiate_bulk_draining(clp, args);
 327        dprintk("%s returning %i\n", __func__, res);
 328        return res;
 329
 330}
 331
 332__be32 nfs4_callback_layoutrecall(struct cb_layoutrecallargs *args,
 333                                  void *dummy, struct cb_process_state *cps)
 334{
 335        u32 res;
 336
 337        dprintk("%s: -->\n", __func__);
 338
 339        if (cps->clp)
 340                res = do_callback_layoutrecall(cps->clp, args);
 341        else
 342                res = NFS4ERR_OP_NOT_IN_SESSION;
 343
 344        dprintk("%s: exit with status = %d\n", __func__, res);
 345        return cpu_to_be32(res);
 346}
 347
 348static void pnfs_recall_all_layouts(struct nfs_client *clp)
 349{
 350        struct cb_layoutrecallargs args;
 351
 352        /* Pretend we got a CB_LAYOUTRECALL(ALL) */
 353        memset(&args, 0, sizeof(args));
 354        args.cbl_recall_type = RETURN_ALL;
 355        /* FIXME we ignore errors, what should we do? */
 356        do_callback_layoutrecall(clp, &args);
 357}
 358
 359__be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
 360                                  void *dummy, struct cb_process_state *cps)
 361{
 362        int i;
 363        __be32 res = 0;
 364        struct nfs_client *clp = cps->clp;
 365        struct nfs_server *server = NULL;
 366
 367        dprintk("%s: -->\n", __func__);
 368
 369        if (!clp) {
 370                res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
 371                goto out;
 372        }
 373
 374        for (i = 0; i < args->ndevs; i++) {
 375                struct cb_devicenotifyitem *dev = &args->devs[i];
 376
 377                if (!server ||
 378                    server->pnfs_curr_ld->id != dev->cbd_layout_type) {
 379                        rcu_read_lock();
 380                        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
 381                                if (server->pnfs_curr_ld &&
 382                                    server->pnfs_curr_ld->id == dev->cbd_layout_type) {
 383                                        rcu_read_unlock();
 384                                        goto found;
 385                                }
 386                        rcu_read_unlock();
 387                        dprintk("%s: layout type %u not found\n",
 388                                __func__, dev->cbd_layout_type);
 389                        continue;
 390                }
 391
 392        found:
 393                nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
 394        }
 395
 396out:
 397        kfree(args->devs);
 398        dprintk("%s: exit with status = %u\n",
 399                __func__, be32_to_cpu(res));
 400        return res;
 401}
 402
 403/*
 404 * Validate the sequenceID sent by the server.
 405 * Return success if the sequenceID is one more than what we last saw on
 406 * this slot, accounting for wraparound.  Increments the slot's sequence.
 407 *
 408 * We don't yet implement a duplicate request cache, instead we set the
 409 * back channel ca_maxresponsesize_cached to zero. This is OK for now
 410 * since we only currently implement idempotent callbacks anyway.
 411 *
 412 * We have a single slot backchannel at this time, so we don't bother
 413 * checking the used_slots bit array on the table.  The lower layer guarantees
 414 * a single outstanding callback request at a time.
 415 */
 416static __be32
 417validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
 418                const struct cb_sequenceargs * args)
 419{
 420        dprintk("%s enter. slotid %u seqid %u, slot table seqid: %u\n",
 421                __func__, args->csa_slotid, args->csa_sequenceid, slot->seq_nr);
 422
 423        if (args->csa_slotid > tbl->server_highest_slotid)
 424                return htonl(NFS4ERR_BADSLOT);
 425
 426        /* Replay */
 427        if (args->csa_sequenceid == slot->seq_nr) {
 428                dprintk("%s seqid %u is a replay\n",
 429                        __func__, args->csa_sequenceid);
 430                if (nfs4_test_locked_slot(tbl, slot->slot_nr))
 431                        return htonl(NFS4ERR_DELAY);
 432                /* Signal process_op to set this error on next op */
 433                if (args->csa_cachethis == 0)
 434                        return htonl(NFS4ERR_RETRY_UNCACHED_REP);
 435
 436                /* Liar! We never allowed you to set csa_cachethis != 0 */
 437                return htonl(NFS4ERR_SEQ_FALSE_RETRY);
 438        }
 439
 440        /* Wraparound */
 441        if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) {
 442                if (args->csa_sequenceid == 1)
 443                        return htonl(NFS4_OK);
 444        } else if (likely(args->csa_sequenceid == slot->seq_nr + 1))
 445                return htonl(NFS4_OK);
 446
 447        /* Misordered request */
 448        return htonl(NFS4ERR_SEQ_MISORDERED);
 449}
 450
 451/*
 452 * For each referring call triple, check the session's slot table for
 453 * a match.  If the slot is in use and the sequence numbers match, the
 454 * client is still waiting for a response to the original request.
 455 */
 456static bool referring_call_exists(struct nfs_client *clp,
 457                                  uint32_t nrclists,
 458                                  struct referring_call_list *rclists)
 459{
 460        bool status = 0;
 461        int i, j;
 462        struct nfs4_session *session;
 463        struct nfs4_slot_table *tbl;
 464        struct referring_call_list *rclist;
 465        struct referring_call *ref;
 466
 467        /*
 468         * XXX When client trunking is implemented, this becomes
 469         * a session lookup from within the loop
 470         */
 471        session = clp->cl_session;
 472        tbl = &session->fc_slot_table;
 473
 474        for (i = 0; i < nrclists; i++) {
 475                rclist = &rclists[i];
 476                if (memcmp(session->sess_id.data,
 477                           rclist->rcl_sessionid.data,
 478                           NFS4_MAX_SESSIONID_LEN) != 0)
 479                        continue;
 480
 481                for (j = 0; j < rclist->rcl_nrefcalls; j++) {
 482                        ref = &rclist->rcl_refcalls[j];
 483
 484                        dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u "
 485                                "slotid %u\n", __func__,
 486                                ((u32 *)&rclist->rcl_sessionid.data)[0],
 487                                ((u32 *)&rclist->rcl_sessionid.data)[1],
 488                                ((u32 *)&rclist->rcl_sessionid.data)[2],
 489                                ((u32 *)&rclist->rcl_sessionid.data)[3],
 490                                ref->rc_sequenceid, ref->rc_slotid);
 491
 492                        status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid,
 493                                        ref->rc_sequenceid, HZ >> 1) < 0;
 494                        if (status)
 495                                goto out;
 496                }
 497        }
 498
 499out:
 500        return status;
 501}
 502
 503__be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
 504                              struct cb_sequenceres *res,
 505                              struct cb_process_state *cps)
 506{
 507        struct nfs4_slot_table *tbl;
 508        struct nfs4_slot *slot;
 509        struct nfs_client *clp;
 510        int i;
 511        __be32 status = htonl(NFS4ERR_BADSESSION);
 512
 513        clp = nfs4_find_client_sessionid(cps->net, args->csa_addr,
 514                                         &args->csa_sessionid, cps->minorversion);
 515        if (clp == NULL)
 516                goto out;
 517
 518        if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
 519                goto out;
 520
 521        tbl = &clp->cl_session->bc_slot_table;
 522
 523        /* Set up res before grabbing the spinlock */
 524        memcpy(&res->csr_sessionid, &args->csa_sessionid,
 525               sizeof(res->csr_sessionid));
 526        res->csr_sequenceid = args->csa_sequenceid;
 527        res->csr_slotid = args->csa_slotid;
 528
 529        spin_lock(&tbl->slot_tbl_lock);
 530        /* state manager is resetting the session */
 531        if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
 532                status = htonl(NFS4ERR_DELAY);
 533                /* Return NFS4ERR_BADSESSION if we're draining the session
 534                 * in order to reset it.
 535                 */
 536                if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
 537                        status = htonl(NFS4ERR_BADSESSION);
 538                goto out_unlock;
 539        }
 540
 541        status = htonl(NFS4ERR_BADSLOT);
 542        slot = nfs4_lookup_slot(tbl, args->csa_slotid);
 543        if (IS_ERR(slot))
 544                goto out_unlock;
 545
 546        res->csr_highestslotid = tbl->server_highest_slotid;
 547        res->csr_target_highestslotid = tbl->target_highest_slotid;
 548
 549        status = validate_seqid(tbl, slot, args);
 550        if (status)
 551                goto out_unlock;
 552        if (!nfs4_try_to_lock_slot(tbl, slot)) {
 553                status = htonl(NFS4ERR_DELAY);
 554                goto out_unlock;
 555        }
 556        cps->slot = slot;
 557
 558        /* The ca_maxresponsesize_cached is 0 with no DRC */
 559        if (args->csa_cachethis != 0) {
 560                status = htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
 561                goto out_unlock;
 562        }
 563
 564        /*
 565         * Check for pending referring calls.  If a match is found, a
 566         * related callback was received before the response to the original
 567         * call.
 568         */
 569        if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
 570                status = htonl(NFS4ERR_DELAY);
 571                goto out_unlock;
 572        }
 573
 574        /*
 575         * RFC5661 20.9.3
 576         * If CB_SEQUENCE returns an error, then the state of the slot
 577         * (sequence ID, cached reply) MUST NOT change.
 578         */
 579        slot->seq_nr = args->csa_sequenceid;
 580out_unlock:
 581        spin_unlock(&tbl->slot_tbl_lock);
 582
 583out:
 584        cps->clp = clp; /* put in nfs4_callback_compound */
 585        for (i = 0; i < args->csa_nrclists; i++)
 586                kfree(args->csa_rclists[i].rcl_refcalls);
 587        kfree(args->csa_rclists);
 588
 589        if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) {
 590                cps->drc_status = status;
 591                status = 0;
 592        } else
 593                res->csr_status = status;
 594
 595        trace_nfs4_cb_sequence(args, res, status);
 596        dprintk("%s: exit with status = %d res->csr_status %d\n", __func__,
 597                ntohl(status), ntohl(res->csr_status));
 598        return status;
 599}
 600
 601static bool
 602validate_bitmap_values(unsigned long mask)
 603{
 604        return (mask & ~RCA4_TYPE_MASK_ALL) == 0;
 605}
 606
 607__be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
 608                               struct cb_process_state *cps)
 609{
 610        __be32 status;
 611        fmode_t flags = 0;
 612
 613        status = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
 614        if (!cps->clp) /* set in cb_sequence */
 615                goto out;
 616
 617        dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
 618                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 619
 620        status = cpu_to_be32(NFS4ERR_INVAL);
 621        if (!validate_bitmap_values(args->craa_type_mask))
 622                goto out;
 623
 624        status = cpu_to_be32(NFS4_OK);
 625        if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
 626                     &args->craa_type_mask))
 627                flags = FMODE_READ;
 628        if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
 629                     &args->craa_type_mask))
 630                flags |= FMODE_WRITE;
 631        if (test_bit(RCA4_TYPE_MASK_FILE_LAYOUT, (const unsigned long *)
 632                     &args->craa_type_mask))
 633                pnfs_recall_all_layouts(cps->clp);
 634        if (flags)
 635                nfs_expire_unused_delegation_types(cps->clp, flags);
 636out:
 637        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 638        return status;
 639}
 640
 641/* Reduce the fore channel's max_slots to the target value */
 642__be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
 643                                struct cb_process_state *cps)
 644{
 645        struct nfs4_slot_table *fc_tbl;
 646        __be32 status;
 647
 648        status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
 649        if (!cps->clp) /* set in cb_sequence */
 650                goto out;
 651
 652        dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %u\n",
 653                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
 654                args->crsa_target_highest_slotid);
 655
 656        fc_tbl = &cps->clp->cl_session->fc_slot_table;
 657
 658        status = htonl(NFS4_OK);
 659
 660        nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid);
 661        nfs41_notify_server(cps->clp);
 662out:
 663        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
 664        return status;
 665}
 666
 667__be32 nfs4_callback_notify_lock(struct cb_notify_lock_args *args, void *dummy,
 668                                 struct cb_process_state *cps)
 669{
 670        if (!cps->clp) /* set in cb_sequence */
 671                return htonl(NFS4ERR_OP_NOT_IN_SESSION);
 672
 673        dprintk_rcu("NFS: CB_NOTIFY_LOCK request from %s\n",
 674                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
 675
 676        /* Don't wake anybody if the string looked bogus */
 677        if (args->cbnl_valid)
 678                __wake_up(&cps->clp->cl_lock_waitq, TASK_NORMAL, 0, args);
 679
 680        return htonl(NFS4_OK);
 681}
 682#endif /* CONFIG_NFS_V4_1 */
 683