0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/errno.h>
0011 #include <linux/math.h>
0012 #include <linux/nfs4.h>
0013 #include <linux/nfs_fs.h>
0014 #include <linux/slab.h>
0015 #include <linux/rcupdate.h>
0016 #include <linux/types.h>
0017
0018 #include "nfs4_fs.h"
0019 #include "callback.h"
0020 #include "delegation.h"
0021 #include "internal.h"
0022 #include "pnfs.h"
0023 #include "nfs4session.h"
0024 #include "nfs4trace.h"
0025
0026 #define NFSDBG_FACILITY NFSDBG_CALLBACK
0027
0028 __be32 nfs4_callback_getattr(void *argp, void *resp,
0029 struct cb_process_state *cps)
0030 {
0031 struct cb_getattrargs *args = argp;
0032 struct cb_getattrres *res = resp;
0033 struct nfs_delegation *delegation;
0034 struct inode *inode;
0035
0036 res->status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
0037 if (!cps->clp)
0038 goto out;
0039
0040 res->bitmap[0] = res->bitmap[1] = 0;
0041 res->status = htonl(NFS4ERR_BADHANDLE);
0042
0043 dprintk_rcu("NFS: GETATTR callback request from %s\n",
0044 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
0045
0046 inode = nfs_delegation_find_inode(cps->clp, &args->fh);
0047 if (IS_ERR(inode)) {
0048 if (inode == ERR_PTR(-EAGAIN))
0049 res->status = htonl(NFS4ERR_DELAY);
0050 trace_nfs4_cb_getattr(cps->clp, &args->fh, NULL,
0051 -ntohl(res->status));
0052 goto out;
0053 }
0054 rcu_read_lock();
0055 delegation = nfs4_get_valid_delegation(inode);
0056 if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
0057 goto out_iput;
0058 res->size = i_size_read(inode);
0059 res->change_attr = delegation->change_attr;
0060 if (nfs_have_writebacks(inode))
0061 res->change_attr++;
0062 res->ctime = inode->i_ctime;
0063 res->mtime = inode->i_mtime;
0064 res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
0065 args->bitmap[0];
0066 res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
0067 args->bitmap[1];
0068 res->status = 0;
0069 out_iput:
0070 rcu_read_unlock();
0071 trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status));
0072 nfs_iput_and_deactive(inode);
0073 out:
0074 dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
0075 return res->status;
0076 }
0077
0078 __be32 nfs4_callback_recall(void *argp, void *resp,
0079 struct cb_process_state *cps)
0080 {
0081 struct cb_recallargs *args = argp;
0082 struct inode *inode;
0083 __be32 res;
0084
0085 res = htonl(NFS4ERR_OP_NOT_IN_SESSION);
0086 if (!cps->clp)
0087 goto out;
0088
0089 dprintk_rcu("NFS: RECALL callback request from %s\n",
0090 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
0091
0092 res = htonl(NFS4ERR_BADHANDLE);
0093 inode = nfs_delegation_find_inode(cps->clp, &args->fh);
0094 if (IS_ERR(inode)) {
0095 if (inode == ERR_PTR(-EAGAIN))
0096 res = htonl(NFS4ERR_DELAY);
0097 trace_nfs4_cb_recall(cps->clp, &args->fh, NULL,
0098 &args->stateid, -ntohl(res));
0099 goto out;
0100 }
0101
0102 switch (nfs_async_inode_return_delegation(inode, &args->stateid)) {
0103 case 0:
0104 res = 0;
0105 break;
0106 case -ENOENT:
0107 res = htonl(NFS4ERR_BAD_STATEID);
0108 break;
0109 default:
0110 res = htonl(NFS4ERR_RESOURCE);
0111 }
0112 trace_nfs4_cb_recall(cps->clp, &args->fh, inode,
0113 &args->stateid, -ntohl(res));
0114 nfs_iput_and_deactive(inode);
0115 out:
0116 dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
0117 return res;
0118 }
0119
0120 #if defined(CONFIG_NFS_V4_1)
0121
0122
0123
0124
0125
0126
0127 static struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp,
0128 const nfs4_stateid *stateid)
0129 __must_hold(RCU)
0130 {
0131 struct nfs_server *server;
0132 struct inode *inode;
0133 struct pnfs_layout_hdr *lo;
0134
0135 rcu_read_lock();
0136 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
0137 list_for_each_entry_rcu(lo, &server->layouts, plh_layouts) {
0138 if (!pnfs_layout_is_valid(lo))
0139 continue;
0140 if (!nfs4_stateid_match_other(stateid, &lo->plh_stateid))
0141 continue;
0142 if (nfs_sb_active(server->super))
0143 inode = igrab(lo->plh_inode);
0144 else
0145 inode = ERR_PTR(-EAGAIN);
0146 rcu_read_unlock();
0147 if (inode)
0148 return inode;
0149 nfs_sb_deactive(server->super);
0150 return ERR_PTR(-EAGAIN);
0151 }
0152 }
0153 rcu_read_unlock();
0154 return ERR_PTR(-ENOENT);
0155 }
0156
0157
0158
0159
0160
0161
0162
0163 static struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp,
0164 const struct nfs_fh *fh)
0165 {
0166 struct nfs_server *server;
0167 struct nfs_inode *nfsi;
0168 struct inode *inode;
0169 struct pnfs_layout_hdr *lo;
0170
0171 rcu_read_lock();
0172 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
0173 list_for_each_entry_rcu(lo, &server->layouts, plh_layouts) {
0174 nfsi = NFS_I(lo->plh_inode);
0175 if (nfs_compare_fh(fh, &nfsi->fh))
0176 continue;
0177 if (nfsi->layout != lo)
0178 continue;
0179 if (nfs_sb_active(server->super))
0180 inode = igrab(lo->plh_inode);
0181 else
0182 inode = ERR_PTR(-EAGAIN);
0183 rcu_read_unlock();
0184 if (inode)
0185 return inode;
0186 nfs_sb_deactive(server->super);
0187 return ERR_PTR(-EAGAIN);
0188 }
0189 }
0190 rcu_read_unlock();
0191 return ERR_PTR(-ENOENT);
0192 }
0193
0194 static struct inode *nfs_layout_find_inode(struct nfs_client *clp,
0195 const struct nfs_fh *fh,
0196 const nfs4_stateid *stateid)
0197 {
0198 struct inode *inode;
0199
0200 inode = nfs_layout_find_inode_by_stateid(clp, stateid);
0201 if (inode == ERR_PTR(-ENOENT))
0202 inode = nfs_layout_find_inode_by_fh(clp, fh);
0203 return inode;
0204 }
0205
0206
0207
0208
0209 static u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo,
0210 const nfs4_stateid *new)
0211 {
0212 u32 oldseq, newseq;
0213
0214
0215 if (!pnfs_layout_is_valid(lo))
0216 return NFS4ERR_NOMATCHING_LAYOUT;
0217
0218
0219 if (!nfs4_stateid_match_other(&lo->plh_stateid, new))
0220 return NFS4ERR_BAD_STATEID;
0221
0222 newseq = be32_to_cpu(new->seqid);
0223
0224 if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) &&
0225 lo->plh_return_seq != 0) {
0226 if (newseq < lo->plh_return_seq)
0227 return NFS4ERR_OLD_STATEID;
0228 if (newseq > lo->plh_return_seq)
0229 return NFS4ERR_DELAY;
0230 goto out;
0231 }
0232
0233
0234 oldseq = be32_to_cpu(lo->plh_stateid.seqid);
0235 if (newseq > oldseq + 1)
0236 return NFS4ERR_DELAY;
0237
0238 if (newseq <= oldseq)
0239 return NFS4ERR_OLD_STATEID;
0240 out:
0241 return NFS_OK;
0242 }
0243
0244 static u32 initiate_file_draining(struct nfs_client *clp,
0245 struct cb_layoutrecallargs *args)
0246 {
0247 struct inode *ino;
0248 struct pnfs_layout_hdr *lo;
0249 u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
0250 LIST_HEAD(free_me_list);
0251
0252 ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid);
0253 if (IS_ERR(ino)) {
0254 if (ino == ERR_PTR(-EAGAIN))
0255 rv = NFS4ERR_DELAY;
0256 goto out_noput;
0257 }
0258
0259 pnfs_layoutcommit_inode(ino, false);
0260
0261
0262 spin_lock(&ino->i_lock);
0263 lo = NFS_I(ino)->layout;
0264 if (!lo) {
0265 spin_unlock(&ino->i_lock);
0266 goto out;
0267 }
0268 pnfs_get_layout_hdr(lo);
0269 rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid);
0270 if (rv != NFS_OK)
0271 goto unlock;
0272
0273
0274
0275
0276 if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
0277 rv = NFS4ERR_DELAY;
0278 goto unlock;
0279 }
0280
0281 pnfs_set_layout_stateid(lo, &args->cbl_stateid, NULL, true);
0282 switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
0283 &args->cbl_range,
0284 be32_to_cpu(args->cbl_stateid.seqid))) {
0285 case 0:
0286 case -EBUSY:
0287
0288 rv = NFS4_OK;
0289 break;
0290 case -ENOENT:
0291 set_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags);
0292
0293 rv = NFS4ERR_NOMATCHING_LAYOUT;
0294
0295 if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
0296 NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
0297 &args->cbl_range);
0298 }
0299 }
0300 unlock:
0301 spin_unlock(&ino->i_lock);
0302 pnfs_free_lseg_list(&free_me_list);
0303
0304 nfs_commit_inode(ino, 0);
0305 pnfs_put_layout_hdr(lo);
0306 out:
0307 nfs_iput_and_deactive(ino);
0308 out_noput:
0309 trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
0310 &args->cbl_stateid, -rv);
0311 return rv;
0312 }
0313
0314 static u32 initiate_bulk_draining(struct nfs_client *clp,
0315 struct cb_layoutrecallargs *args)
0316 {
0317 int stat;
0318
0319 if (args->cbl_recall_type == RETURN_FSID)
0320 stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true);
0321 else
0322 stat = pnfs_destroy_layouts_byclid(clp, true);
0323 if (stat != 0)
0324 return NFS4ERR_DELAY;
0325 return NFS4ERR_NOMATCHING_LAYOUT;
0326 }
0327
0328 static u32 do_callback_layoutrecall(struct nfs_client *clp,
0329 struct cb_layoutrecallargs *args)
0330 {
0331 if (args->cbl_recall_type == RETURN_FILE)
0332 return initiate_file_draining(clp, args);
0333 return initiate_bulk_draining(clp, args);
0334 }
0335
0336 __be32 nfs4_callback_layoutrecall(void *argp, void *resp,
0337 struct cb_process_state *cps)
0338 {
0339 struct cb_layoutrecallargs *args = argp;
0340 u32 res = NFS4ERR_OP_NOT_IN_SESSION;
0341
0342 if (cps->clp)
0343 res = do_callback_layoutrecall(cps->clp, args);
0344 return cpu_to_be32(res);
0345 }
0346
0347 static void pnfs_recall_all_layouts(struct nfs_client *clp)
0348 {
0349 struct cb_layoutrecallargs args;
0350
0351
0352 memset(&args, 0, sizeof(args));
0353 args.cbl_recall_type = RETURN_ALL;
0354
0355 do_callback_layoutrecall(clp, &args);
0356 }
0357
0358 __be32 nfs4_callback_devicenotify(void *argp, void *resp,
0359 struct cb_process_state *cps)
0360 {
0361 struct cb_devicenotifyargs *args = argp;
0362 const struct pnfs_layoutdriver_type *ld = NULL;
0363 uint32_t i;
0364 __be32 res = 0;
0365
0366 if (!cps->clp) {
0367 res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
0368 goto out;
0369 }
0370
0371 for (i = 0; i < args->ndevs; i++) {
0372 struct cb_devicenotifyitem *dev = &args->devs[i];
0373
0374 if (!ld || ld->id != dev->cbd_layout_type) {
0375 pnfs_put_layoutdriver(ld);
0376 ld = pnfs_find_layoutdriver(dev->cbd_layout_type);
0377 if (!ld)
0378 continue;
0379 }
0380 nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id);
0381 }
0382 pnfs_put_layoutdriver(ld);
0383 out:
0384 kfree(args->devs);
0385 return res;
0386 }
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401 static __be32
0402 validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
0403 const struct cb_sequenceargs * args)
0404 {
0405 __be32 ret;
0406
0407 ret = cpu_to_be32(NFS4ERR_BADSLOT);
0408 if (args->csa_slotid > tbl->server_highest_slotid)
0409 goto out_err;
0410
0411
0412 if (args->csa_sequenceid == slot->seq_nr) {
0413 ret = cpu_to_be32(NFS4ERR_DELAY);
0414 if (nfs4_test_locked_slot(tbl, slot->slot_nr))
0415 goto out_err;
0416
0417
0418 ret = cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP);
0419 if (args->csa_cachethis == 0)
0420 goto out_err;
0421
0422
0423 ret = cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY);
0424 goto out_err;
0425 }
0426
0427
0428
0429 ret = cpu_to_be32(NFS4ERR_SEQ_MISORDERED);
0430 if (args->csa_sequenceid != slot->seq_nr + 1)
0431 goto out_err;
0432
0433 return cpu_to_be32(NFS4_OK);
0434
0435 out_err:
0436 trace_nfs4_cb_seqid_err(args, ret);
0437 return ret;
0438 }
0439
0440
0441
0442
0443
0444
0445 static int referring_call_exists(struct nfs_client *clp,
0446 uint32_t nrclists,
0447 struct referring_call_list *rclists,
0448 spinlock_t *lock)
0449 __releases(lock)
0450 __acquires(lock)
0451 {
0452 int status = 0;
0453 int i, j;
0454 struct nfs4_session *session;
0455 struct nfs4_slot_table *tbl;
0456 struct referring_call_list *rclist;
0457 struct referring_call *ref;
0458
0459
0460
0461
0462
0463 session = clp->cl_session;
0464 tbl = &session->fc_slot_table;
0465
0466 for (i = 0; i < nrclists; i++) {
0467 rclist = &rclists[i];
0468 if (memcmp(session->sess_id.data,
0469 rclist->rcl_sessionid.data,
0470 NFS4_MAX_SESSIONID_LEN) != 0)
0471 continue;
0472
0473 for (j = 0; j < rclist->rcl_nrefcalls; j++) {
0474 ref = &rclist->rcl_refcalls[j];
0475 spin_unlock(lock);
0476 status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid,
0477 ref->rc_sequenceid, HZ >> 1) < 0;
0478 spin_lock(lock);
0479 if (status)
0480 goto out;
0481 }
0482 }
0483
0484 out:
0485 return status;
0486 }
0487
0488 __be32 nfs4_callback_sequence(void *argp, void *resp,
0489 struct cb_process_state *cps)
0490 {
0491 struct cb_sequenceargs *args = argp;
0492 struct cb_sequenceres *res = resp;
0493 struct nfs4_slot_table *tbl;
0494 struct nfs4_slot *slot;
0495 struct nfs_client *clp;
0496 int i;
0497 __be32 status = htonl(NFS4ERR_BADSESSION);
0498
0499 clp = nfs4_find_client_sessionid(cps->net, args->csa_addr,
0500 &args->csa_sessionid, cps->minorversion);
0501 if (clp == NULL)
0502 goto out;
0503
0504 if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
0505 goto out;
0506
0507 tbl = &clp->cl_session->bc_slot_table;
0508
0509
0510 memcpy(&res->csr_sessionid, &args->csa_sessionid,
0511 sizeof(res->csr_sessionid));
0512 res->csr_sequenceid = args->csa_sequenceid;
0513 res->csr_slotid = args->csa_slotid;
0514
0515 spin_lock(&tbl->slot_tbl_lock);
0516
0517 if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
0518 status = htonl(NFS4ERR_DELAY);
0519
0520
0521
0522 if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
0523 status = htonl(NFS4ERR_BADSESSION);
0524 goto out_unlock;
0525 }
0526
0527 status = htonl(NFS4ERR_BADSLOT);
0528 slot = nfs4_lookup_slot(tbl, args->csa_slotid);
0529 if (IS_ERR(slot))
0530 goto out_unlock;
0531
0532 res->csr_highestslotid = tbl->server_highest_slotid;
0533 res->csr_target_highestslotid = tbl->target_highest_slotid;
0534
0535 status = validate_seqid(tbl, slot, args);
0536 if (status)
0537 goto out_unlock;
0538 if (!nfs4_try_to_lock_slot(tbl, slot)) {
0539 status = htonl(NFS4ERR_DELAY);
0540 goto out_unlock;
0541 }
0542 cps->slot = slot;
0543
0544
0545 if (args->csa_cachethis != 0) {
0546 status = htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
0547 goto out_unlock;
0548 }
0549
0550
0551
0552
0553
0554
0555 if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists,
0556 &tbl->slot_tbl_lock) < 0) {
0557 status = htonl(NFS4ERR_DELAY);
0558 goto out_unlock;
0559 }
0560
0561
0562
0563
0564
0565
0566 slot->seq_nr = args->csa_sequenceid;
0567 out_unlock:
0568 spin_unlock(&tbl->slot_tbl_lock);
0569
0570 out:
0571 cps->clp = clp;
0572 for (i = 0; i < args->csa_nrclists; i++)
0573 kfree(args->csa_rclists[i].rcl_refcalls);
0574 kfree(args->csa_rclists);
0575
0576 if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) {
0577 cps->drc_status = status;
0578 status = 0;
0579 } else
0580 res->csr_status = status;
0581
0582 trace_nfs4_cb_sequence(args, res, status);
0583 return status;
0584 }
0585
0586 static bool
0587 validate_bitmap_values(unsigned int mask)
0588 {
0589 return (mask & ~RCA4_TYPE_MASK_ALL) == 0;
0590 }
0591
0592 __be32 nfs4_callback_recallany(void *argp, void *resp,
0593 struct cb_process_state *cps)
0594 {
0595 struct cb_recallanyargs *args = argp;
0596 __be32 status;
0597 fmode_t flags = 0;
0598 bool schedule_manager = false;
0599
0600 status = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION);
0601 if (!cps->clp)
0602 goto out;
0603
0604 dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
0605 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
0606
0607 status = cpu_to_be32(NFS4ERR_INVAL);
0608 if (!validate_bitmap_values(args->craa_type_mask))
0609 goto out;
0610
0611 status = cpu_to_be32(NFS4_OK);
0612 if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_RDATA_DLG))
0613 flags = FMODE_READ;
0614 if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_WDATA_DLG))
0615 flags |= FMODE_WRITE;
0616 if (flags)
0617 nfs_expire_unused_delegation_types(cps->clp, flags);
0618
0619 if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_FILE_LAYOUT))
0620 pnfs_recall_all_layouts(cps->clp);
0621
0622 if (args->craa_type_mask & BIT(PNFS_FF_RCA4_TYPE_MASK_READ)) {
0623 set_bit(NFS4CLNT_RECALL_ANY_LAYOUT_READ, &cps->clp->cl_state);
0624 schedule_manager = true;
0625 }
0626 if (args->craa_type_mask & BIT(PNFS_FF_RCA4_TYPE_MASK_RW)) {
0627 set_bit(NFS4CLNT_RECALL_ANY_LAYOUT_RW, &cps->clp->cl_state);
0628 schedule_manager = true;
0629 }
0630 if (schedule_manager)
0631 nfs4_schedule_state_manager(cps->clp);
0632
0633 out:
0634 dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
0635 return status;
0636 }
0637
0638
0639 __be32 nfs4_callback_recallslot(void *argp, void *resp,
0640 struct cb_process_state *cps)
0641 {
0642 struct cb_recallslotargs *args = argp;
0643 struct nfs4_slot_table *fc_tbl;
0644 __be32 status;
0645
0646 status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
0647 if (!cps->clp)
0648 goto out;
0649
0650 dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %u\n",
0651 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
0652 args->crsa_target_highest_slotid);
0653
0654 fc_tbl = &cps->clp->cl_session->fc_slot_table;
0655
0656 status = htonl(NFS4_OK);
0657
0658 nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid);
0659 nfs41_notify_server(cps->clp);
0660 out:
0661 dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
0662 return status;
0663 }
0664
0665 __be32 nfs4_callback_notify_lock(void *argp, void *resp,
0666 struct cb_process_state *cps)
0667 {
0668 struct cb_notify_lock_args *args = argp;
0669
0670 if (!cps->clp)
0671 return htonl(NFS4ERR_OP_NOT_IN_SESSION);
0672
0673 dprintk_rcu("NFS: CB_NOTIFY_LOCK request from %s\n",
0674 rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
0675
0676
0677 if (args->cbnl_valid)
0678 __wake_up(&cps->clp->cl_lock_waitq, TASK_NORMAL, 0, args);
0679
0680 return htonl(NFS4_OK);
0681 }
0682 #endif
0683 #ifdef CONFIG_NFS_V4_2
0684 static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state,
0685 struct cb_offloadargs *args)
0686 {
0687 cp_state->count = args->wr_count;
0688 cp_state->error = args->error;
0689 if (!args->error) {
0690 cp_state->verf.committed = args->wr_writeverf.committed;
0691 memcpy(&cp_state->verf.verifier.data[0],
0692 &args->wr_writeverf.verifier.data[0],
0693 NFS4_VERIFIER_SIZE);
0694 }
0695 }
0696
0697 __be32 nfs4_callback_offload(void *data, void *dummy,
0698 struct cb_process_state *cps)
0699 {
0700 struct cb_offloadargs *args = data;
0701 struct nfs_server *server;
0702 struct nfs4_copy_state *copy, *tmp_copy;
0703 bool found = false;
0704
0705 copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL);
0706 if (!copy)
0707 return htonl(NFS4ERR_SERVERFAULT);
0708
0709 spin_lock(&cps->clp->cl_lock);
0710 rcu_read_lock();
0711 list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
0712 client_link) {
0713 list_for_each_entry(tmp_copy, &server->ss_copies, copies) {
0714 if (memcmp(args->coa_stateid.other,
0715 tmp_copy->stateid.other,
0716 sizeof(args->coa_stateid.other)))
0717 continue;
0718 nfs4_copy_cb_args(tmp_copy, args);
0719 complete(&tmp_copy->completion);
0720 found = true;
0721 goto out;
0722 }
0723 }
0724 out:
0725 rcu_read_unlock();
0726 if (!found) {
0727 memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
0728 nfs4_copy_cb_args(copy, args);
0729 list_add_tail(©->copies, &cps->clp->pending_cb_stateids);
0730 } else
0731 kfree(copy);
0732 spin_unlock(&cps->clp->cl_lock);
0733
0734 trace_nfs4_cb_offload(&args->coa_fh, &args->coa_stateid,
0735 args->wr_count, args->error,
0736 args->wr_writeverf.committed);
0737 return 0;
0738 }
0739 #endif