18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/nfs/callback_proc.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Trond Myklebust 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * NFSv4 callback procedures 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/nfs4.h> 108c2ecf20Sopenharmony_ci#include <linux/nfs_fs.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 138c2ecf20Sopenharmony_ci#include "nfs4_fs.h" 148c2ecf20Sopenharmony_ci#include "callback.h" 158c2ecf20Sopenharmony_ci#include "delegation.h" 168c2ecf20Sopenharmony_ci#include "internal.h" 178c2ecf20Sopenharmony_ci#include "pnfs.h" 188c2ecf20Sopenharmony_ci#include "nfs4session.h" 198c2ecf20Sopenharmony_ci#include "nfs4trace.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_CALLBACK 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci__be32 nfs4_callback_getattr(void *argp, void *resp, 248c2ecf20Sopenharmony_ci struct cb_process_state *cps) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct cb_getattrargs *args = argp; 278c2ecf20Sopenharmony_ci struct cb_getattrres *res = resp; 288c2ecf20Sopenharmony_ci struct nfs_delegation *delegation; 298c2ecf20Sopenharmony_ci struct inode *inode; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci res->status = htonl(NFS4ERR_OP_NOT_IN_SESSION); 328c2ecf20Sopenharmony_ci if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ 338c2ecf20Sopenharmony_ci goto out; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci res->bitmap[0] = res->bitmap[1] = 0; 368c2ecf20Sopenharmony_ci res->status = htonl(NFS4ERR_BADHANDLE); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci dprintk_rcu("NFS: GETATTR callback request from %s\n", 398c2ecf20Sopenharmony_ci rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci inode = nfs_delegation_find_inode(cps->clp, &args->fh); 428c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 438c2ecf20Sopenharmony_ci if (inode == ERR_PTR(-EAGAIN)) 448c2ecf20Sopenharmony_ci res->status = htonl(NFS4ERR_DELAY); 458c2ecf20Sopenharmony_ci trace_nfs4_cb_getattr(cps->clp, &args->fh, NULL, 468c2ecf20Sopenharmony_ci -ntohl(res->status)); 478c2ecf20Sopenharmony_ci goto out; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci rcu_read_lock(); 508c2ecf20Sopenharmony_ci delegation = nfs4_get_valid_delegation(inode); 518c2ecf20Sopenharmony_ci if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) 528c2ecf20Sopenharmony_ci goto out_iput; 538c2ecf20Sopenharmony_ci res->size = i_size_read(inode); 548c2ecf20Sopenharmony_ci res->change_attr = delegation->change_attr; 558c2ecf20Sopenharmony_ci if (nfs_have_writebacks(inode)) 568c2ecf20Sopenharmony_ci res->change_attr++; 578c2ecf20Sopenharmony_ci res->ctime = inode->i_ctime; 588c2ecf20Sopenharmony_ci res->mtime = inode->i_mtime; 598c2ecf20Sopenharmony_ci res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) & 608c2ecf20Sopenharmony_ci args->bitmap[0]; 618c2ecf20Sopenharmony_ci res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) & 628c2ecf20Sopenharmony_ci args->bitmap[1]; 638c2ecf20Sopenharmony_ci res->status = 0; 648c2ecf20Sopenharmony_ciout_iput: 658c2ecf20Sopenharmony_ci rcu_read_unlock(); 668c2ecf20Sopenharmony_ci trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status)); 678c2ecf20Sopenharmony_ci nfs_iput_and_deactive(inode); 688c2ecf20Sopenharmony_ciout: 698c2ecf20Sopenharmony_ci dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status)); 708c2ecf20Sopenharmony_ci return res->status; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci__be32 nfs4_callback_recall(void *argp, void *resp, 748c2ecf20Sopenharmony_ci struct cb_process_state *cps) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct cb_recallargs *args = argp; 778c2ecf20Sopenharmony_ci struct inode *inode; 788c2ecf20Sopenharmony_ci __be32 res; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci res = htonl(NFS4ERR_OP_NOT_IN_SESSION); 818c2ecf20Sopenharmony_ci if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ 828c2ecf20Sopenharmony_ci goto out; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dprintk_rcu("NFS: RECALL callback request from %s\n", 858c2ecf20Sopenharmony_ci rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci res = htonl(NFS4ERR_BADHANDLE); 888c2ecf20Sopenharmony_ci inode = nfs_delegation_find_inode(cps->clp, &args->fh); 898c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 908c2ecf20Sopenharmony_ci if (inode == ERR_PTR(-EAGAIN)) 918c2ecf20Sopenharmony_ci res = htonl(NFS4ERR_DELAY); 928c2ecf20Sopenharmony_ci trace_nfs4_cb_recall(cps->clp, &args->fh, NULL, 938c2ecf20Sopenharmony_ci &args->stateid, -ntohl(res)); 948c2ecf20Sopenharmony_ci goto out; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci /* Set up a helper thread to actually return the delegation */ 978c2ecf20Sopenharmony_ci switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { 988c2ecf20Sopenharmony_ci case 0: 998c2ecf20Sopenharmony_ci res = 0; 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci case -ENOENT: 1028c2ecf20Sopenharmony_ci res = htonl(NFS4ERR_BAD_STATEID); 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci default: 1058c2ecf20Sopenharmony_ci res = htonl(NFS4ERR_RESOURCE); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci trace_nfs4_cb_recall(cps->clp, &args->fh, inode, 1088c2ecf20Sopenharmony_ci &args->stateid, -ntohl(res)); 1098c2ecf20Sopenharmony_ci nfs_iput_and_deactive(inode); 1108c2ecf20Sopenharmony_ciout: 1118c2ecf20Sopenharmony_ci dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); 1128c2ecf20Sopenharmony_ci return res; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#if defined(CONFIG_NFS_V4_1) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* 1188c2ecf20Sopenharmony_ci * Lookup a layout inode by stateid 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * Note: returns a refcount on the inode and superblock 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp, 1238c2ecf20Sopenharmony_ci const nfs4_stateid *stateid) 1248c2ecf20Sopenharmony_ci __must_hold(RCU) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct nfs_server *server; 1278c2ecf20Sopenharmony_ci struct inode *inode; 1288c2ecf20Sopenharmony_ci struct pnfs_layout_hdr *lo; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci rcu_read_lock(); 1318c2ecf20Sopenharmony_ci list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { 1328c2ecf20Sopenharmony_ci list_for_each_entry_rcu(lo, &server->layouts, plh_layouts) { 1338c2ecf20Sopenharmony_ci if (!pnfs_layout_is_valid(lo)) 1348c2ecf20Sopenharmony_ci continue; 1358c2ecf20Sopenharmony_ci if (!nfs4_stateid_match_other(stateid, &lo->plh_stateid)) 1368c2ecf20Sopenharmony_ci continue; 1378c2ecf20Sopenharmony_ci if (nfs_sb_active(server->super)) 1388c2ecf20Sopenharmony_ci inode = igrab(lo->plh_inode); 1398c2ecf20Sopenharmony_ci else 1408c2ecf20Sopenharmony_ci inode = ERR_PTR(-EAGAIN); 1418c2ecf20Sopenharmony_ci rcu_read_unlock(); 1428c2ecf20Sopenharmony_ci if (inode) 1438c2ecf20Sopenharmony_ci return inode; 1448c2ecf20Sopenharmony_ci nfs_sb_deactive(server->super); 1458c2ecf20Sopenharmony_ci return ERR_PTR(-EAGAIN); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci rcu_read_unlock(); 1498c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * Lookup a layout inode by filehandle. 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Note: returns a refcount on the inode and superblock 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp, 1598c2ecf20Sopenharmony_ci const struct nfs_fh *fh) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct nfs_server *server; 1628c2ecf20Sopenharmony_ci struct nfs_inode *nfsi; 1638c2ecf20Sopenharmony_ci struct inode *inode; 1648c2ecf20Sopenharmony_ci struct pnfs_layout_hdr *lo; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci rcu_read_lock(); 1678c2ecf20Sopenharmony_ci list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { 1688c2ecf20Sopenharmony_ci list_for_each_entry_rcu(lo, &server->layouts, plh_layouts) { 1698c2ecf20Sopenharmony_ci nfsi = NFS_I(lo->plh_inode); 1708c2ecf20Sopenharmony_ci if (nfs_compare_fh(fh, &nfsi->fh)) 1718c2ecf20Sopenharmony_ci continue; 1728c2ecf20Sopenharmony_ci if (nfsi->layout != lo) 1738c2ecf20Sopenharmony_ci continue; 1748c2ecf20Sopenharmony_ci if (nfs_sb_active(server->super)) 1758c2ecf20Sopenharmony_ci inode = igrab(lo->plh_inode); 1768c2ecf20Sopenharmony_ci else 1778c2ecf20Sopenharmony_ci inode = ERR_PTR(-EAGAIN); 1788c2ecf20Sopenharmony_ci rcu_read_unlock(); 1798c2ecf20Sopenharmony_ci if (inode) 1808c2ecf20Sopenharmony_ci return inode; 1818c2ecf20Sopenharmony_ci nfs_sb_deactive(server->super); 1828c2ecf20Sopenharmony_ci return ERR_PTR(-EAGAIN); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci rcu_read_unlock(); 1868c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct inode *nfs_layout_find_inode(struct nfs_client *clp, 1908c2ecf20Sopenharmony_ci const struct nfs_fh *fh, 1918c2ecf20Sopenharmony_ci const nfs4_stateid *stateid) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct inode *inode; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci inode = nfs_layout_find_inode_by_stateid(clp, stateid); 1968c2ecf20Sopenharmony_ci if (inode == ERR_PTR(-ENOENT)) 1978c2ecf20Sopenharmony_ci inode = nfs_layout_find_inode_by_fh(clp, fh); 1988c2ecf20Sopenharmony_ci return inode; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* 2028c2ecf20Sopenharmony_ci * Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing) 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo, 2058c2ecf20Sopenharmony_ci const nfs4_stateid *new) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci u32 oldseq, newseq; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* Is the stateid not initialised? */ 2108c2ecf20Sopenharmony_ci if (!pnfs_layout_is_valid(lo)) 2118c2ecf20Sopenharmony_ci return NFS4ERR_NOMATCHING_LAYOUT; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Mismatched stateid? */ 2148c2ecf20Sopenharmony_ci if (!nfs4_stateid_match_other(&lo->plh_stateid, new)) 2158c2ecf20Sopenharmony_ci return NFS4ERR_BAD_STATEID; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci newseq = be32_to_cpu(new->seqid); 2188c2ecf20Sopenharmony_ci /* Are we already in a layout recall situation? */ 2198c2ecf20Sopenharmony_ci if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) && 2208c2ecf20Sopenharmony_ci lo->plh_return_seq != 0) { 2218c2ecf20Sopenharmony_ci if (newseq < lo->plh_return_seq) 2228c2ecf20Sopenharmony_ci return NFS4ERR_OLD_STATEID; 2238c2ecf20Sopenharmony_ci if (newseq > lo->plh_return_seq) 2248c2ecf20Sopenharmony_ci return NFS4ERR_DELAY; 2258c2ecf20Sopenharmony_ci goto out; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Check that the stateid matches what we think it should be. */ 2298c2ecf20Sopenharmony_ci oldseq = be32_to_cpu(lo->plh_stateid.seqid); 2308c2ecf20Sopenharmony_ci if (newseq > oldseq + 1) 2318c2ecf20Sopenharmony_ci return NFS4ERR_DELAY; 2328c2ecf20Sopenharmony_ci /* Crazy server! */ 2338c2ecf20Sopenharmony_ci if (newseq <= oldseq) 2348c2ecf20Sopenharmony_ci return NFS4ERR_OLD_STATEID; 2358c2ecf20Sopenharmony_ciout: 2368c2ecf20Sopenharmony_ci return NFS_OK; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic u32 initiate_file_draining(struct nfs_client *clp, 2408c2ecf20Sopenharmony_ci struct cb_layoutrecallargs *args) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct inode *ino; 2438c2ecf20Sopenharmony_ci struct pnfs_layout_hdr *lo; 2448c2ecf20Sopenharmony_ci u32 rv = NFS4ERR_NOMATCHING_LAYOUT; 2458c2ecf20Sopenharmony_ci LIST_HEAD(free_me_list); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid); 2488c2ecf20Sopenharmony_ci if (IS_ERR(ino)) { 2498c2ecf20Sopenharmony_ci if (ino == ERR_PTR(-EAGAIN)) 2508c2ecf20Sopenharmony_ci rv = NFS4ERR_DELAY; 2518c2ecf20Sopenharmony_ci goto out_noput; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci pnfs_layoutcommit_inode(ino, false); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci spin_lock(&ino->i_lock); 2588c2ecf20Sopenharmony_ci lo = NFS_I(ino)->layout; 2598c2ecf20Sopenharmony_ci if (!lo) { 2608c2ecf20Sopenharmony_ci spin_unlock(&ino->i_lock); 2618c2ecf20Sopenharmony_ci goto out; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci pnfs_get_layout_hdr(lo); 2648c2ecf20Sopenharmony_ci rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid); 2658c2ecf20Sopenharmony_ci if (rv != NFS_OK) 2668c2ecf20Sopenharmony_ci goto unlock; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return) 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { 2728c2ecf20Sopenharmony_ci rv = NFS4ERR_DELAY; 2738c2ecf20Sopenharmony_ci goto unlock; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci pnfs_set_layout_stateid(lo, &args->cbl_stateid, NULL, true); 2778c2ecf20Sopenharmony_ci switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list, 2788c2ecf20Sopenharmony_ci &args->cbl_range, 2798c2ecf20Sopenharmony_ci be32_to_cpu(args->cbl_stateid.seqid))) { 2808c2ecf20Sopenharmony_ci case 0: 2818c2ecf20Sopenharmony_ci case -EBUSY: 2828c2ecf20Sopenharmony_ci /* There are layout segments that need to be returned */ 2838c2ecf20Sopenharmony_ci rv = NFS4_OK; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case -ENOENT: 2868c2ecf20Sopenharmony_ci set_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags); 2878c2ecf20Sopenharmony_ci /* Embrace your forgetfulness! */ 2888c2ecf20Sopenharmony_ci rv = NFS4ERR_NOMATCHING_LAYOUT; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) { 2918c2ecf20Sopenharmony_ci NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, 2928c2ecf20Sopenharmony_ci &args->cbl_range); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ciunlock: 2968c2ecf20Sopenharmony_ci spin_unlock(&ino->i_lock); 2978c2ecf20Sopenharmony_ci pnfs_free_lseg_list(&free_me_list); 2988c2ecf20Sopenharmony_ci /* Free all lsegs that are attached to commit buckets */ 2998c2ecf20Sopenharmony_ci nfs_commit_inode(ino, 0); 3008c2ecf20Sopenharmony_ci pnfs_put_layout_hdr(lo); 3018c2ecf20Sopenharmony_ciout: 3028c2ecf20Sopenharmony_ci nfs_iput_and_deactive(ino); 3038c2ecf20Sopenharmony_ciout_noput: 3048c2ecf20Sopenharmony_ci trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino, 3058c2ecf20Sopenharmony_ci &args->cbl_stateid, -rv); 3068c2ecf20Sopenharmony_ci return rv; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic u32 initiate_bulk_draining(struct nfs_client *clp, 3108c2ecf20Sopenharmony_ci struct cb_layoutrecallargs *args) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci int stat; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (args->cbl_recall_type == RETURN_FSID) 3158c2ecf20Sopenharmony_ci stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true); 3168c2ecf20Sopenharmony_ci else 3178c2ecf20Sopenharmony_ci stat = pnfs_destroy_layouts_byclid(clp, true); 3188c2ecf20Sopenharmony_ci if (stat != 0) 3198c2ecf20Sopenharmony_ci return NFS4ERR_DELAY; 3208c2ecf20Sopenharmony_ci return NFS4ERR_NOMATCHING_LAYOUT; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic u32 do_callback_layoutrecall(struct nfs_client *clp, 3248c2ecf20Sopenharmony_ci struct cb_layoutrecallargs *args) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci if (args->cbl_recall_type == RETURN_FILE) 3278c2ecf20Sopenharmony_ci return initiate_file_draining(clp, args); 3288c2ecf20Sopenharmony_ci return initiate_bulk_draining(clp, args); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci__be32 nfs4_callback_layoutrecall(void *argp, void *resp, 3328c2ecf20Sopenharmony_ci struct cb_process_state *cps) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct cb_layoutrecallargs *args = argp; 3358c2ecf20Sopenharmony_ci u32 res = NFS4ERR_OP_NOT_IN_SESSION; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (cps->clp) 3388c2ecf20Sopenharmony_ci res = do_callback_layoutrecall(cps->clp, args); 3398c2ecf20Sopenharmony_ci return cpu_to_be32(res); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void pnfs_recall_all_layouts(struct nfs_client *clp) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct cb_layoutrecallargs args; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Pretend we got a CB_LAYOUTRECALL(ALL) */ 3478c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 3488c2ecf20Sopenharmony_ci args.cbl_recall_type = RETURN_ALL; 3498c2ecf20Sopenharmony_ci /* FIXME we ignore errors, what should we do? */ 3508c2ecf20Sopenharmony_ci do_callback_layoutrecall(clp, &args); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci__be32 nfs4_callback_devicenotify(void *argp, void *resp, 3548c2ecf20Sopenharmony_ci struct cb_process_state *cps) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct cb_devicenotifyargs *args = argp; 3578c2ecf20Sopenharmony_ci const struct pnfs_layoutdriver_type *ld = NULL; 3588c2ecf20Sopenharmony_ci uint32_t i; 3598c2ecf20Sopenharmony_ci __be32 res = 0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (!cps->clp) { 3628c2ecf20Sopenharmony_ci res = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION); 3638c2ecf20Sopenharmony_ci goto out; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci for (i = 0; i < args->ndevs; i++) { 3678c2ecf20Sopenharmony_ci struct cb_devicenotifyitem *dev = &args->devs[i]; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (!ld || ld->id != dev->cbd_layout_type) { 3708c2ecf20Sopenharmony_ci pnfs_put_layoutdriver(ld); 3718c2ecf20Sopenharmony_ci ld = pnfs_find_layoutdriver(dev->cbd_layout_type); 3728c2ecf20Sopenharmony_ci if (!ld) 3738c2ecf20Sopenharmony_ci continue; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci nfs4_delete_deviceid(ld, cps->clp, &dev->cbd_dev_id); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci pnfs_put_layoutdriver(ld); 3788c2ecf20Sopenharmony_ciout: 3798c2ecf20Sopenharmony_ci kfree(args->devs); 3808c2ecf20Sopenharmony_ci return res; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/* 3848c2ecf20Sopenharmony_ci * Validate the sequenceID sent by the server. 3858c2ecf20Sopenharmony_ci * Return success if the sequenceID is one more than what we last saw on 3868c2ecf20Sopenharmony_ci * this slot, accounting for wraparound. Increments the slot's sequence. 3878c2ecf20Sopenharmony_ci * 3888c2ecf20Sopenharmony_ci * We don't yet implement a duplicate request cache, instead we set the 3898c2ecf20Sopenharmony_ci * back channel ca_maxresponsesize_cached to zero. This is OK for now 3908c2ecf20Sopenharmony_ci * since we only currently implement idempotent callbacks anyway. 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * We have a single slot backchannel at this time, so we don't bother 3938c2ecf20Sopenharmony_ci * checking the used_slots bit array on the table. The lower layer guarantees 3948c2ecf20Sopenharmony_ci * a single outstanding callback request at a time. 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_cistatic __be32 3978c2ecf20Sopenharmony_civalidate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, 3988c2ecf20Sopenharmony_ci const struct cb_sequenceargs * args) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci __be32 ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci ret = cpu_to_be32(NFS4ERR_BADSLOT); 4038c2ecf20Sopenharmony_ci if (args->csa_slotid > tbl->server_highest_slotid) 4048c2ecf20Sopenharmony_ci goto out_err; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Replay */ 4078c2ecf20Sopenharmony_ci if (args->csa_sequenceid == slot->seq_nr) { 4088c2ecf20Sopenharmony_ci ret = cpu_to_be32(NFS4ERR_DELAY); 4098c2ecf20Sopenharmony_ci if (nfs4_test_locked_slot(tbl, slot->slot_nr)) 4108c2ecf20Sopenharmony_ci goto out_err; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Signal process_op to set this error on next op */ 4138c2ecf20Sopenharmony_ci ret = cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP); 4148c2ecf20Sopenharmony_ci if (args->csa_cachethis == 0) 4158c2ecf20Sopenharmony_ci goto out_err; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Liar! We never allowed you to set csa_cachethis != 0 */ 4188c2ecf20Sopenharmony_ci ret = cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY); 4198c2ecf20Sopenharmony_ci goto out_err; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Note: wraparound relies on seq_nr being of type u32 */ 4238c2ecf20Sopenharmony_ci /* Misordered request */ 4248c2ecf20Sopenharmony_ci ret = cpu_to_be32(NFS4ERR_SEQ_MISORDERED); 4258c2ecf20Sopenharmony_ci if (args->csa_sequenceid != slot->seq_nr + 1) 4268c2ecf20Sopenharmony_ci goto out_err; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return cpu_to_be32(NFS4_OK); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ciout_err: 4318c2ecf20Sopenharmony_ci trace_nfs4_cb_seqid_err(args, ret); 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* 4368c2ecf20Sopenharmony_ci * For each referring call triple, check the session's slot table for 4378c2ecf20Sopenharmony_ci * a match. If the slot is in use and the sequence numbers match, the 4388c2ecf20Sopenharmony_ci * client is still waiting for a response to the original request. 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_cistatic int referring_call_exists(struct nfs_client *clp, 4418c2ecf20Sopenharmony_ci uint32_t nrclists, 4428c2ecf20Sopenharmony_ci struct referring_call_list *rclists, 4438c2ecf20Sopenharmony_ci spinlock_t *lock) 4448c2ecf20Sopenharmony_ci __releases(lock) 4458c2ecf20Sopenharmony_ci __acquires(lock) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci int status = 0; 4488c2ecf20Sopenharmony_ci int i, j; 4498c2ecf20Sopenharmony_ci struct nfs4_session *session; 4508c2ecf20Sopenharmony_ci struct nfs4_slot_table *tbl; 4518c2ecf20Sopenharmony_ci struct referring_call_list *rclist; 4528c2ecf20Sopenharmony_ci struct referring_call *ref; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * XXX When client trunking is implemented, this becomes 4568c2ecf20Sopenharmony_ci * a session lookup from within the loop 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci session = clp->cl_session; 4598c2ecf20Sopenharmony_ci tbl = &session->fc_slot_table; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci for (i = 0; i < nrclists; i++) { 4628c2ecf20Sopenharmony_ci rclist = &rclists[i]; 4638c2ecf20Sopenharmony_ci if (memcmp(session->sess_id.data, 4648c2ecf20Sopenharmony_ci rclist->rcl_sessionid.data, 4658c2ecf20Sopenharmony_ci NFS4_MAX_SESSIONID_LEN) != 0) 4668c2ecf20Sopenharmony_ci continue; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for (j = 0; j < rclist->rcl_nrefcalls; j++) { 4698c2ecf20Sopenharmony_ci ref = &rclist->rcl_refcalls[j]; 4708c2ecf20Sopenharmony_ci spin_unlock(lock); 4718c2ecf20Sopenharmony_ci status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid, 4728c2ecf20Sopenharmony_ci ref->rc_sequenceid, HZ >> 1) < 0; 4738c2ecf20Sopenharmony_ci spin_lock(lock); 4748c2ecf20Sopenharmony_ci if (status) 4758c2ecf20Sopenharmony_ci goto out; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ciout: 4808c2ecf20Sopenharmony_ci return status; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci__be32 nfs4_callback_sequence(void *argp, void *resp, 4848c2ecf20Sopenharmony_ci struct cb_process_state *cps) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci struct cb_sequenceargs *args = argp; 4878c2ecf20Sopenharmony_ci struct cb_sequenceres *res = resp; 4888c2ecf20Sopenharmony_ci struct nfs4_slot_table *tbl; 4898c2ecf20Sopenharmony_ci struct nfs4_slot *slot; 4908c2ecf20Sopenharmony_ci struct nfs_client *clp; 4918c2ecf20Sopenharmony_ci int i; 4928c2ecf20Sopenharmony_ci __be32 status = htonl(NFS4ERR_BADSESSION); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, 4958c2ecf20Sopenharmony_ci &args->csa_sessionid, cps->minorversion); 4968c2ecf20Sopenharmony_ci if (clp == NULL) 4978c2ecf20Sopenharmony_ci goto out; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!(clp->cl_session->flags & SESSION4_BACK_CHAN)) 5008c2ecf20Sopenharmony_ci goto out; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci tbl = &clp->cl_session->bc_slot_table; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Set up res before grabbing the spinlock */ 5058c2ecf20Sopenharmony_ci memcpy(&res->csr_sessionid, &args->csa_sessionid, 5068c2ecf20Sopenharmony_ci sizeof(res->csr_sessionid)); 5078c2ecf20Sopenharmony_ci res->csr_sequenceid = args->csa_sequenceid; 5088c2ecf20Sopenharmony_ci res->csr_slotid = args->csa_slotid; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci spin_lock(&tbl->slot_tbl_lock); 5118c2ecf20Sopenharmony_ci /* state manager is resetting the session */ 5128c2ecf20Sopenharmony_ci if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { 5138c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_DELAY); 5148c2ecf20Sopenharmony_ci /* Return NFS4ERR_BADSESSION if we're draining the session 5158c2ecf20Sopenharmony_ci * in order to reset it. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) 5188c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_BADSESSION); 5198c2ecf20Sopenharmony_ci goto out_unlock; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_BADSLOT); 5238c2ecf20Sopenharmony_ci slot = nfs4_lookup_slot(tbl, args->csa_slotid); 5248c2ecf20Sopenharmony_ci if (IS_ERR(slot)) 5258c2ecf20Sopenharmony_ci goto out_unlock; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci res->csr_highestslotid = tbl->server_highest_slotid; 5288c2ecf20Sopenharmony_ci res->csr_target_highestslotid = tbl->target_highest_slotid; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci status = validate_seqid(tbl, slot, args); 5318c2ecf20Sopenharmony_ci if (status) 5328c2ecf20Sopenharmony_ci goto out_unlock; 5338c2ecf20Sopenharmony_ci if (!nfs4_try_to_lock_slot(tbl, slot)) { 5348c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_DELAY); 5358c2ecf20Sopenharmony_ci goto out_unlock; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci cps->slot = slot; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* The ca_maxresponsesize_cached is 0 with no DRC */ 5408c2ecf20Sopenharmony_ci if (args->csa_cachethis != 0) { 5418c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); 5428c2ecf20Sopenharmony_ci goto out_unlock; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* 5468c2ecf20Sopenharmony_ci * Check for pending referring calls. If a match is found, a 5478c2ecf20Sopenharmony_ci * related callback was received before the response to the original 5488c2ecf20Sopenharmony_ci * call. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists, 5518c2ecf20Sopenharmony_ci &tbl->slot_tbl_lock) < 0) { 5528c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_DELAY); 5538c2ecf20Sopenharmony_ci goto out_unlock; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * RFC5661 20.9.3 5588c2ecf20Sopenharmony_ci * If CB_SEQUENCE returns an error, then the state of the slot 5598c2ecf20Sopenharmony_ci * (sequence ID, cached reply) MUST NOT change. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci slot->seq_nr = args->csa_sequenceid; 5628c2ecf20Sopenharmony_ciout_unlock: 5638c2ecf20Sopenharmony_ci spin_unlock(&tbl->slot_tbl_lock); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ciout: 5668c2ecf20Sopenharmony_ci cps->clp = clp; /* put in nfs4_callback_compound */ 5678c2ecf20Sopenharmony_ci for (i = 0; i < args->csa_nrclists; i++) 5688c2ecf20Sopenharmony_ci kfree(args->csa_rclists[i].rcl_refcalls); 5698c2ecf20Sopenharmony_ci kfree(args->csa_rclists); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) { 5728c2ecf20Sopenharmony_ci cps->drc_status = status; 5738c2ecf20Sopenharmony_ci status = 0; 5748c2ecf20Sopenharmony_ci } else 5758c2ecf20Sopenharmony_ci res->csr_status = status; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci trace_nfs4_cb_sequence(args, res, status); 5788c2ecf20Sopenharmony_ci return status; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic bool 5828c2ecf20Sopenharmony_civalidate_bitmap_values(unsigned int mask) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci return (mask & ~RCA4_TYPE_MASK_ALL) == 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci__be32 nfs4_callback_recallany(void *argp, void *resp, 5888c2ecf20Sopenharmony_ci struct cb_process_state *cps) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct cb_recallanyargs *args = argp; 5918c2ecf20Sopenharmony_ci __be32 status; 5928c2ecf20Sopenharmony_ci fmode_t flags = 0; 5938c2ecf20Sopenharmony_ci bool schedule_manager = false; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci status = cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION); 5968c2ecf20Sopenharmony_ci if (!cps->clp) /* set in cb_sequence */ 5978c2ecf20Sopenharmony_ci goto out; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci dprintk_rcu("NFS: RECALL_ANY callback request from %s\n", 6008c2ecf20Sopenharmony_ci rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci status = cpu_to_be32(NFS4ERR_INVAL); 6038c2ecf20Sopenharmony_ci if (!validate_bitmap_values(args->craa_type_mask)) 6048c2ecf20Sopenharmony_ci goto out; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci status = cpu_to_be32(NFS4_OK); 6078c2ecf20Sopenharmony_ci if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_RDATA_DLG)) 6088c2ecf20Sopenharmony_ci flags = FMODE_READ; 6098c2ecf20Sopenharmony_ci if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_WDATA_DLG)) 6108c2ecf20Sopenharmony_ci flags |= FMODE_WRITE; 6118c2ecf20Sopenharmony_ci if (flags) 6128c2ecf20Sopenharmony_ci nfs_expire_unused_delegation_types(cps->clp, flags); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_FILE_LAYOUT)) 6158c2ecf20Sopenharmony_ci pnfs_recall_all_layouts(cps->clp); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (args->craa_type_mask & BIT(PNFS_FF_RCA4_TYPE_MASK_READ)) { 6188c2ecf20Sopenharmony_ci set_bit(NFS4CLNT_RECALL_ANY_LAYOUT_READ, &cps->clp->cl_state); 6198c2ecf20Sopenharmony_ci schedule_manager = true; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci if (args->craa_type_mask & BIT(PNFS_FF_RCA4_TYPE_MASK_RW)) { 6228c2ecf20Sopenharmony_ci set_bit(NFS4CLNT_RECALL_ANY_LAYOUT_RW, &cps->clp->cl_state); 6238c2ecf20Sopenharmony_ci schedule_manager = true; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci if (schedule_manager) 6268c2ecf20Sopenharmony_ci nfs4_schedule_state_manager(cps->clp); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ciout: 6298c2ecf20Sopenharmony_ci dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); 6308c2ecf20Sopenharmony_ci return status; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/* Reduce the fore channel's max_slots to the target value */ 6348c2ecf20Sopenharmony_ci__be32 nfs4_callback_recallslot(void *argp, void *resp, 6358c2ecf20Sopenharmony_ci struct cb_process_state *cps) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct cb_recallslotargs *args = argp; 6388c2ecf20Sopenharmony_ci struct nfs4_slot_table *fc_tbl; 6398c2ecf20Sopenharmony_ci __be32 status; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci status = htonl(NFS4ERR_OP_NOT_IN_SESSION); 6428c2ecf20Sopenharmony_ci if (!cps->clp) /* set in cb_sequence */ 6438c2ecf20Sopenharmony_ci goto out; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %u\n", 6468c2ecf20Sopenharmony_ci rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), 6478c2ecf20Sopenharmony_ci args->crsa_target_highest_slotid); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci fc_tbl = &cps->clp->cl_session->fc_slot_table; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci status = htonl(NFS4_OK); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid); 6548c2ecf20Sopenharmony_ci nfs41_notify_server(cps->clp); 6558c2ecf20Sopenharmony_ciout: 6568c2ecf20Sopenharmony_ci dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); 6578c2ecf20Sopenharmony_ci return status; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci__be32 nfs4_callback_notify_lock(void *argp, void *resp, 6618c2ecf20Sopenharmony_ci struct cb_process_state *cps) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct cb_notify_lock_args *args = argp; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!cps->clp) /* set in cb_sequence */ 6668c2ecf20Sopenharmony_ci return htonl(NFS4ERR_OP_NOT_IN_SESSION); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci dprintk_rcu("NFS: CB_NOTIFY_LOCK request from %s\n", 6698c2ecf20Sopenharmony_ci rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Don't wake anybody if the string looked bogus */ 6728c2ecf20Sopenharmony_ci if (args->cbnl_valid) 6738c2ecf20Sopenharmony_ci __wake_up(&cps->clp->cl_lock_waitq, TASK_NORMAL, 0, args); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return htonl(NFS4_OK); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci#endif /* CONFIG_NFS_V4_1 */ 6788c2ecf20Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 6798c2ecf20Sopenharmony_cistatic void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state, 6808c2ecf20Sopenharmony_ci struct cb_offloadargs *args) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci cp_state->count = args->wr_count; 6838c2ecf20Sopenharmony_ci cp_state->error = args->error; 6848c2ecf20Sopenharmony_ci if (!args->error) { 6858c2ecf20Sopenharmony_ci cp_state->verf.committed = args->wr_writeverf.committed; 6868c2ecf20Sopenharmony_ci memcpy(&cp_state->verf.verifier.data[0], 6878c2ecf20Sopenharmony_ci &args->wr_writeverf.verifier.data[0], 6888c2ecf20Sopenharmony_ci NFS4_VERIFIER_SIZE); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci__be32 nfs4_callback_offload(void *data, void *dummy, 6938c2ecf20Sopenharmony_ci struct cb_process_state *cps) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct cb_offloadargs *args = data; 6968c2ecf20Sopenharmony_ci struct nfs_server *server; 6978c2ecf20Sopenharmony_ci struct nfs4_copy_state *copy, *tmp_copy; 6988c2ecf20Sopenharmony_ci bool found = false; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS); 7018c2ecf20Sopenharmony_ci if (!copy) 7028c2ecf20Sopenharmony_ci return htonl(NFS4ERR_SERVERFAULT); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci spin_lock(&cps->clp->cl_lock); 7058c2ecf20Sopenharmony_ci rcu_read_lock(); 7068c2ecf20Sopenharmony_ci list_for_each_entry_rcu(server, &cps->clp->cl_superblocks, 7078c2ecf20Sopenharmony_ci client_link) { 7088c2ecf20Sopenharmony_ci list_for_each_entry(tmp_copy, &server->ss_copies, copies) { 7098c2ecf20Sopenharmony_ci if (memcmp(args->coa_stateid.other, 7108c2ecf20Sopenharmony_ci tmp_copy->stateid.other, 7118c2ecf20Sopenharmony_ci sizeof(args->coa_stateid.other))) 7128c2ecf20Sopenharmony_ci continue; 7138c2ecf20Sopenharmony_ci nfs4_copy_cb_args(tmp_copy, args); 7148c2ecf20Sopenharmony_ci complete(&tmp_copy->completion); 7158c2ecf20Sopenharmony_ci found = true; 7168c2ecf20Sopenharmony_ci goto out; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ciout: 7208c2ecf20Sopenharmony_ci rcu_read_unlock(); 7218c2ecf20Sopenharmony_ci if (!found) { 7228c2ecf20Sopenharmony_ci memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE); 7238c2ecf20Sopenharmony_ci nfs4_copy_cb_args(copy, args); 7248c2ecf20Sopenharmony_ci list_add_tail(©->copies, &cps->clp->pending_cb_stateids); 7258c2ecf20Sopenharmony_ci } else 7268c2ecf20Sopenharmony_ci kfree(copy); 7278c2ecf20Sopenharmony_ci spin_unlock(&cps->clp->cl_lock); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return 0; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci#endif /* CONFIG_NFS_V4_2 */ 732