162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Process version 2 NFS requests. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/namei.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "cache.h" 1162306a36Sopenharmony_ci#include "xdr.h" 1262306a36Sopenharmony_ci#include "vfs.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define NFSDDBG_FACILITY NFSDDBG_PROC 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic __be32 1762306a36Sopenharmony_cinfsd_proc_null(struct svc_rqst *rqstp) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci return rpc_success; 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * Get a file's attributes 2462306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic __be32 2762306a36Sopenharmony_cinfsd_proc_getattr(struct svc_rqst *rqstp) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct nfsd_fhandle *argp = rqstp->rq_argp; 3062306a36Sopenharmony_ci struct nfsd_attrstat *resp = rqstp->rq_resp; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci fh_copy(&resp->fh, &argp->fh); 3562306a36Sopenharmony_ci resp->status = fh_verify(rqstp, &resp->fh, 0, 3662306a36Sopenharmony_ci NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); 3762306a36Sopenharmony_ci if (resp->status != nfs_ok) 3862306a36Sopenharmony_ci goto out; 3962306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 4062306a36Sopenharmony_ciout: 4162306a36Sopenharmony_ci return rpc_success; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Set a file's attributes 4662306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic __be32 4962306a36Sopenharmony_cinfsd_proc_setattr(struct svc_rqst *rqstp) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct nfsd_sattrargs *argp = rqstp->rq_argp; 5262306a36Sopenharmony_ci struct nfsd_attrstat *resp = rqstp->rq_resp; 5362306a36Sopenharmony_ci struct iattr *iap = &argp->attrs; 5462306a36Sopenharmony_ci struct nfsd_attrs attrs = { 5562306a36Sopenharmony_ci .na_iattr = iap, 5662306a36Sopenharmony_ci }; 5762306a36Sopenharmony_ci struct svc_fh *fhp; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", 6062306a36Sopenharmony_ci SVCFH_fmt(&argp->fh), 6162306a36Sopenharmony_ci argp->attrs.ia_valid, (long) argp->attrs.ia_size); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci fhp = fh_copy(&resp->fh, &argp->fh); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* 6662306a36Sopenharmony_ci * NFSv2 does not differentiate between "set-[ac]time-to-now" 6762306a36Sopenharmony_ci * which only requires access, and "set-[ac]time-to-X" which 6862306a36Sopenharmony_ci * requires ownership. 6962306a36Sopenharmony_ci * So if it looks like it might be "set both to the same time which 7062306a36Sopenharmony_ci * is close to now", and if setattr_prepare fails, then we 7162306a36Sopenharmony_ci * convert to "set to now" instead of "set to explicit time" 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * We only call setattr_prepare as the last test as technically 7462306a36Sopenharmony_ci * it is not an interface that we should be using. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) 7762306a36Sopenharmony_ci#define MAX_TOUCH_TIME_ERROR (30*60) 7862306a36Sopenharmony_ci if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && 7962306a36Sopenharmony_ci iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * Looks probable. 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * Now just make sure time is in the right ballpark. 8462306a36Sopenharmony_ci * Solaris, at least, doesn't seem to care what the time 8562306a36Sopenharmony_ci * request is. We require it be within 30 minutes of now. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds(); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); 9062306a36Sopenharmony_ci if (resp->status != nfs_ok) 9162306a36Sopenharmony_ci goto out; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (delta < 0) 9462306a36Sopenharmony_ci delta = -delta; 9562306a36Sopenharmony_ci if (delta < MAX_TOUCH_TIME_ERROR && 9662306a36Sopenharmony_ci setattr_prepare(&nop_mnt_idmap, fhp->fh_dentry, iap) != 0) { 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. 9962306a36Sopenharmony_ci * This will cause notify_change to set these times 10062306a36Sopenharmony_ci * to "now" 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci iap->ia_valid &= ~BOTH_TIME_SET; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0); 10762306a36Sopenharmony_ci if (resp->status != nfs_ok) 10862306a36Sopenharmony_ci goto out; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 11162306a36Sopenharmony_ciout: 11262306a36Sopenharmony_ci return rpc_success; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* Obsolete, replaced by MNTPROC_MNT. */ 11662306a36Sopenharmony_cistatic __be32 11762306a36Sopenharmony_cinfsd_proc_root(struct svc_rqst *rqstp) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return rpc_success; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Look up a path name component 12462306a36Sopenharmony_ci * Note: the dentry in the resp->fh may be negative if the file 12562306a36Sopenharmony_ci * doesn't exist yet. 12662306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic __be32 12962306a36Sopenharmony_cinfsd_proc_lookup(struct svc_rqst *rqstp) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct nfsd_diropargs *argp = rqstp->rq_argp; 13262306a36Sopenharmony_ci struct nfsd_diropres *resp = rqstp->rq_resp; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci dprintk("nfsd: LOOKUP %s %.*s\n", 13562306a36Sopenharmony_ci SVCFH_fmt(&argp->fh), argp->len, argp->name); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci fh_init(&resp->fh, NFS_FHSIZE); 13862306a36Sopenharmony_ci resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, 13962306a36Sopenharmony_ci &resp->fh); 14062306a36Sopenharmony_ci fh_put(&argp->fh); 14162306a36Sopenharmony_ci if (resp->status != nfs_ok) 14262306a36Sopenharmony_ci goto out; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 14562306a36Sopenharmony_ciout: 14662306a36Sopenharmony_ci return rpc_success; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* 15062306a36Sopenharmony_ci * Read a symlink. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic __be32 15362306a36Sopenharmony_cinfsd_proc_readlink(struct svc_rqst *rqstp) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct nfsd_fhandle *argp = rqstp->rq_argp; 15662306a36Sopenharmony_ci struct nfsd_readlinkres *resp = rqstp->rq_resp; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Read the symlink. */ 16162306a36Sopenharmony_ci resp->len = NFS_MAXPATHLEN; 16262306a36Sopenharmony_ci resp->page = *(rqstp->rq_next_page++); 16362306a36Sopenharmony_ci resp->status = nfsd_readlink(rqstp, &argp->fh, 16462306a36Sopenharmony_ci page_address(resp->page), &resp->len); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci fh_put(&argp->fh); 16762306a36Sopenharmony_ci return rpc_success; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * Read a portion of a file. 17262306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic __be32 17562306a36Sopenharmony_cinfsd_proc_read(struct svc_rqst *rqstp) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct nfsd_readargs *argp = rqstp->rq_argp; 17862306a36Sopenharmony_ci struct nfsd_readres *resp = rqstp->rq_resp; 17962306a36Sopenharmony_ci u32 eof; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci dprintk("nfsd: READ %s %d bytes at %d\n", 18262306a36Sopenharmony_ci SVCFH_fmt(&argp->fh), 18362306a36Sopenharmony_ci argp->count, argp->offset); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2); 18662306a36Sopenharmony_ci argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci resp->pages = rqstp->rq_next_page; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Obtain buffer pointer for payload. 19 is 1 word for 19162306a36Sopenharmony_ci * status, 17 words for fattr, and 1 word for the byte count. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci resp->count = argp->count; 19662306a36Sopenharmony_ci fh_copy(&resp->fh, &argp->fh); 19762306a36Sopenharmony_ci resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, 19862306a36Sopenharmony_ci &resp->count, &eof); 19962306a36Sopenharmony_ci if (resp->status == nfs_ok) 20062306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 20162306a36Sopenharmony_ci else if (resp->status == nfserr_jukebox) 20262306a36Sopenharmony_ci set_bit(RQ_DROPME, &rqstp->rq_flags); 20362306a36Sopenharmony_ci return rpc_success; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* Reserved */ 20762306a36Sopenharmony_cistatic __be32 20862306a36Sopenharmony_cinfsd_proc_writecache(struct svc_rqst *rqstp) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci return rpc_success; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* 21462306a36Sopenharmony_ci * Write data to a file 21562306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_cistatic __be32 21862306a36Sopenharmony_cinfsd_proc_write(struct svc_rqst *rqstp) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct nfsd_writeargs *argp = rqstp->rq_argp; 22162306a36Sopenharmony_ci struct nfsd_attrstat *resp = rqstp->rq_resp; 22262306a36Sopenharmony_ci unsigned long cnt = argp->len; 22362306a36Sopenharmony_ci unsigned int nvecs; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci dprintk("nfsd: WRITE %s %u bytes at %d\n", 22662306a36Sopenharmony_ci SVCFH_fmt(&argp->fh), 22762306a36Sopenharmony_ci argp->len, argp->offset); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci nvecs = svc_fill_write_vector(rqstp, &argp->payload); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), 23262306a36Sopenharmony_ci argp->offset, rqstp->rq_vec, nvecs, 23362306a36Sopenharmony_ci &cnt, NFS_DATA_SYNC, NULL); 23462306a36Sopenharmony_ci if (resp->status == nfs_ok) 23562306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 23662306a36Sopenharmony_ci else if (resp->status == nfserr_jukebox) 23762306a36Sopenharmony_ci set_bit(RQ_DROPME, &rqstp->rq_flags); 23862306a36Sopenharmony_ci return rpc_success; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* 24262306a36Sopenharmony_ci * CREATE processing is complicated. The keyword here is `overloaded.' 24362306a36Sopenharmony_ci * The parent directory is kept locked between the check for existence 24462306a36Sopenharmony_ci * and the actual create() call in compliance with VFS protocols. 24562306a36Sopenharmony_ci * N.B. After this call _both_ argp->fh and resp->fh need an fh_put 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistatic __be32 24862306a36Sopenharmony_cinfsd_proc_create(struct svc_rqst *rqstp) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct nfsd_createargs *argp = rqstp->rq_argp; 25162306a36Sopenharmony_ci struct nfsd_diropres *resp = rqstp->rq_resp; 25262306a36Sopenharmony_ci svc_fh *dirfhp = &argp->fh; 25362306a36Sopenharmony_ci svc_fh *newfhp = &resp->fh; 25462306a36Sopenharmony_ci struct iattr *attr = &argp->attrs; 25562306a36Sopenharmony_ci struct nfsd_attrs attrs = { 25662306a36Sopenharmony_ci .na_iattr = attr, 25762306a36Sopenharmony_ci }; 25862306a36Sopenharmony_ci struct inode *inode; 25962306a36Sopenharmony_ci struct dentry *dchild; 26062306a36Sopenharmony_ci int type, mode; 26162306a36Sopenharmony_ci int hosterr; 26262306a36Sopenharmony_ci dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dprintk("nfsd: CREATE %s %.*s\n", 26562306a36Sopenharmony_ci SVCFH_fmt(dirfhp), argp->len, argp->name); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* First verify the parent file handle */ 26862306a36Sopenharmony_ci resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); 26962306a36Sopenharmony_ci if (resp->status != nfs_ok) 27062306a36Sopenharmony_ci goto done; /* must fh_put dirfhp even on error */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci resp->status = nfserr_exist; 27562306a36Sopenharmony_ci if (isdotent(argp->name, argp->len)) 27662306a36Sopenharmony_ci goto done; 27762306a36Sopenharmony_ci hosterr = fh_want_write(dirfhp); 27862306a36Sopenharmony_ci if (hosterr) { 27962306a36Sopenharmony_ci resp->status = nfserrno(hosterr); 28062306a36Sopenharmony_ci goto done; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT); 28462306a36Sopenharmony_ci dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); 28562306a36Sopenharmony_ci if (IS_ERR(dchild)) { 28662306a36Sopenharmony_ci resp->status = nfserrno(PTR_ERR(dchild)); 28762306a36Sopenharmony_ci goto out_unlock; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci fh_init(newfhp, NFS_FHSIZE); 29062306a36Sopenharmony_ci resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); 29162306a36Sopenharmony_ci if (!resp->status && d_really_is_negative(dchild)) 29262306a36Sopenharmony_ci resp->status = nfserr_noent; 29362306a36Sopenharmony_ci dput(dchild); 29462306a36Sopenharmony_ci if (resp->status) { 29562306a36Sopenharmony_ci if (resp->status != nfserr_noent) 29662306a36Sopenharmony_ci goto out_unlock; 29762306a36Sopenharmony_ci /* 29862306a36Sopenharmony_ci * If the new file handle wasn't verified, we can't tell 29962306a36Sopenharmony_ci * whether the file exists or not. Time to bail ... 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci resp->status = nfserr_acces; 30262306a36Sopenharmony_ci if (!newfhp->fh_dentry) { 30362306a36Sopenharmony_ci printk(KERN_WARNING 30462306a36Sopenharmony_ci "nfsd_proc_create: file handle not verified\n"); 30562306a36Sopenharmony_ci goto out_unlock; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci inode = d_inode(newfhp->fh_dentry); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Unfudge the mode bits */ 31262306a36Sopenharmony_ci if (attr->ia_valid & ATTR_MODE) { 31362306a36Sopenharmony_ci type = attr->ia_mode & S_IFMT; 31462306a36Sopenharmony_ci mode = attr->ia_mode & ~S_IFMT; 31562306a36Sopenharmony_ci if (!type) { 31662306a36Sopenharmony_ci /* no type, so if target exists, assume same as that, 31762306a36Sopenharmony_ci * else assume a file */ 31862306a36Sopenharmony_ci if (inode) { 31962306a36Sopenharmony_ci type = inode->i_mode & S_IFMT; 32062306a36Sopenharmony_ci switch(type) { 32162306a36Sopenharmony_ci case S_IFCHR: 32262306a36Sopenharmony_ci case S_IFBLK: 32362306a36Sopenharmony_ci /* reserve rdev for later checking */ 32462306a36Sopenharmony_ci rdev = inode->i_rdev; 32562306a36Sopenharmony_ci attr->ia_valid |= ATTR_SIZE; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci fallthrough; 32862306a36Sopenharmony_ci case S_IFIFO: 32962306a36Sopenharmony_ci /* this is probably a permission check.. 33062306a36Sopenharmony_ci * at least IRIX implements perm checking on 33162306a36Sopenharmony_ci * echo thing > device-special-file-or-pipe 33262306a36Sopenharmony_ci * by doing a CREATE with type==0 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci resp->status = nfsd_permission(rqstp, 33562306a36Sopenharmony_ci newfhp->fh_export, 33662306a36Sopenharmony_ci newfhp->fh_dentry, 33762306a36Sopenharmony_ci NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); 33862306a36Sopenharmony_ci if (resp->status && resp->status != nfserr_rofs) 33962306a36Sopenharmony_ci goto out_unlock; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } else 34262306a36Sopenharmony_ci type = S_IFREG; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } else if (inode) { 34562306a36Sopenharmony_ci type = inode->i_mode & S_IFMT; 34662306a36Sopenharmony_ci mode = inode->i_mode & ~S_IFMT; 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci type = S_IFREG; 34962306a36Sopenharmony_ci mode = 0; /* ??? */ 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci attr->ia_valid |= ATTR_MODE; 35362306a36Sopenharmony_ci attr->ia_mode = mode; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Special treatment for non-regular files according to the 35662306a36Sopenharmony_ci * gospel of sun micro 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci if (type != S_IFREG) { 35962306a36Sopenharmony_ci if (type != S_IFBLK && type != S_IFCHR) { 36062306a36Sopenharmony_ci rdev = 0; 36162306a36Sopenharmony_ci } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { 36262306a36Sopenharmony_ci /* If you think you've seen the worst, grok this. */ 36362306a36Sopenharmony_ci type = S_IFIFO; 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci /* Okay, char or block special */ 36662306a36Sopenharmony_ci if (!rdev) 36762306a36Sopenharmony_ci rdev = wanted; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* we've used the SIZE information, so discard it */ 37162306a36Sopenharmony_ci attr->ia_valid &= ~ATTR_SIZE; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* Make sure the type and device matches */ 37462306a36Sopenharmony_ci resp->status = nfserr_exist; 37562306a36Sopenharmony_ci if (inode && inode_wrong_type(inode, type)) 37662306a36Sopenharmony_ci goto out_unlock; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci resp->status = nfs_ok; 38062306a36Sopenharmony_ci if (!inode) { 38162306a36Sopenharmony_ci /* File doesn't exist. Create it and set attrs */ 38262306a36Sopenharmony_ci resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type, 38362306a36Sopenharmony_ci rdev, newfhp); 38462306a36Sopenharmony_ci } else if (type == S_IFREG) { 38562306a36Sopenharmony_ci dprintk("nfsd: existing %s, valid=%x, size=%ld\n", 38662306a36Sopenharmony_ci argp->name, attr->ia_valid, (long) attr->ia_size); 38762306a36Sopenharmony_ci /* File already exists. We ignore all attributes except 38862306a36Sopenharmony_ci * size, so that creat() behaves exactly like 38962306a36Sopenharmony_ci * open(..., O_CREAT|O_TRUNC|O_WRONLY). 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci attr->ia_valid &= ATTR_SIZE; 39262306a36Sopenharmony_ci if (attr->ia_valid) 39362306a36Sopenharmony_ci resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0, 39462306a36Sopenharmony_ci (time64_t)0); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ciout_unlock: 39862306a36Sopenharmony_ci inode_unlock(dirfhp->fh_dentry->d_inode); 39962306a36Sopenharmony_ci fh_drop_write(dirfhp); 40062306a36Sopenharmony_cidone: 40162306a36Sopenharmony_ci fh_put(dirfhp); 40262306a36Sopenharmony_ci if (resp->status != nfs_ok) 40362306a36Sopenharmony_ci goto out; 40462306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 40562306a36Sopenharmony_ciout: 40662306a36Sopenharmony_ci return rpc_success; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic __be32 41062306a36Sopenharmony_cinfsd_proc_remove(struct svc_rqst *rqstp) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci struct nfsd_diropargs *argp = rqstp->rq_argp; 41362306a36Sopenharmony_ci struct nfsd_stat *resp = rqstp->rq_resp; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh), 41662306a36Sopenharmony_ci argp->len, argp->name); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* Unlink. -SIFDIR means file must not be a directory */ 41962306a36Sopenharmony_ci resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, 42062306a36Sopenharmony_ci argp->name, argp->len); 42162306a36Sopenharmony_ci fh_put(&argp->fh); 42262306a36Sopenharmony_ci return rpc_success; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic __be32 42662306a36Sopenharmony_cinfsd_proc_rename(struct svc_rqst *rqstp) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct nfsd_renameargs *argp = rqstp->rq_argp; 42962306a36Sopenharmony_ci struct nfsd_stat *resp = rqstp->rq_resp; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci dprintk("nfsd: RENAME %s %.*s -> \n", 43262306a36Sopenharmony_ci SVCFH_fmt(&argp->ffh), argp->flen, argp->fname); 43362306a36Sopenharmony_ci dprintk("nfsd: -> %s %.*s\n", 43462306a36Sopenharmony_ci SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, 43762306a36Sopenharmony_ci &argp->tfh, argp->tname, argp->tlen); 43862306a36Sopenharmony_ci fh_put(&argp->ffh); 43962306a36Sopenharmony_ci fh_put(&argp->tfh); 44062306a36Sopenharmony_ci return rpc_success; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic __be32 44462306a36Sopenharmony_cinfsd_proc_link(struct svc_rqst *rqstp) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct nfsd_linkargs *argp = rqstp->rq_argp; 44762306a36Sopenharmony_ci struct nfsd_stat *resp = rqstp->rq_resp; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci dprintk("nfsd: LINK %s ->\n", 45062306a36Sopenharmony_ci SVCFH_fmt(&argp->ffh)); 45162306a36Sopenharmony_ci dprintk("nfsd: %s %.*s\n", 45262306a36Sopenharmony_ci SVCFH_fmt(&argp->tfh), 45362306a36Sopenharmony_ci argp->tlen, 45462306a36Sopenharmony_ci argp->tname); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, 45762306a36Sopenharmony_ci &argp->ffh); 45862306a36Sopenharmony_ci fh_put(&argp->ffh); 45962306a36Sopenharmony_ci fh_put(&argp->tfh); 46062306a36Sopenharmony_ci return rpc_success; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic __be32 46462306a36Sopenharmony_cinfsd_proc_symlink(struct svc_rqst *rqstp) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct nfsd_symlinkargs *argp = rqstp->rq_argp; 46762306a36Sopenharmony_ci struct nfsd_stat *resp = rqstp->rq_resp; 46862306a36Sopenharmony_ci struct nfsd_attrs attrs = { 46962306a36Sopenharmony_ci .na_iattr = &argp->attrs, 47062306a36Sopenharmony_ci }; 47162306a36Sopenharmony_ci struct svc_fh newfh; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (argp->tlen > NFS_MAXPATHLEN) { 47462306a36Sopenharmony_ci resp->status = nfserr_nametoolong; 47562306a36Sopenharmony_ci goto out; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, 47962306a36Sopenharmony_ci page_address(rqstp->rq_arg.pages[0]), 48062306a36Sopenharmony_ci argp->tlen); 48162306a36Sopenharmony_ci if (IS_ERR(argp->tname)) { 48262306a36Sopenharmony_ci resp->status = nfserrno(PTR_ERR(argp->tname)); 48362306a36Sopenharmony_ci goto out; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n", 48762306a36Sopenharmony_ci SVCFH_fmt(&argp->ffh), argp->flen, argp->fname, 48862306a36Sopenharmony_ci argp->tlen, argp->tname); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci fh_init(&newfh, NFS_FHSIZE); 49162306a36Sopenharmony_ci resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, 49262306a36Sopenharmony_ci argp->tname, &attrs, &newfh); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci kfree(argp->tname); 49562306a36Sopenharmony_ci fh_put(&argp->ffh); 49662306a36Sopenharmony_ci fh_put(&newfh); 49762306a36Sopenharmony_ciout: 49862306a36Sopenharmony_ci return rpc_success; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* 50262306a36Sopenharmony_ci * Make directory. This operation is not idempotent. 50362306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_cistatic __be32 50662306a36Sopenharmony_cinfsd_proc_mkdir(struct svc_rqst *rqstp) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct nfsd_createargs *argp = rqstp->rq_argp; 50962306a36Sopenharmony_ci struct nfsd_diropres *resp = rqstp->rq_resp; 51062306a36Sopenharmony_ci struct nfsd_attrs attrs = { 51162306a36Sopenharmony_ci .na_iattr = &argp->attrs, 51262306a36Sopenharmony_ci }; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (resp->fh.fh_dentry) { 51762306a36Sopenharmony_ci printk(KERN_WARNING 51862306a36Sopenharmony_ci "nfsd_proc_mkdir: response already verified??\n"); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci argp->attrs.ia_valid &= ~ATTR_SIZE; 52262306a36Sopenharmony_ci fh_init(&resp->fh, NFS_FHSIZE); 52362306a36Sopenharmony_ci resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, 52462306a36Sopenharmony_ci &attrs, S_IFDIR, 0, &resp->fh); 52562306a36Sopenharmony_ci fh_put(&argp->fh); 52662306a36Sopenharmony_ci if (resp->status != nfs_ok) 52762306a36Sopenharmony_ci goto out; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci resp->status = fh_getattr(&resp->fh, &resp->stat); 53062306a36Sopenharmony_ciout: 53162306a36Sopenharmony_ci return rpc_success; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* 53562306a36Sopenharmony_ci * Remove a directory 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_cistatic __be32 53862306a36Sopenharmony_cinfsd_proc_rmdir(struct svc_rqst *rqstp) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct nfsd_diropargs *argp = rqstp->rq_argp; 54162306a36Sopenharmony_ci struct nfsd_stat *resp = rqstp->rq_resp; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, 54662306a36Sopenharmony_ci argp->name, argp->len); 54762306a36Sopenharmony_ci fh_put(&argp->fh); 54862306a36Sopenharmony_ci return rpc_success; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, 55262306a36Sopenharmony_ci struct nfsd_readdirres *resp, 55362306a36Sopenharmony_ci u32 count) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct xdr_buf *buf = &resp->dirlist; 55662306a36Sopenharmony_ci struct xdr_stream *xdr = &resp->xdr; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci memset(buf, 0, sizeof(*buf)); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Reserve room for the NULL ptr & eof flag (-2 words) */ 56162306a36Sopenharmony_ci buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), (u32)PAGE_SIZE); 56262306a36Sopenharmony_ci buf->buflen -= XDR_UNIT * 2; 56362306a36Sopenharmony_ci buf->pages = rqstp->rq_next_page; 56462306a36Sopenharmony_ci rqstp->rq_next_page++; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci xdr_init_encode_pages(xdr, buf, buf->pages, NULL); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/* 57062306a36Sopenharmony_ci * Read a portion of a directory. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_cistatic __be32 57362306a36Sopenharmony_cinfsd_proc_readdir(struct svc_rqst *rqstp) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct nfsd_readdirargs *argp = rqstp->rq_argp; 57662306a36Sopenharmony_ci struct nfsd_readdirres *resp = rqstp->rq_resp; 57762306a36Sopenharmony_ci loff_t offset; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci dprintk("nfsd: READDIR %s %d bytes at %d\n", 58062306a36Sopenharmony_ci SVCFH_fmt(&argp->fh), 58162306a36Sopenharmony_ci argp->count, argp->cookie); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci nfsd_init_dirlist_pages(rqstp, resp, argp->count); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci resp->common.err = nfs_ok; 58662306a36Sopenharmony_ci resp->cookie_offset = 0; 58762306a36Sopenharmony_ci offset = argp->cookie; 58862306a36Sopenharmony_ci resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, 58962306a36Sopenharmony_ci &resp->common, nfssvc_encode_entry); 59062306a36Sopenharmony_ci nfssvc_encode_nfscookie(resp, offset); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci fh_put(&argp->fh); 59362306a36Sopenharmony_ci return rpc_success; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/* 59762306a36Sopenharmony_ci * Get file system info 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_cistatic __be32 60062306a36Sopenharmony_cinfsd_proc_statfs(struct svc_rqst *rqstp) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct nfsd_fhandle *argp = rqstp->rq_argp; 60362306a36Sopenharmony_ci struct nfsd_statfsres *resp = rqstp->rq_resp; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 60862306a36Sopenharmony_ci NFSD_MAY_BYPASS_GSS_ON_ROOT); 60962306a36Sopenharmony_ci fh_put(&argp->fh); 61062306a36Sopenharmony_ci return rpc_success; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/* 61462306a36Sopenharmony_ci * NFSv2 Server procedures. 61562306a36Sopenharmony_ci * Only the results of non-idempotent operations are cached. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci#define ST 1 /* status */ 61962306a36Sopenharmony_ci#define FH 8 /* filehandle */ 62062306a36Sopenharmony_ci#define AT 18 /* attributes */ 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic const struct svc_procedure nfsd_procedures2[18] = { 62362306a36Sopenharmony_ci [NFSPROC_NULL] = { 62462306a36Sopenharmony_ci .pc_func = nfsd_proc_null, 62562306a36Sopenharmony_ci .pc_decode = nfssvc_decode_voidarg, 62662306a36Sopenharmony_ci .pc_encode = nfssvc_encode_voidres, 62762306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_voidargs), 62862306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_voidargs), 62962306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_voidres), 63062306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 63162306a36Sopenharmony_ci .pc_xdrressize = 0, 63262306a36Sopenharmony_ci .pc_name = "NULL", 63362306a36Sopenharmony_ci }, 63462306a36Sopenharmony_ci [NFSPROC_GETATTR] = { 63562306a36Sopenharmony_ci .pc_func = nfsd_proc_getattr, 63662306a36Sopenharmony_ci .pc_decode = nfssvc_decode_fhandleargs, 63762306a36Sopenharmony_ci .pc_encode = nfssvc_encode_attrstatres, 63862306a36Sopenharmony_ci .pc_release = nfssvc_release_attrstat, 63962306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_fhandle), 64062306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_fhandle), 64162306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_attrstat), 64262306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 64362306a36Sopenharmony_ci .pc_xdrressize = ST+AT, 64462306a36Sopenharmony_ci .pc_name = "GETATTR", 64562306a36Sopenharmony_ci }, 64662306a36Sopenharmony_ci [NFSPROC_SETATTR] = { 64762306a36Sopenharmony_ci .pc_func = nfsd_proc_setattr, 64862306a36Sopenharmony_ci .pc_decode = nfssvc_decode_sattrargs, 64962306a36Sopenharmony_ci .pc_encode = nfssvc_encode_attrstatres, 65062306a36Sopenharmony_ci .pc_release = nfssvc_release_attrstat, 65162306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_sattrargs), 65262306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_sattrargs), 65362306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_attrstat), 65462306a36Sopenharmony_ci .pc_cachetype = RC_REPLBUFF, 65562306a36Sopenharmony_ci .pc_xdrressize = ST+AT, 65662306a36Sopenharmony_ci .pc_name = "SETATTR", 65762306a36Sopenharmony_ci }, 65862306a36Sopenharmony_ci [NFSPROC_ROOT] = { 65962306a36Sopenharmony_ci .pc_func = nfsd_proc_root, 66062306a36Sopenharmony_ci .pc_decode = nfssvc_decode_voidarg, 66162306a36Sopenharmony_ci .pc_encode = nfssvc_encode_voidres, 66262306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_voidargs), 66362306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_voidargs), 66462306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_voidres), 66562306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 66662306a36Sopenharmony_ci .pc_xdrressize = 0, 66762306a36Sopenharmony_ci .pc_name = "ROOT", 66862306a36Sopenharmony_ci }, 66962306a36Sopenharmony_ci [NFSPROC_LOOKUP] = { 67062306a36Sopenharmony_ci .pc_func = nfsd_proc_lookup, 67162306a36Sopenharmony_ci .pc_decode = nfssvc_decode_diropargs, 67262306a36Sopenharmony_ci .pc_encode = nfssvc_encode_diropres, 67362306a36Sopenharmony_ci .pc_release = nfssvc_release_diropres, 67462306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_diropargs), 67562306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_diropargs), 67662306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_diropres), 67762306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 67862306a36Sopenharmony_ci .pc_xdrressize = ST+FH+AT, 67962306a36Sopenharmony_ci .pc_name = "LOOKUP", 68062306a36Sopenharmony_ci }, 68162306a36Sopenharmony_ci [NFSPROC_READLINK] = { 68262306a36Sopenharmony_ci .pc_func = nfsd_proc_readlink, 68362306a36Sopenharmony_ci .pc_decode = nfssvc_decode_fhandleargs, 68462306a36Sopenharmony_ci .pc_encode = nfssvc_encode_readlinkres, 68562306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_fhandle), 68662306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_fhandle), 68762306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_readlinkres), 68862306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 68962306a36Sopenharmony_ci .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, 69062306a36Sopenharmony_ci .pc_name = "READLINK", 69162306a36Sopenharmony_ci }, 69262306a36Sopenharmony_ci [NFSPROC_READ] = { 69362306a36Sopenharmony_ci .pc_func = nfsd_proc_read, 69462306a36Sopenharmony_ci .pc_decode = nfssvc_decode_readargs, 69562306a36Sopenharmony_ci .pc_encode = nfssvc_encode_readres, 69662306a36Sopenharmony_ci .pc_release = nfssvc_release_readres, 69762306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_readargs), 69862306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_readargs), 69962306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_readres), 70062306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 70162306a36Sopenharmony_ci .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, 70262306a36Sopenharmony_ci .pc_name = "READ", 70362306a36Sopenharmony_ci }, 70462306a36Sopenharmony_ci [NFSPROC_WRITECACHE] = { 70562306a36Sopenharmony_ci .pc_func = nfsd_proc_writecache, 70662306a36Sopenharmony_ci .pc_decode = nfssvc_decode_voidarg, 70762306a36Sopenharmony_ci .pc_encode = nfssvc_encode_voidres, 70862306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_voidargs), 70962306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_voidargs), 71062306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_voidres), 71162306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 71262306a36Sopenharmony_ci .pc_xdrressize = 0, 71362306a36Sopenharmony_ci .pc_name = "WRITECACHE", 71462306a36Sopenharmony_ci }, 71562306a36Sopenharmony_ci [NFSPROC_WRITE] = { 71662306a36Sopenharmony_ci .pc_func = nfsd_proc_write, 71762306a36Sopenharmony_ci .pc_decode = nfssvc_decode_writeargs, 71862306a36Sopenharmony_ci .pc_encode = nfssvc_encode_attrstatres, 71962306a36Sopenharmony_ci .pc_release = nfssvc_release_attrstat, 72062306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_writeargs), 72162306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_writeargs), 72262306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_attrstat), 72362306a36Sopenharmony_ci .pc_cachetype = RC_REPLBUFF, 72462306a36Sopenharmony_ci .pc_xdrressize = ST+AT, 72562306a36Sopenharmony_ci .pc_name = "WRITE", 72662306a36Sopenharmony_ci }, 72762306a36Sopenharmony_ci [NFSPROC_CREATE] = { 72862306a36Sopenharmony_ci .pc_func = nfsd_proc_create, 72962306a36Sopenharmony_ci .pc_decode = nfssvc_decode_createargs, 73062306a36Sopenharmony_ci .pc_encode = nfssvc_encode_diropres, 73162306a36Sopenharmony_ci .pc_release = nfssvc_release_diropres, 73262306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_createargs), 73362306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_createargs), 73462306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_diropres), 73562306a36Sopenharmony_ci .pc_cachetype = RC_REPLBUFF, 73662306a36Sopenharmony_ci .pc_xdrressize = ST+FH+AT, 73762306a36Sopenharmony_ci .pc_name = "CREATE", 73862306a36Sopenharmony_ci }, 73962306a36Sopenharmony_ci [NFSPROC_REMOVE] = { 74062306a36Sopenharmony_ci .pc_func = nfsd_proc_remove, 74162306a36Sopenharmony_ci .pc_decode = nfssvc_decode_diropargs, 74262306a36Sopenharmony_ci .pc_encode = nfssvc_encode_statres, 74362306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_diropargs), 74462306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_diropargs), 74562306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_stat), 74662306a36Sopenharmony_ci .pc_cachetype = RC_REPLSTAT, 74762306a36Sopenharmony_ci .pc_xdrressize = ST, 74862306a36Sopenharmony_ci .pc_name = "REMOVE", 74962306a36Sopenharmony_ci }, 75062306a36Sopenharmony_ci [NFSPROC_RENAME] = { 75162306a36Sopenharmony_ci .pc_func = nfsd_proc_rename, 75262306a36Sopenharmony_ci .pc_decode = nfssvc_decode_renameargs, 75362306a36Sopenharmony_ci .pc_encode = nfssvc_encode_statres, 75462306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_renameargs), 75562306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_renameargs), 75662306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_stat), 75762306a36Sopenharmony_ci .pc_cachetype = RC_REPLSTAT, 75862306a36Sopenharmony_ci .pc_xdrressize = ST, 75962306a36Sopenharmony_ci .pc_name = "RENAME", 76062306a36Sopenharmony_ci }, 76162306a36Sopenharmony_ci [NFSPROC_LINK] = { 76262306a36Sopenharmony_ci .pc_func = nfsd_proc_link, 76362306a36Sopenharmony_ci .pc_decode = nfssvc_decode_linkargs, 76462306a36Sopenharmony_ci .pc_encode = nfssvc_encode_statres, 76562306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_linkargs), 76662306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_linkargs), 76762306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_stat), 76862306a36Sopenharmony_ci .pc_cachetype = RC_REPLSTAT, 76962306a36Sopenharmony_ci .pc_xdrressize = ST, 77062306a36Sopenharmony_ci .pc_name = "LINK", 77162306a36Sopenharmony_ci }, 77262306a36Sopenharmony_ci [NFSPROC_SYMLINK] = { 77362306a36Sopenharmony_ci .pc_func = nfsd_proc_symlink, 77462306a36Sopenharmony_ci .pc_decode = nfssvc_decode_symlinkargs, 77562306a36Sopenharmony_ci .pc_encode = nfssvc_encode_statres, 77662306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_symlinkargs), 77762306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_symlinkargs), 77862306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_stat), 77962306a36Sopenharmony_ci .pc_cachetype = RC_REPLSTAT, 78062306a36Sopenharmony_ci .pc_xdrressize = ST, 78162306a36Sopenharmony_ci .pc_name = "SYMLINK", 78262306a36Sopenharmony_ci }, 78362306a36Sopenharmony_ci [NFSPROC_MKDIR] = { 78462306a36Sopenharmony_ci .pc_func = nfsd_proc_mkdir, 78562306a36Sopenharmony_ci .pc_decode = nfssvc_decode_createargs, 78662306a36Sopenharmony_ci .pc_encode = nfssvc_encode_diropres, 78762306a36Sopenharmony_ci .pc_release = nfssvc_release_diropres, 78862306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_createargs), 78962306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_createargs), 79062306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_diropres), 79162306a36Sopenharmony_ci .pc_cachetype = RC_REPLBUFF, 79262306a36Sopenharmony_ci .pc_xdrressize = ST+FH+AT, 79362306a36Sopenharmony_ci .pc_name = "MKDIR", 79462306a36Sopenharmony_ci }, 79562306a36Sopenharmony_ci [NFSPROC_RMDIR] = { 79662306a36Sopenharmony_ci .pc_func = nfsd_proc_rmdir, 79762306a36Sopenharmony_ci .pc_decode = nfssvc_decode_diropargs, 79862306a36Sopenharmony_ci .pc_encode = nfssvc_encode_statres, 79962306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_diropargs), 80062306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_diropargs), 80162306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_stat), 80262306a36Sopenharmony_ci .pc_cachetype = RC_REPLSTAT, 80362306a36Sopenharmony_ci .pc_xdrressize = ST, 80462306a36Sopenharmony_ci .pc_name = "RMDIR", 80562306a36Sopenharmony_ci }, 80662306a36Sopenharmony_ci [NFSPROC_READDIR] = { 80762306a36Sopenharmony_ci .pc_func = nfsd_proc_readdir, 80862306a36Sopenharmony_ci .pc_decode = nfssvc_decode_readdirargs, 80962306a36Sopenharmony_ci .pc_encode = nfssvc_encode_readdirres, 81062306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_readdirargs), 81162306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_readdirargs), 81262306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_readdirres), 81362306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 81462306a36Sopenharmony_ci .pc_name = "READDIR", 81562306a36Sopenharmony_ci }, 81662306a36Sopenharmony_ci [NFSPROC_STATFS] = { 81762306a36Sopenharmony_ci .pc_func = nfsd_proc_statfs, 81862306a36Sopenharmony_ci .pc_decode = nfssvc_decode_fhandleargs, 81962306a36Sopenharmony_ci .pc_encode = nfssvc_encode_statfsres, 82062306a36Sopenharmony_ci .pc_argsize = sizeof(struct nfsd_fhandle), 82162306a36Sopenharmony_ci .pc_argzero = sizeof(struct nfsd_fhandle), 82262306a36Sopenharmony_ci .pc_ressize = sizeof(struct nfsd_statfsres), 82362306a36Sopenharmony_ci .pc_cachetype = RC_NOCACHE, 82462306a36Sopenharmony_ci .pc_xdrressize = ST+5, 82562306a36Sopenharmony_ci .pc_name = "STATFS", 82662306a36Sopenharmony_ci }, 82762306a36Sopenharmony_ci}; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic DEFINE_PER_CPU_ALIGNED(unsigned long, 83062306a36Sopenharmony_ci nfsd_count2[ARRAY_SIZE(nfsd_procedures2)]); 83162306a36Sopenharmony_ciconst struct svc_version nfsd_version2 = { 83262306a36Sopenharmony_ci .vs_vers = 2, 83362306a36Sopenharmony_ci .vs_nproc = ARRAY_SIZE(nfsd_procedures2), 83462306a36Sopenharmony_ci .vs_proc = nfsd_procedures2, 83562306a36Sopenharmony_ci .vs_count = nfsd_count2, 83662306a36Sopenharmony_ci .vs_dispatch = nfsd_dispatch, 83762306a36Sopenharmony_ci .vs_xdrsize = NFS2_SVC_XDRSIZE, 83862306a36Sopenharmony_ci}; 839