18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * XDR support for nfsd/protocol version 3. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()! 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/namei.h> 118c2ecf20Sopenharmony_ci#include <linux/sunrpc/svc_xprt.h> 128c2ecf20Sopenharmony_ci#include "xdr3.h" 138c2ecf20Sopenharmony_ci#include "auth.h" 148c2ecf20Sopenharmony_ci#include "netns.h" 158c2ecf20Sopenharmony_ci#include "vfs.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define NFSDDBG_FACILITY NFSDDBG_XDR 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * Mapping of S_IF* types to NFS file types 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistatic u32 nfs3_ftypes[] = { 248c2ecf20Sopenharmony_ci NF3NON, NF3FIFO, NF3CHR, NF3BAD, 258c2ecf20Sopenharmony_ci NF3DIR, NF3BAD, NF3BLK, NF3BAD, 268c2ecf20Sopenharmony_ci NF3REG, NF3BAD, NF3LNK, NF3BAD, 278c2ecf20Sopenharmony_ci NF3SOCK, NF3BAD, NF3LNK, NF3BAD, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * XDR functions for basic NFS types 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic __be32 * 358c2ecf20Sopenharmony_ciencode_time3(__be32 *p, struct timespec64 *time) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); 388c2ecf20Sopenharmony_ci return p; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic __be32 * 428c2ecf20Sopenharmony_cidecode_time3(__be32 *p, struct timespec64 *time) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci time->tv_sec = ntohl(*p++); 458c2ecf20Sopenharmony_ci time->tv_nsec = ntohl(*p++); 468c2ecf20Sopenharmony_ci return p; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic __be32 * 508c2ecf20Sopenharmony_cidecode_fh(__be32 *p, struct svc_fh *fhp) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci unsigned int size; 538c2ecf20Sopenharmony_ci fh_init(fhp, NFS3_FHSIZE); 548c2ecf20Sopenharmony_ci size = ntohl(*p++); 558c2ecf20Sopenharmony_ci if (size > NFS3_FHSIZE) 568c2ecf20Sopenharmony_ci return NULL; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci memcpy(&fhp->fh_handle.fh_base, p, size); 598c2ecf20Sopenharmony_ci fhp->fh_handle.fh_size = size; 608c2ecf20Sopenharmony_ci return p + XDR_QUADLEN(size); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Helper function for NFSv3 ACL code */ 648c2ecf20Sopenharmony_ci__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return decode_fh(p, fhp); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic __be32 * 708c2ecf20Sopenharmony_ciencode_fh(__be32 *p, struct svc_fh *fhp) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci unsigned int size = fhp->fh_handle.fh_size; 738c2ecf20Sopenharmony_ci *p++ = htonl(size); 748c2ecf20Sopenharmony_ci if (size) p[XDR_QUADLEN(size)-1]=0; 758c2ecf20Sopenharmony_ci memcpy(p, &fhp->fh_handle.fh_base, size); 768c2ecf20Sopenharmony_ci return p + XDR_QUADLEN(size); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * Decode a file name and make sure that the path contains 818c2ecf20Sopenharmony_ci * no slashes or null bytes. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistatic __be32 * 848c2ecf20Sopenharmony_cidecode_filename(__be32 *p, char **namp, unsigned int *lenp) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci char *name; 878c2ecf20Sopenharmony_ci unsigned int i; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { 908c2ecf20Sopenharmony_ci for (i = 0, name = *namp; i < *lenp; i++, name++) { 918c2ecf20Sopenharmony_ci if (*name == '\0' || *name == '/') 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return p; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic __be32 * 1008c2ecf20Sopenharmony_cidecode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci u32 tmp; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci iap->ia_valid = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (*p++) { 1078c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_MODE; 1088c2ecf20Sopenharmony_ci iap->ia_mode = ntohl(*p++); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci if (*p++) { 1118c2ecf20Sopenharmony_ci iap->ia_uid = make_kuid(userns, ntohl(*p++)); 1128c2ecf20Sopenharmony_ci if (uid_valid(iap->ia_uid)) 1138c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_UID; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci if (*p++) { 1168c2ecf20Sopenharmony_ci iap->ia_gid = make_kgid(userns, ntohl(*p++)); 1178c2ecf20Sopenharmony_ci if (gid_valid(iap->ia_gid)) 1188c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_GID; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci if (*p++) { 1218c2ecf20Sopenharmony_ci u64 newsize; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_SIZE; 1248c2ecf20Sopenharmony_ci p = xdr_decode_hyper(p, &newsize); 1258c2ecf20Sopenharmony_ci iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ 1288c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_ATIME; 1298c2ecf20Sopenharmony_ci } else if (tmp == 2) { /* set to client time */ 1308c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; 1318c2ecf20Sopenharmony_ci iap->ia_atime.tv_sec = ntohl(*p++); 1328c2ecf20Sopenharmony_ci iap->ia_atime.tv_nsec = ntohl(*p++); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ 1358c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_MTIME; 1368c2ecf20Sopenharmony_ci } else if (tmp == 2) { /* set to client time */ 1378c2ecf20Sopenharmony_ci iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; 1388c2ecf20Sopenharmony_ci iap->ia_mtime.tv_sec = ntohl(*p++); 1398c2ecf20Sopenharmony_ci iap->ia_mtime.tv_nsec = ntohl(*p++); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci return p; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci u64 f; 1478c2ecf20Sopenharmony_ci switch(fsid_source(fhp)) { 1488c2ecf20Sopenharmony_ci default: 1498c2ecf20Sopenharmony_ci case FSIDSOURCE_DEV: 1508c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, (u64)huge_encode_dev 1518c2ecf20Sopenharmony_ci (fhp->fh_dentry->d_sb->s_dev)); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case FSIDSOURCE_FSID: 1548c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case FSIDSOURCE_UUID: 1578c2ecf20Sopenharmony_ci f = ((u64*)fhp->fh_export->ex_uuid)[0]; 1588c2ecf20Sopenharmony_ci f ^= ((u64*)fhp->fh_export->ex_uuid)[1]; 1598c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, f); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return p; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic __be32 * 1668c2ecf20Sopenharmony_ciencode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, 1678c2ecf20Sopenharmony_ci struct kstat *stat) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct user_namespace *userns = nfsd_user_namespace(rqstp); 1708c2ecf20Sopenharmony_ci *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); 1718c2ecf20Sopenharmony_ci *p++ = htonl((u32) (stat->mode & S_IALLUGO)); 1728c2ecf20Sopenharmony_ci *p++ = htonl((u32) stat->nlink); 1738c2ecf20Sopenharmony_ci *p++ = htonl((u32) from_kuid_munged(userns, stat->uid)); 1748c2ecf20Sopenharmony_ci *p++ = htonl((u32) from_kgid_munged(userns, stat->gid)); 1758c2ecf20Sopenharmony_ci if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { 1768c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); 1778c2ecf20Sopenharmony_ci } else { 1788c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, (u64) stat->size); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); 1818c2ecf20Sopenharmony_ci *p++ = htonl((u32) MAJOR(stat->rdev)); 1828c2ecf20Sopenharmony_ci *p++ = htonl((u32) MINOR(stat->rdev)); 1838c2ecf20Sopenharmony_ci p = encode_fsid(p, fhp); 1848c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, stat->ino); 1858c2ecf20Sopenharmony_ci p = encode_time3(p, &stat->atime); 1868c2ecf20Sopenharmony_ci p = encode_time3(p, &stat->mtime); 1878c2ecf20Sopenharmony_ci p = encode_time3(p, &stat->ctime); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return p; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic __be32 * 1938c2ecf20Sopenharmony_ciencode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci /* Attributes to follow */ 1968c2ecf20Sopenharmony_ci *p++ = xdr_one; 1978c2ecf20Sopenharmony_ci return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci/* 2018c2ecf20Sopenharmony_ci * Encode post-operation attributes. 2028c2ecf20Sopenharmony_ci * The inode may be NULL if the call failed because of a stale file 2038c2ecf20Sopenharmony_ci * handle. In this case, no attributes are returned. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic __be32 * 2068c2ecf20Sopenharmony_ciencode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct dentry *dentry = fhp->fh_dentry; 2098c2ecf20Sopenharmony_ci if (dentry && d_really_is_positive(dentry)) { 2108c2ecf20Sopenharmony_ci __be32 err; 2118c2ecf20Sopenharmony_ci struct kstat stat; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci err = fh_getattr(fhp, &stat); 2148c2ecf20Sopenharmony_ci if (!err) { 2158c2ecf20Sopenharmony_ci *p++ = xdr_one; /* attributes follow */ 2168c2ecf20Sopenharmony_ci lease_get_mtime(d_inode(dentry), &stat.mtime); 2178c2ecf20Sopenharmony_ci return encode_fattr3(rqstp, p, fhp, &stat); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci *p++ = xdr_zero; 2218c2ecf20Sopenharmony_ci return p; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Helper for NFSv3 ACLs */ 2258c2ecf20Sopenharmony_ci__be32 * 2268c2ecf20Sopenharmony_cinfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci return encode_post_op_attr(rqstp, p, fhp); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* 2328c2ecf20Sopenharmony_ci * Enocde weak cache consistency data 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_cistatic __be32 * 2358c2ecf20Sopenharmony_ciencode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct dentry *dentry = fhp->fh_dentry; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) { 2408c2ecf20Sopenharmony_ci if (fhp->fh_pre_saved) { 2418c2ecf20Sopenharmony_ci *p++ = xdr_one; 2428c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); 2438c2ecf20Sopenharmony_ci p = encode_time3(p, &fhp->fh_pre_mtime); 2448c2ecf20Sopenharmony_ci p = encode_time3(p, &fhp->fh_pre_ctime); 2458c2ecf20Sopenharmony_ci } else { 2468c2ecf20Sopenharmony_ci *p++ = xdr_zero; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci return encode_saved_post_attr(rqstp, p, fhp); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci /* no pre- or post-attrs */ 2518c2ecf20Sopenharmony_ci *p++ = xdr_zero; 2528c2ecf20Sopenharmony_ci return encode_post_op_attr(rqstp, p, fhp); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * Fill in the pre_op attr for the wcc data 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_civoid fill_pre_wcc(struct svc_fh *fhp) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct inode *inode; 2618c2ecf20Sopenharmony_ci struct kstat stat; 2628c2ecf20Sopenharmony_ci __be32 err; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (fhp->fh_pre_saved) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci inode = d_inode(fhp->fh_dentry); 2688c2ecf20Sopenharmony_ci err = fh_getattr(fhp, &stat); 2698c2ecf20Sopenharmony_ci if (err) { 2708c2ecf20Sopenharmony_ci /* Grab the times from inode anyway */ 2718c2ecf20Sopenharmony_ci stat.mtime = inode->i_mtime; 2728c2ecf20Sopenharmony_ci stat.ctime = inode->i_ctime; 2738c2ecf20Sopenharmony_ci stat.size = inode->i_size; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci fhp->fh_pre_mtime = stat.mtime; 2778c2ecf20Sopenharmony_ci fhp->fh_pre_ctime = stat.ctime; 2788c2ecf20Sopenharmony_ci fhp->fh_pre_size = stat.size; 2798c2ecf20Sopenharmony_ci fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); 2808c2ecf20Sopenharmony_ci fhp->fh_pre_saved = true; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* 2848c2ecf20Sopenharmony_ci * Fill in the post_op attr for the wcc data 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_civoid fill_post_wcc(struct svc_fh *fhp) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci __be32 err; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (fhp->fh_post_saved) 2918c2ecf20Sopenharmony_ci printk("nfsd: inode locked twice during operation.\n"); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci err = fh_getattr(fhp, &fhp->fh_post_attr); 2948c2ecf20Sopenharmony_ci fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr, 2958c2ecf20Sopenharmony_ci d_inode(fhp->fh_dentry)); 2968c2ecf20Sopenharmony_ci if (err) { 2978c2ecf20Sopenharmony_ci fhp->fh_post_saved = false; 2988c2ecf20Sopenharmony_ci /* Grab the ctime anyway - set_change_info might use it */ 2998c2ecf20Sopenharmony_ci fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime; 3008c2ecf20Sopenharmony_ci } else 3018c2ecf20Sopenharmony_ci fhp->fh_post_saved = true; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* 3058c2ecf20Sopenharmony_ci * XDR decode functions 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ciint 3088c2ecf20Sopenharmony_cinfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci return 1; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ciint 3148c2ecf20Sopenharmony_cinfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct nfsd_fhandle *args = rqstp->rq_argp; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 3198c2ecf20Sopenharmony_ci if (!p) 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ciint 3258c2ecf20Sopenharmony_cinfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct nfsd3_sattrargs *args = rqstp->rq_argp; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 3308c2ecf20Sopenharmony_ci if (!p) 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if ((args->check_guard = ntohl(*p++)) != 0) { 3358c2ecf20Sopenharmony_ci struct timespec64 time; 3368c2ecf20Sopenharmony_ci p = decode_time3(p, &time); 3378c2ecf20Sopenharmony_ci args->guardtime = time.tv_sec; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciint 3448c2ecf20Sopenharmony_cinfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct nfsd3_diropargs *args = rqstp->rq_argp; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->fh)) 3498c2ecf20Sopenharmony_ci || !(p = decode_filename(p, &args->name, &args->len))) 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciint 3568c2ecf20Sopenharmony_cinfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct nfsd3_accessargs *args = rqstp->rq_argp; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 3618c2ecf20Sopenharmony_ci if (!p) 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci args->access = ntohl(*p++); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint 3698c2ecf20Sopenharmony_cinfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct nfsd3_readargs *args = rqstp->rq_argp; 3728c2ecf20Sopenharmony_ci unsigned int len; 3738c2ecf20Sopenharmony_ci int v; 3748c2ecf20Sopenharmony_ci u32 max_blocksize = svc_max_payload(rqstp); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 3778c2ecf20Sopenharmony_ci if (!p) 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci p = xdr_decode_hyper(p, &args->offset); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci args->count = ntohl(*p++); 3828c2ecf20Sopenharmony_ci len = min(args->count, max_blocksize); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* set up the kvec */ 3858c2ecf20Sopenharmony_ci v=0; 3868c2ecf20Sopenharmony_ci while (len > 0) { 3878c2ecf20Sopenharmony_ci struct page *p = *(rqstp->rq_next_page++); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci rqstp->rq_vec[v].iov_base = page_address(p); 3908c2ecf20Sopenharmony_ci rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE); 3918c2ecf20Sopenharmony_ci len -= rqstp->rq_vec[v].iov_len; 3928c2ecf20Sopenharmony_ci v++; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci args->vlen = v; 3958c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciint 3998c2ecf20Sopenharmony_cinfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct nfsd3_writeargs *args = rqstp->rq_argp; 4028c2ecf20Sopenharmony_ci unsigned int len, hdr, dlen; 4038c2ecf20Sopenharmony_ci u32 max_blocksize = svc_max_payload(rqstp); 4048c2ecf20Sopenharmony_ci struct kvec *head = rqstp->rq_arg.head; 4058c2ecf20Sopenharmony_ci struct kvec *tail = rqstp->rq_arg.tail; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 4088c2ecf20Sopenharmony_ci if (!p) 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci p = xdr_decode_hyper(p, &args->offset); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci args->count = ntohl(*p++); 4138c2ecf20Sopenharmony_ci args->stable = ntohl(*p++); 4148c2ecf20Sopenharmony_ci len = args->len = ntohl(*p++); 4158c2ecf20Sopenharmony_ci if ((void *)p > head->iov_base + head->iov_len) 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * The count must equal the amount of data passed. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci if (args->count != args->len) 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * Check to make sure that we got the right number of 4258c2ecf20Sopenharmony_ci * bytes. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci hdr = (void*)p - head->iov_base; 4288c2ecf20Sopenharmony_ci dlen = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len - hdr; 4298c2ecf20Sopenharmony_ci /* 4308c2ecf20Sopenharmony_ci * Round the length of the data which was specified up to 4318c2ecf20Sopenharmony_ci * the next multiple of XDR units and then compare that 4328c2ecf20Sopenharmony_ci * against the length which was actually received. 4338c2ecf20Sopenharmony_ci * Note that when RPCSEC/GSS (for example) is used, the 4348c2ecf20Sopenharmony_ci * data buffer can be padded so dlen might be larger 4358c2ecf20Sopenharmony_ci * than required. It must never be smaller. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci if (dlen < XDR_QUADLEN(len)*4) 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (args->count > max_blocksize) { 4418c2ecf20Sopenharmony_ci args->count = max_blocksize; 4428c2ecf20Sopenharmony_ci len = args->len = max_blocksize; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci args->first.iov_base = (void *)p; 4468c2ecf20Sopenharmony_ci args->first.iov_len = head->iov_len - hdr; 4478c2ecf20Sopenharmony_ci return 1; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ciint 4518c2ecf20Sopenharmony_cinfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct nfsd3_createargs *args = rqstp->rq_argp; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->fh)) 4568c2ecf20Sopenharmony_ci || !(p = decode_filename(p, &args->name, &args->len))) 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci switch (args->createmode = ntohl(*p++)) { 4608c2ecf20Sopenharmony_ci case NFS3_CREATE_UNCHECKED: 4618c2ecf20Sopenharmony_ci case NFS3_CREATE_GUARDED: 4628c2ecf20Sopenharmony_ci p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci case NFS3_CREATE_EXCLUSIVE: 4658c2ecf20Sopenharmony_ci args->verf = p; 4668c2ecf20Sopenharmony_ci p += 2; 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci default: 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ciint 4768c2ecf20Sopenharmony_cinfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct nfsd3_createargs *args = rqstp->rq_argp; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->fh)) || 4818c2ecf20Sopenharmony_ci !(p = decode_filename(p, &args->name, &args->len))) 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciint 4898c2ecf20Sopenharmony_cinfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct nfsd3_symlinkargs *args = rqstp->rq_argp; 4928c2ecf20Sopenharmony_ci char *base = (char *)p; 4938c2ecf20Sopenharmony_ci size_t dlen; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->ffh)) || 4968c2ecf20Sopenharmony_ci !(p = decode_filename(p, &args->fname, &args->flen))) 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci args->tlen = ntohl(*p++); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci args->first.iov_base = p; 5038c2ecf20Sopenharmony_ci args->first.iov_len = rqstp->rq_arg.head[0].iov_len; 5048c2ecf20Sopenharmony_ci args->first.iov_len -= (char *)p - base; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci dlen = args->first.iov_len + rqstp->rq_arg.page_len + 5078c2ecf20Sopenharmony_ci rqstp->rq_arg.tail[0].iov_len; 5088c2ecf20Sopenharmony_ci if (dlen < XDR_QUADLEN(args->tlen) << 2) 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci return 1; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciint 5148c2ecf20Sopenharmony_cinfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct nfsd3_mknodargs *args = rqstp->rq_argp; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->fh)) 5198c2ecf20Sopenharmony_ci || !(p = decode_filename(p, &args->name, &args->len))) 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci args->ftype = ntohl(*p++); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (args->ftype == NF3BLK || args->ftype == NF3CHR 5258c2ecf20Sopenharmony_ci || args->ftype == NF3SOCK || args->ftype == NF3FIFO) 5268c2ecf20Sopenharmony_ci p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (args->ftype == NF3BLK || args->ftype == NF3CHR) { 5298c2ecf20Sopenharmony_ci args->major = ntohl(*p++); 5308c2ecf20Sopenharmony_ci args->minor = ntohl(*p++); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ciint 5378c2ecf20Sopenharmony_cinfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct nfsd3_renameargs *args = rqstp->rq_argp; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->ffh)) 5428c2ecf20Sopenharmony_ci || !(p = decode_filename(p, &args->fname, &args->flen)) 5438c2ecf20Sopenharmony_ci || !(p = decode_fh(p, &args->tfh)) 5448c2ecf20Sopenharmony_ci || !(p = decode_filename(p, &args->tname, &args->tlen))) 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ciint 5518c2ecf20Sopenharmony_cinfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct nfsd3_readlinkargs *args = rqstp->rq_argp; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 5568c2ecf20Sopenharmony_ci if (!p) 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci args->buffer = page_address(*(rqstp->rq_next_page++)); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ciint 5648c2ecf20Sopenharmony_cinfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct nfsd3_linkargs *args = rqstp->rq_argp; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (!(p = decode_fh(p, &args->ffh)) 5698c2ecf20Sopenharmony_ci || !(p = decode_fh(p, &args->tfh)) 5708c2ecf20Sopenharmony_ci || !(p = decode_filename(p, &args->tname, &args->tlen))) 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ciint 5778c2ecf20Sopenharmony_cinfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct nfsd3_readdirargs *args = rqstp->rq_argp; 5808c2ecf20Sopenharmony_ci int len; 5818c2ecf20Sopenharmony_ci u32 max_blocksize = svc_max_payload(rqstp); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 5848c2ecf20Sopenharmony_ci if (!p) 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci p = xdr_decode_hyper(p, &args->cookie); 5878c2ecf20Sopenharmony_ci args->verf = p; p += 2; 5888c2ecf20Sopenharmony_ci args->dircount = ~0; 5898c2ecf20Sopenharmony_ci args->count = ntohl(*p++); 5908c2ecf20Sopenharmony_ci len = args->count = min_t(u32, args->count, max_blocksize); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci while (len > 0) { 5938c2ecf20Sopenharmony_ci struct page *p = *(rqstp->rq_next_page++); 5948c2ecf20Sopenharmony_ci if (!args->buffer) 5958c2ecf20Sopenharmony_ci args->buffer = page_address(p); 5968c2ecf20Sopenharmony_ci len -= PAGE_SIZE; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ciint 6038c2ecf20Sopenharmony_cinfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct nfsd3_readdirargs *args = rqstp->rq_argp; 6068c2ecf20Sopenharmony_ci int len; 6078c2ecf20Sopenharmony_ci u32 max_blocksize = svc_max_payload(rqstp); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 6108c2ecf20Sopenharmony_ci if (!p) 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci p = xdr_decode_hyper(p, &args->cookie); 6138c2ecf20Sopenharmony_ci args->verf = p; p += 2; 6148c2ecf20Sopenharmony_ci args->dircount = ntohl(*p++); 6158c2ecf20Sopenharmony_ci args->count = ntohl(*p++); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci len = args->count = min(args->count, max_blocksize); 6188c2ecf20Sopenharmony_ci while (len > 0) { 6198c2ecf20Sopenharmony_ci struct page *p = *(rqstp->rq_next_page++); 6208c2ecf20Sopenharmony_ci if (!args->buffer) 6218c2ecf20Sopenharmony_ci args->buffer = page_address(p); 6228c2ecf20Sopenharmony_ci len -= PAGE_SIZE; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ciint 6298c2ecf20Sopenharmony_cinfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct nfsd3_commitargs *args = rqstp->rq_argp; 6328c2ecf20Sopenharmony_ci p = decode_fh(p, &args->fh); 6338c2ecf20Sopenharmony_ci if (!p) 6348c2ecf20Sopenharmony_ci return 0; 6358c2ecf20Sopenharmony_ci p = xdr_decode_hyper(p, &args->offset); 6368c2ecf20Sopenharmony_ci args->count = ntohl(*p++); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci return xdr_argsize_check(rqstp, p); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/* 6428c2ecf20Sopenharmony_ci * XDR encode functions 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ciint 6468c2ecf20Sopenharmony_cinfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci/* GETATTR */ 6528c2ecf20Sopenharmony_ciint 6538c2ecf20Sopenharmony_cinfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct nfsd3_attrstat *resp = rqstp->rq_resp; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci *p++ = resp->status; 6588c2ecf20Sopenharmony_ci if (resp->status == 0) { 6598c2ecf20Sopenharmony_ci lease_get_mtime(d_inode(resp->fh.fh_dentry), 6608c2ecf20Sopenharmony_ci &resp->stat.mtime); 6618c2ecf20Sopenharmony_ci p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/* SETATTR, REMOVE, RMDIR */ 6678c2ecf20Sopenharmony_ciint 6688c2ecf20Sopenharmony_cinfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct nfsd3_attrstat *resp = rqstp->rq_resp; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci *p++ = resp->status; 6738c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->fh); 6748c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/* LOOKUP */ 6788c2ecf20Sopenharmony_ciint 6798c2ecf20Sopenharmony_cinfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct nfsd3_diropres *resp = rqstp->rq_resp; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci *p++ = resp->status; 6848c2ecf20Sopenharmony_ci if (resp->status == 0) { 6858c2ecf20Sopenharmony_ci p = encode_fh(p, &resp->fh); 6868c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->dirfh); 6898c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* ACCESS */ 6938c2ecf20Sopenharmony_ciint 6948c2ecf20Sopenharmony_cinfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct nfsd3_accessres *resp = rqstp->rq_resp; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci *p++ = resp->status; 6998c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 7008c2ecf20Sopenharmony_ci if (resp->status == 0) 7018c2ecf20Sopenharmony_ci *p++ = htonl(resp->access); 7028c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* READLINK */ 7068c2ecf20Sopenharmony_ciint 7078c2ecf20Sopenharmony_cinfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct nfsd3_readlinkres *resp = rqstp->rq_resp; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci *p++ = resp->status; 7128c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 7138c2ecf20Sopenharmony_ci if (resp->status == 0) { 7148c2ecf20Sopenharmony_ci *p++ = htonl(resp->len); 7158c2ecf20Sopenharmony_ci xdr_ressize_check(rqstp, p); 7168c2ecf20Sopenharmony_ci rqstp->rq_res.page_len = resp->len; 7178c2ecf20Sopenharmony_ci if (resp->len & 3) { 7188c2ecf20Sopenharmony_ci /* need to pad the tail */ 7198c2ecf20Sopenharmony_ci rqstp->rq_res.tail[0].iov_base = p; 7208c2ecf20Sopenharmony_ci *p = 0; 7218c2ecf20Sopenharmony_ci rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci return 1; 7248c2ecf20Sopenharmony_ci } else 7258c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* READ */ 7298c2ecf20Sopenharmony_ciint 7308c2ecf20Sopenharmony_cinfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct nfsd3_readres *resp = rqstp->rq_resp; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci *p++ = resp->status; 7358c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 7368c2ecf20Sopenharmony_ci if (resp->status == 0) { 7378c2ecf20Sopenharmony_ci *p++ = htonl(resp->count); 7388c2ecf20Sopenharmony_ci *p++ = htonl(resp->eof); 7398c2ecf20Sopenharmony_ci *p++ = htonl(resp->count); /* xdr opaque count */ 7408c2ecf20Sopenharmony_ci xdr_ressize_check(rqstp, p); 7418c2ecf20Sopenharmony_ci /* now update rqstp->rq_res to reflect data as well */ 7428c2ecf20Sopenharmony_ci rqstp->rq_res.page_len = resp->count; 7438c2ecf20Sopenharmony_ci if (resp->count & 3) { 7448c2ecf20Sopenharmony_ci /* need to pad the tail */ 7458c2ecf20Sopenharmony_ci rqstp->rq_res.tail[0].iov_base = p; 7468c2ecf20Sopenharmony_ci *p = 0; 7478c2ecf20Sopenharmony_ci rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci return 1; 7508c2ecf20Sopenharmony_ci } else 7518c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci/* WRITE */ 7558c2ecf20Sopenharmony_ciint 7568c2ecf20Sopenharmony_cinfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct nfsd3_writeres *resp = rqstp->rq_resp; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci *p++ = resp->status; 7618c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->fh); 7628c2ecf20Sopenharmony_ci if (resp->status == 0) { 7638c2ecf20Sopenharmony_ci *p++ = htonl(resp->count); 7648c2ecf20Sopenharmony_ci *p++ = htonl(resp->committed); 7658c2ecf20Sopenharmony_ci *p++ = resp->verf[0]; 7668c2ecf20Sopenharmony_ci *p++ = resp->verf[1]; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci/* CREATE, MKDIR, SYMLINK, MKNOD */ 7728c2ecf20Sopenharmony_ciint 7738c2ecf20Sopenharmony_cinfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct nfsd3_diropres *resp = rqstp->rq_resp; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci *p++ = resp->status; 7788c2ecf20Sopenharmony_ci if (resp->status == 0) { 7798c2ecf20Sopenharmony_ci *p++ = xdr_one; 7808c2ecf20Sopenharmony_ci p = encode_fh(p, &resp->fh); 7818c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->dirfh); 7848c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci/* RENAME */ 7888c2ecf20Sopenharmony_ciint 7898c2ecf20Sopenharmony_cinfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct nfsd3_renameres *resp = rqstp->rq_resp; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci *p++ = resp->status; 7948c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->ffh); 7958c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->tfh); 7968c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci/* LINK */ 8008c2ecf20Sopenharmony_ciint 8018c2ecf20Sopenharmony_cinfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct nfsd3_linkres *resp = rqstp->rq_resp; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci *p++ = resp->status; 8068c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 8078c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->tfh); 8088c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci/* READDIR */ 8128c2ecf20Sopenharmony_ciint 8138c2ecf20Sopenharmony_cinfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct nfsd3_readdirres *resp = rqstp->rq_resp; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci *p++ = resp->status; 8188c2ecf20Sopenharmony_ci p = encode_post_op_attr(rqstp, p, &resp->fh); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (resp->status == 0) { 8218c2ecf20Sopenharmony_ci /* stupid readdir cookie */ 8228c2ecf20Sopenharmony_ci memcpy(p, resp->verf, 8); p += 2; 8238c2ecf20Sopenharmony_ci xdr_ressize_check(rqstp, p); 8248c2ecf20Sopenharmony_ci if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE) 8258c2ecf20Sopenharmony_ci return 1; /*No room for trailer */ 8268c2ecf20Sopenharmony_ci rqstp->rq_res.page_len = (resp->count) << 2; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* add the 'tail' to the end of the 'head' page - page 0. */ 8298c2ecf20Sopenharmony_ci rqstp->rq_res.tail[0].iov_base = p; 8308c2ecf20Sopenharmony_ci *p++ = 0; /* no more entries */ 8318c2ecf20Sopenharmony_ci *p++ = htonl(resp->common.err == nfserr_eof); 8328c2ecf20Sopenharmony_ci rqstp->rq_res.tail[0].iov_len = 2<<2; 8338c2ecf20Sopenharmony_ci return 1; 8348c2ecf20Sopenharmony_ci } else 8358c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic __be32 * 8398c2ecf20Sopenharmony_ciencode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, 8408c2ecf20Sopenharmony_ci int namlen, u64 ino) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci *p++ = xdr_one; /* mark entry present */ 8438c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, ino); /* file id */ 8448c2ecf20Sopenharmony_ci p = xdr_encode_array(p, name, namlen);/* name length & name */ 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci cd->offset = p; /* remember pointer */ 8478c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */ 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci return p; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic __be32 8538c2ecf20Sopenharmony_cicompose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, 8548c2ecf20Sopenharmony_ci const char *name, int namlen, u64 ino) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct svc_export *exp; 8578c2ecf20Sopenharmony_ci struct dentry *dparent, *dchild; 8588c2ecf20Sopenharmony_ci __be32 rv = nfserr_noent; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci dparent = cd->fh.fh_dentry; 8618c2ecf20Sopenharmony_ci exp = cd->fh.fh_export; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (isdotent(name, namlen)) { 8648c2ecf20Sopenharmony_ci if (namlen == 2) { 8658c2ecf20Sopenharmony_ci dchild = dget_parent(dparent); 8668c2ecf20Sopenharmony_ci /* 8678c2ecf20Sopenharmony_ci * Don't return filehandle for ".." if we're at 8688c2ecf20Sopenharmony_ci * the filesystem or export root: 8698c2ecf20Sopenharmony_ci */ 8708c2ecf20Sopenharmony_ci if (dchild == dparent) 8718c2ecf20Sopenharmony_ci goto out; 8728c2ecf20Sopenharmony_ci if (dparent == exp->ex_path.dentry) 8738c2ecf20Sopenharmony_ci goto out; 8748c2ecf20Sopenharmony_ci } else 8758c2ecf20Sopenharmony_ci dchild = dget(dparent); 8768c2ecf20Sopenharmony_ci } else 8778c2ecf20Sopenharmony_ci dchild = lookup_positive_unlocked(name, dparent, namlen); 8788c2ecf20Sopenharmony_ci if (IS_ERR(dchild)) 8798c2ecf20Sopenharmony_ci return rv; 8808c2ecf20Sopenharmony_ci if (d_mountpoint(dchild)) 8818c2ecf20Sopenharmony_ci goto out; 8828c2ecf20Sopenharmony_ci if (dchild->d_inode->i_ino != ino) 8838c2ecf20Sopenharmony_ci goto out; 8848c2ecf20Sopenharmony_ci rv = fh_compose(fhp, exp, dchild, &cd->fh); 8858c2ecf20Sopenharmony_ciout: 8868c2ecf20Sopenharmony_ci dput(dchild); 8878c2ecf20Sopenharmony_ci return rv; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct svc_fh *fh = &cd->scratch; 8938c2ecf20Sopenharmony_ci __be32 err; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci fh_init(fh, NFS3_FHSIZE); 8968c2ecf20Sopenharmony_ci err = compose_entry_fh(cd, fh, name, namlen, ino); 8978c2ecf20Sopenharmony_ci if (err) { 8988c2ecf20Sopenharmony_ci *p++ = 0; 8998c2ecf20Sopenharmony_ci *p++ = 0; 9008c2ecf20Sopenharmony_ci goto out; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci p = encode_post_op_attr(cd->rqstp, p, fh); 9038c2ecf20Sopenharmony_ci *p++ = xdr_one; /* yes, a file handle follows */ 9048c2ecf20Sopenharmony_ci p = encode_fh(p, fh); 9058c2ecf20Sopenharmony_ciout: 9068c2ecf20Sopenharmony_ci fh_put(fh); 9078c2ecf20Sopenharmony_ci return p; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci/* 9118c2ecf20Sopenharmony_ci * Encode a directory entry. This one works for both normal readdir 9128c2ecf20Sopenharmony_ci * and readdirplus. 9138c2ecf20Sopenharmony_ci * The normal readdir reply requires 2 (fileid) + 1 (stringlen) 9148c2ecf20Sopenharmony_ci * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen. 9158c2ecf20Sopenharmony_ci * 9168c2ecf20Sopenharmony_ci * The readdirplus baggage is 1+21 words for post_op_attr, plus the 9178c2ecf20Sopenharmony_ci * file handle. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1) 9218c2ecf20Sopenharmony_ci#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) 9228c2ecf20Sopenharmony_cistatic int 9238c2ecf20Sopenharmony_ciencode_entry(struct readdir_cd *ccd, const char *name, int namlen, 9248c2ecf20Sopenharmony_ci loff_t offset, u64 ino, unsigned int d_type, int plus) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, 9278c2ecf20Sopenharmony_ci common); 9288c2ecf20Sopenharmony_ci __be32 *p = cd->buffer; 9298c2ecf20Sopenharmony_ci caddr_t curr_page_addr = NULL; 9308c2ecf20Sopenharmony_ci struct page ** page; 9318c2ecf20Sopenharmony_ci int slen; /* string (name) length */ 9328c2ecf20Sopenharmony_ci int elen; /* estimated entry length in words */ 9338c2ecf20Sopenharmony_ci int num_entry_words = 0; /* actual number of words */ 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (cd->offset) { 9368c2ecf20Sopenharmony_ci u64 offset64 = offset; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (unlikely(cd->offset1)) { 9398c2ecf20Sopenharmony_ci /* we ended up with offset on a page boundary */ 9408c2ecf20Sopenharmony_ci *cd->offset = htonl(offset64 >> 32); 9418c2ecf20Sopenharmony_ci *cd->offset1 = htonl(offset64 & 0xffffffff); 9428c2ecf20Sopenharmony_ci cd->offset1 = NULL; 9438c2ecf20Sopenharmony_ci } else { 9448c2ecf20Sopenharmony_ci xdr_encode_hyper(cd->offset, offset64); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci cd->offset = NULL; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci dprintk("encode_entry(%.*s @%ld%s)\n", 9518c2ecf20Sopenharmony_ci namlen, name, (long) offset, plus? " plus" : ""); 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* truncate filename if too long */ 9558c2ecf20Sopenharmony_ci namlen = min(namlen, NFS3_MAXNAMLEN); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci slen = XDR_QUADLEN(namlen); 9588c2ecf20Sopenharmony_ci elen = slen + NFS3_ENTRY_BAGGAGE 9598c2ecf20Sopenharmony_ci + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (cd->buflen < elen) { 9628c2ecf20Sopenharmony_ci cd->common.err = nfserr_toosmall; 9638c2ecf20Sopenharmony_ci return -EINVAL; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* determine which page in rq_respages[] we are currently filling */ 9678c2ecf20Sopenharmony_ci for (page = cd->rqstp->rq_respages + 1; 9688c2ecf20Sopenharmony_ci page < cd->rqstp->rq_next_page; page++) { 9698c2ecf20Sopenharmony_ci curr_page_addr = page_address(*page); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (((caddr_t)cd->buffer >= curr_page_addr) && 9728c2ecf20Sopenharmony_ci ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE)) 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) { 9778c2ecf20Sopenharmony_ci /* encode entry in current page */ 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci p = encode_entry_baggage(cd, p, name, namlen, ino); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (plus) 9828c2ecf20Sopenharmony_ci p = encode_entryplus_baggage(cd, p, name, namlen, ino); 9838c2ecf20Sopenharmony_ci num_entry_words = p - cd->buffer; 9848c2ecf20Sopenharmony_ci } else if (*(page+1) != NULL) { 9858c2ecf20Sopenharmony_ci /* temporarily encode entry into next page, then move back to 9868c2ecf20Sopenharmony_ci * current and next page in rq_respages[] */ 9878c2ecf20Sopenharmony_ci __be32 *p1, *tmp; 9888c2ecf20Sopenharmony_ci int len1, len2; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* grab next page for temporary storage of entry */ 9918c2ecf20Sopenharmony_ci p1 = tmp = page_address(*(page+1)); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci p1 = encode_entry_baggage(cd, p1, name, namlen, ino); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (plus) 9968c2ecf20Sopenharmony_ci p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci /* determine entry word length and lengths to go in pages */ 9998c2ecf20Sopenharmony_ci num_entry_words = p1 - tmp; 10008c2ecf20Sopenharmony_ci len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer; 10018c2ecf20Sopenharmony_ci if ((num_entry_words << 2) < len1) { 10028c2ecf20Sopenharmony_ci /* the actual number of words in the entry is less 10038c2ecf20Sopenharmony_ci * than elen and can still fit in the current page 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ci memmove(p, tmp, num_entry_words << 2); 10068c2ecf20Sopenharmony_ci p += num_entry_words; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* update offset */ 10098c2ecf20Sopenharmony_ci cd->offset = cd->buffer + (cd->offset - tmp); 10108c2ecf20Sopenharmony_ci } else { 10118c2ecf20Sopenharmony_ci unsigned int offset_r = (cd->offset - tmp) << 2; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* update pointer to offset location. 10148c2ecf20Sopenharmony_ci * This is a 64bit quantity, so we need to 10158c2ecf20Sopenharmony_ci * deal with 3 cases: 10168c2ecf20Sopenharmony_ci * - entirely in first page 10178c2ecf20Sopenharmony_ci * - entirely in second page 10188c2ecf20Sopenharmony_ci * - 4 bytes in each page 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_ci if (offset_r + 8 <= len1) { 10218c2ecf20Sopenharmony_ci cd->offset = p + (cd->offset - tmp); 10228c2ecf20Sopenharmony_ci } else if (offset_r >= len1) { 10238c2ecf20Sopenharmony_ci cd->offset -= len1 >> 2; 10248c2ecf20Sopenharmony_ci } else { 10258c2ecf20Sopenharmony_ci /* sitting on the fence */ 10268c2ecf20Sopenharmony_ci BUG_ON(offset_r != len1 - 4); 10278c2ecf20Sopenharmony_ci cd->offset = p + (cd->offset - tmp); 10288c2ecf20Sopenharmony_ci cd->offset1 = tmp; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci len2 = (num_entry_words << 2) - len1; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* move from temp page to current and next pages */ 10348c2ecf20Sopenharmony_ci memmove(p, tmp, len1); 10358c2ecf20Sopenharmony_ci memmove(tmp, (caddr_t)tmp+len1, len2); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci p = tmp + (len2 >> 2); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci else { 10418c2ecf20Sopenharmony_ci cd->common.err = nfserr_toosmall; 10428c2ecf20Sopenharmony_ci return -EINVAL; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci cd->buflen -= num_entry_words; 10468c2ecf20Sopenharmony_ci cd->buffer = p; 10478c2ecf20Sopenharmony_ci cd->common.err = nfs_ok; 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ciint 10538c2ecf20Sopenharmony_cinfs3svc_encode_entry(void *cd, const char *name, 10548c2ecf20Sopenharmony_ci int namlen, loff_t offset, u64 ino, unsigned int d_type) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci return encode_entry(cd, name, namlen, offset, ino, d_type, 0); 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ciint 10608c2ecf20Sopenharmony_cinfs3svc_encode_entry_plus(void *cd, const char *name, 10618c2ecf20Sopenharmony_ci int namlen, loff_t offset, u64 ino, 10628c2ecf20Sopenharmony_ci unsigned int d_type) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci return encode_entry(cd, name, namlen, offset, ino, d_type, 1); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci/* FSSTAT */ 10688c2ecf20Sopenharmony_ciint 10698c2ecf20Sopenharmony_cinfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci struct nfsd3_fsstatres *resp = rqstp->rq_resp; 10728c2ecf20Sopenharmony_ci struct kstatfs *s = &resp->stats; 10738c2ecf20Sopenharmony_ci u64 bs = s->f_bsize; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci *p++ = resp->status; 10768c2ecf20Sopenharmony_ci *p++ = xdr_zero; /* no post_op_attr */ 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (resp->status == 0) { 10798c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ 10808c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ 10818c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ 10828c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, s->f_files); /* total inodes */ 10838c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ 10848c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ 10858c2ecf20Sopenharmony_ci *p++ = htonl(resp->invarsec); /* mean unchanged time */ 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci/* FSINFO */ 10918c2ecf20Sopenharmony_ciint 10928c2ecf20Sopenharmony_cinfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci struct nfsd3_fsinfores *resp = rqstp->rq_resp; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci *p++ = resp->status; 10978c2ecf20Sopenharmony_ci *p++ = xdr_zero; /* no post_op_attr */ 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (resp->status == 0) { 11008c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_rtmax); 11018c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_rtpref); 11028c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_rtmult); 11038c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_wtmax); 11048c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_wtpref); 11058c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_wtmult); 11068c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_dtpref); 11078c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, resp->f_maxfilesize); 11088c2ecf20Sopenharmony_ci *p++ = xdr_one; 11098c2ecf20Sopenharmony_ci *p++ = xdr_zero; 11108c2ecf20Sopenharmony_ci *p++ = htonl(resp->f_properties); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/* PATHCONF */ 11178c2ecf20Sopenharmony_ciint 11188c2ecf20Sopenharmony_cinfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci struct nfsd3_pathconfres *resp = rqstp->rq_resp; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci *p++ = resp->status; 11238c2ecf20Sopenharmony_ci *p++ = xdr_zero; /* no post_op_attr */ 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (resp->status == 0) { 11268c2ecf20Sopenharmony_ci *p++ = htonl(resp->p_link_max); 11278c2ecf20Sopenharmony_ci *p++ = htonl(resp->p_name_max); 11288c2ecf20Sopenharmony_ci *p++ = htonl(resp->p_no_trunc); 11298c2ecf20Sopenharmony_ci *p++ = htonl(resp->p_chown_restricted); 11308c2ecf20Sopenharmony_ci *p++ = htonl(resp->p_case_insensitive); 11318c2ecf20Sopenharmony_ci *p++ = htonl(resp->p_case_preserving); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci/* COMMIT */ 11388c2ecf20Sopenharmony_ciint 11398c2ecf20Sopenharmony_cinfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct nfsd3_commitres *resp = rqstp->rq_resp; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci *p++ = resp->status; 11448c2ecf20Sopenharmony_ci p = encode_wcc_data(rqstp, p, &resp->fh); 11458c2ecf20Sopenharmony_ci /* Write verifier */ 11468c2ecf20Sopenharmony_ci if (resp->status == 0) { 11478c2ecf20Sopenharmony_ci *p++ = resp->verf[0]; 11488c2ecf20Sopenharmony_ci *p++ = resp->verf[1]; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci return xdr_ressize_check(rqstp, p); 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci/* 11548c2ecf20Sopenharmony_ci * XDR release functions 11558c2ecf20Sopenharmony_ci */ 11568c2ecf20Sopenharmony_civoid 11578c2ecf20Sopenharmony_cinfs3svc_release_fhandle(struct svc_rqst *rqstp) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct nfsd3_attrstat *resp = rqstp->rq_resp; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci fh_put(&resp->fh); 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_civoid 11658c2ecf20Sopenharmony_cinfs3svc_release_fhandle2(struct svc_rqst *rqstp) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci struct nfsd3_fhandle_pair *resp = rqstp->rq_resp; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci fh_put(&resp->fh1); 11708c2ecf20Sopenharmony_ci fh_put(&resp->fh2); 11718c2ecf20Sopenharmony_ci} 1172