cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nfsproc.c (23929B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Process version 2 NFS requests.
      4 *
      5 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
      6 */
      7
      8#include <linux/namei.h>
      9
     10#include "cache.h"
     11#include "xdr.h"
     12#include "vfs.h"
     13
     14#define NFSDDBG_FACILITY		NFSDDBG_PROC
     15
     16static __be32
     17nfsd_proc_null(struct svc_rqst *rqstp)
     18{
     19	return rpc_success;
     20}
     21
     22/*
     23 * Get a file's attributes
     24 * N.B. After this call resp->fh needs an fh_put
     25 */
     26static __be32
     27nfsd_proc_getattr(struct svc_rqst *rqstp)
     28{
     29	struct nfsd_fhandle *argp = rqstp->rq_argp;
     30	struct nfsd_attrstat *resp = rqstp->rq_resp;
     31
     32	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
     33
     34	fh_copy(&resp->fh, &argp->fh);
     35	resp->status = fh_verify(rqstp, &resp->fh, 0,
     36				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
     37	if (resp->status != nfs_ok)
     38		goto out;
     39	resp->status = fh_getattr(&resp->fh, &resp->stat);
     40out:
     41	return rpc_success;
     42}
     43
     44/*
     45 * Set a file's attributes
     46 * N.B. After this call resp->fh needs an fh_put
     47 */
     48static __be32
     49nfsd_proc_setattr(struct svc_rqst *rqstp)
     50{
     51	struct nfsd_sattrargs *argp = rqstp->rq_argp;
     52	struct nfsd_attrstat *resp = rqstp->rq_resp;
     53	struct iattr *iap = &argp->attrs;
     54	struct svc_fh *fhp;
     55
     56	dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
     57		SVCFH_fmt(&argp->fh),
     58		argp->attrs.ia_valid, (long) argp->attrs.ia_size);
     59
     60	fhp = fh_copy(&resp->fh, &argp->fh);
     61
     62	/*
     63	 * NFSv2 does not differentiate between "set-[ac]time-to-now"
     64	 * which only requires access, and "set-[ac]time-to-X" which
     65	 * requires ownership.
     66	 * So if it looks like it might be "set both to the same time which
     67	 * is close to now", and if setattr_prepare fails, then we
     68	 * convert to "set to now" instead of "set to explicit time"
     69	 *
     70	 * We only call setattr_prepare as the last test as technically
     71	 * it is not an interface that we should be using.
     72	 */
     73#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
     74#define	MAX_TOUCH_TIME_ERROR (30*60)
     75	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
     76	    iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
     77		/*
     78		 * Looks probable.
     79		 *
     80		 * Now just make sure time is in the right ballpark.
     81		 * Solaris, at least, doesn't seem to care what the time
     82		 * request is.  We require it be within 30 minutes of now.
     83		 */
     84		time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
     85
     86		resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
     87		if (resp->status != nfs_ok)
     88			goto out;
     89
     90		if (delta < 0)
     91			delta = -delta;
     92		if (delta < MAX_TOUCH_TIME_ERROR &&
     93		    setattr_prepare(&init_user_ns, fhp->fh_dentry, iap) != 0) {
     94			/*
     95			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
     96			 * This will cause notify_change to set these times
     97			 * to "now"
     98			 */
     99			iap->ia_valid &= ~BOTH_TIME_SET;
    100		}
    101	}
    102
    103	resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
    104	if (resp->status != nfs_ok)
    105		goto out;
    106
    107	resp->status = fh_getattr(&resp->fh, &resp->stat);
    108out:
    109	return rpc_success;
    110}
    111
    112/* Obsolete, replaced by MNTPROC_MNT. */
    113static __be32
    114nfsd_proc_root(struct svc_rqst *rqstp)
    115{
    116	return rpc_success;
    117}
    118
    119/*
    120 * Look up a path name component
    121 * Note: the dentry in the resp->fh may be negative if the file
    122 * doesn't exist yet.
    123 * N.B. After this call resp->fh needs an fh_put
    124 */
    125static __be32
    126nfsd_proc_lookup(struct svc_rqst *rqstp)
    127{
    128	struct nfsd_diropargs *argp = rqstp->rq_argp;
    129	struct nfsd_diropres *resp = rqstp->rq_resp;
    130
    131	dprintk("nfsd: LOOKUP   %s %.*s\n",
    132		SVCFH_fmt(&argp->fh), argp->len, argp->name);
    133
    134	fh_init(&resp->fh, NFS_FHSIZE);
    135	resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
    136				   &resp->fh);
    137	fh_put(&argp->fh);
    138	if (resp->status != nfs_ok)
    139		goto out;
    140
    141	resp->status = fh_getattr(&resp->fh, &resp->stat);
    142out:
    143	return rpc_success;
    144}
    145
    146/*
    147 * Read a symlink.
    148 */
    149static __be32
    150nfsd_proc_readlink(struct svc_rqst *rqstp)
    151{
    152	struct nfsd_fhandle *argp = rqstp->rq_argp;
    153	struct nfsd_readlinkres *resp = rqstp->rq_resp;
    154
    155	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
    156
    157	/* Read the symlink. */
    158	resp->len = NFS_MAXPATHLEN;
    159	resp->page = *(rqstp->rq_next_page++);
    160	resp->status = nfsd_readlink(rqstp, &argp->fh,
    161				     page_address(resp->page), &resp->len);
    162
    163	fh_put(&argp->fh);
    164	return rpc_success;
    165}
    166
    167/*
    168 * Read a portion of a file.
    169 * N.B. After this call resp->fh needs an fh_put
    170 */
    171static __be32
    172nfsd_proc_read(struct svc_rqst *rqstp)
    173{
    174	struct nfsd_readargs *argp = rqstp->rq_argp;
    175	struct nfsd_readres *resp = rqstp->rq_resp;
    176	unsigned int len;
    177	u32 eof;
    178	int v;
    179
    180	dprintk("nfsd: READ    %s %d bytes at %d\n",
    181		SVCFH_fmt(&argp->fh),
    182		argp->count, argp->offset);
    183
    184	argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
    185
    186	v = 0;
    187	len = argp->count;
    188	resp->pages = rqstp->rq_next_page;
    189	while (len > 0) {
    190		struct page *page = *(rqstp->rq_next_page++);
    191
    192		rqstp->rq_vec[v].iov_base = page_address(page);
    193		rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
    194		len -= rqstp->rq_vec[v].iov_len;
    195		v++;
    196	}
    197
    198	/* Obtain buffer pointer for payload. 19 is 1 word for
    199	 * status, 17 words for fattr, and 1 word for the byte count.
    200	 */
    201	svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
    202
    203	resp->count = argp->count;
    204	fh_copy(&resp->fh, &argp->fh);
    205	resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
    206				 rqstp->rq_vec, v, &resp->count, &eof);
    207	if (resp->status == nfs_ok)
    208		resp->status = fh_getattr(&resp->fh, &resp->stat);
    209	else if (resp->status == nfserr_jukebox)
    210		return rpc_drop_reply;
    211	return rpc_success;
    212}
    213
    214/* Reserved */
    215static __be32
    216nfsd_proc_writecache(struct svc_rqst *rqstp)
    217{
    218	return rpc_success;
    219}
    220
    221/*
    222 * Write data to a file
    223 * N.B. After this call resp->fh needs an fh_put
    224 */
    225static __be32
    226nfsd_proc_write(struct svc_rqst *rqstp)
    227{
    228	struct nfsd_writeargs *argp = rqstp->rq_argp;
    229	struct nfsd_attrstat *resp = rqstp->rq_resp;
    230	unsigned long cnt = argp->len;
    231	unsigned int nvecs;
    232
    233	dprintk("nfsd: WRITE    %s %u bytes at %d\n",
    234		SVCFH_fmt(&argp->fh),
    235		argp->len, argp->offset);
    236
    237	nvecs = svc_fill_write_vector(rqstp, &argp->payload);
    238
    239	resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
    240				  argp->offset, rqstp->rq_vec, nvecs,
    241				  &cnt, NFS_DATA_SYNC, NULL);
    242	if (resp->status == nfs_ok)
    243		resp->status = fh_getattr(&resp->fh, &resp->stat);
    244	else if (resp->status == nfserr_jukebox)
    245		return rpc_drop_reply;
    246	return rpc_success;
    247}
    248
    249/*
    250 * CREATE processing is complicated. The keyword here is `overloaded.'
    251 * The parent directory is kept locked between the check for existence
    252 * and the actual create() call in compliance with VFS protocols.
    253 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
    254 */
    255static __be32
    256nfsd_proc_create(struct svc_rqst *rqstp)
    257{
    258	struct nfsd_createargs *argp = rqstp->rq_argp;
    259	struct nfsd_diropres *resp = rqstp->rq_resp;
    260	svc_fh		*dirfhp = &argp->fh;
    261	svc_fh		*newfhp = &resp->fh;
    262	struct iattr	*attr = &argp->attrs;
    263	struct inode	*inode;
    264	struct dentry	*dchild;
    265	int		type, mode;
    266	int		hosterr;
    267	dev_t		rdev = 0, wanted = new_decode_dev(attr->ia_size);
    268
    269	dprintk("nfsd: CREATE   %s %.*s\n",
    270		SVCFH_fmt(dirfhp), argp->len, argp->name);
    271
    272	/* First verify the parent file handle */
    273	resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
    274	if (resp->status != nfs_ok)
    275		goto done; /* must fh_put dirfhp even on error */
    276
    277	/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
    278
    279	resp->status = nfserr_exist;
    280	if (isdotent(argp->name, argp->len))
    281		goto done;
    282	hosterr = fh_want_write(dirfhp);
    283	if (hosterr) {
    284		resp->status = nfserrno(hosterr);
    285		goto done;
    286	}
    287
    288	fh_lock_nested(dirfhp, I_MUTEX_PARENT);
    289	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
    290	if (IS_ERR(dchild)) {
    291		resp->status = nfserrno(PTR_ERR(dchild));
    292		goto out_unlock;
    293	}
    294	fh_init(newfhp, NFS_FHSIZE);
    295	resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
    296	if (!resp->status && d_really_is_negative(dchild))
    297		resp->status = nfserr_noent;
    298	dput(dchild);
    299	if (resp->status) {
    300		if (resp->status != nfserr_noent)
    301			goto out_unlock;
    302		/*
    303		 * If the new file handle wasn't verified, we can't tell
    304		 * whether the file exists or not. Time to bail ...
    305		 */
    306		resp->status = nfserr_acces;
    307		if (!newfhp->fh_dentry) {
    308			printk(KERN_WARNING 
    309				"nfsd_proc_create: file handle not verified\n");
    310			goto out_unlock;
    311		}
    312	}
    313
    314	inode = d_inode(newfhp->fh_dentry);
    315
    316	/* Unfudge the mode bits */
    317	if (attr->ia_valid & ATTR_MODE) {
    318		type = attr->ia_mode & S_IFMT;
    319		mode = attr->ia_mode & ~S_IFMT;
    320		if (!type) {
    321			/* no type, so if target exists, assume same as that,
    322			 * else assume a file */
    323			if (inode) {
    324				type = inode->i_mode & S_IFMT;
    325				switch(type) {
    326				case S_IFCHR:
    327				case S_IFBLK:
    328					/* reserve rdev for later checking */
    329					rdev = inode->i_rdev;
    330					attr->ia_valid |= ATTR_SIZE;
    331
    332					fallthrough;
    333				case S_IFIFO:
    334					/* this is probably a permission check..
    335					 * at least IRIX implements perm checking on
    336					 *   echo thing > device-special-file-or-pipe
    337					 * by doing a CREATE with type==0
    338					 */
    339					resp->status = nfsd_permission(rqstp,
    340								 newfhp->fh_export,
    341								 newfhp->fh_dentry,
    342								 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
    343					if (resp->status && resp->status != nfserr_rofs)
    344						goto out_unlock;
    345				}
    346			} else
    347				type = S_IFREG;
    348		}
    349	} else if (inode) {
    350		type = inode->i_mode & S_IFMT;
    351		mode = inode->i_mode & ~S_IFMT;
    352	} else {
    353		type = S_IFREG;
    354		mode = 0;	/* ??? */
    355	}
    356
    357	attr->ia_valid |= ATTR_MODE;
    358	attr->ia_mode = mode;
    359
    360	/* Special treatment for non-regular files according to the
    361	 * gospel of sun micro
    362	 */
    363	if (type != S_IFREG) {
    364		if (type != S_IFBLK && type != S_IFCHR) {
    365			rdev = 0;
    366		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
    367			/* If you think you've seen the worst, grok this. */
    368			type = S_IFIFO;
    369		} else {
    370			/* Okay, char or block special */
    371			if (!rdev)
    372				rdev = wanted;
    373		}
    374
    375		/* we've used the SIZE information, so discard it */
    376		attr->ia_valid &= ~ATTR_SIZE;
    377
    378		/* Make sure the type and device matches */
    379		resp->status = nfserr_exist;
    380		if (inode && inode_wrong_type(inode, type))
    381			goto out_unlock;
    382	}
    383
    384	resp->status = nfs_ok;
    385	if (!inode) {
    386		/* File doesn't exist. Create it and set attrs */
    387		resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
    388						  argp->len, attr, type, rdev,
    389						  newfhp);
    390	} else if (type == S_IFREG) {
    391		dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
    392			argp->name, attr->ia_valid, (long) attr->ia_size);
    393		/* File already exists. We ignore all attributes except
    394		 * size, so that creat() behaves exactly like
    395		 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
    396		 */
    397		attr->ia_valid &= ATTR_SIZE;
    398		if (attr->ia_valid)
    399			resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
    400						    (time64_t)0);
    401	}
    402
    403out_unlock:
    404	/* We don't really need to unlock, as fh_put does it. */
    405	fh_unlock(dirfhp);
    406	fh_drop_write(dirfhp);
    407done:
    408	fh_put(dirfhp);
    409	if (resp->status != nfs_ok)
    410		goto out;
    411	resp->status = fh_getattr(&resp->fh, &resp->stat);
    412out:
    413	return rpc_success;
    414}
    415
    416static __be32
    417nfsd_proc_remove(struct svc_rqst *rqstp)
    418{
    419	struct nfsd_diropargs *argp = rqstp->rq_argp;
    420	struct nfsd_stat *resp = rqstp->rq_resp;
    421
    422	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
    423		argp->len, argp->name);
    424
    425	/* Unlink. -SIFDIR means file must not be a directory */
    426	resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
    427				   argp->name, argp->len);
    428	fh_put(&argp->fh);
    429	return rpc_success;
    430}
    431
    432static __be32
    433nfsd_proc_rename(struct svc_rqst *rqstp)
    434{
    435	struct nfsd_renameargs *argp = rqstp->rq_argp;
    436	struct nfsd_stat *resp = rqstp->rq_resp;
    437
    438	dprintk("nfsd: RENAME   %s %.*s -> \n",
    439		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
    440	dprintk("nfsd:        ->  %s %.*s\n",
    441		SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
    442
    443	resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
    444				   &argp->tfh, argp->tname, argp->tlen);
    445	fh_put(&argp->ffh);
    446	fh_put(&argp->tfh);
    447	return rpc_success;
    448}
    449
    450static __be32
    451nfsd_proc_link(struct svc_rqst *rqstp)
    452{
    453	struct nfsd_linkargs *argp = rqstp->rq_argp;
    454	struct nfsd_stat *resp = rqstp->rq_resp;
    455
    456	dprintk("nfsd: LINK     %s ->\n",
    457		SVCFH_fmt(&argp->ffh));
    458	dprintk("nfsd:    %s %.*s\n",
    459		SVCFH_fmt(&argp->tfh),
    460		argp->tlen,
    461		argp->tname);
    462
    463	resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
    464				 &argp->ffh);
    465	fh_put(&argp->ffh);
    466	fh_put(&argp->tfh);
    467	return rpc_success;
    468}
    469
    470static __be32
    471nfsd_proc_symlink(struct svc_rqst *rqstp)
    472{
    473	struct nfsd_symlinkargs *argp = rqstp->rq_argp;
    474	struct nfsd_stat *resp = rqstp->rq_resp;
    475	struct svc_fh	newfh;
    476
    477	if (argp->tlen > NFS_MAXPATHLEN) {
    478		resp->status = nfserr_nametoolong;
    479		goto out;
    480	}
    481
    482	argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
    483						page_address(rqstp->rq_arg.pages[0]),
    484						argp->tlen);
    485	if (IS_ERR(argp->tname)) {
    486		resp->status = nfserrno(PTR_ERR(argp->tname));
    487		goto out;
    488	}
    489
    490	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
    491		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
    492		argp->tlen, argp->tname);
    493
    494	fh_init(&newfh, NFS_FHSIZE);
    495	resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
    496				    argp->tname, &newfh);
    497
    498	kfree(argp->tname);
    499	fh_put(&argp->ffh);
    500	fh_put(&newfh);
    501out:
    502	return rpc_success;
    503}
    504
    505/*
    506 * Make directory. This operation is not idempotent.
    507 * N.B. After this call resp->fh needs an fh_put
    508 */
    509static __be32
    510nfsd_proc_mkdir(struct svc_rqst *rqstp)
    511{
    512	struct nfsd_createargs *argp = rqstp->rq_argp;
    513	struct nfsd_diropres *resp = rqstp->rq_resp;
    514
    515	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
    516
    517	if (resp->fh.fh_dentry) {
    518		printk(KERN_WARNING
    519			"nfsd_proc_mkdir: response already verified??\n");
    520	}
    521
    522	argp->attrs.ia_valid &= ~ATTR_SIZE;
    523	fh_init(&resp->fh, NFS_FHSIZE);
    524	resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
    525				   &argp->attrs, S_IFDIR, 0, &resp->fh);
    526	fh_put(&argp->fh);
    527	if (resp->status != nfs_ok)
    528		goto out;
    529
    530	resp->status = fh_getattr(&resp->fh, &resp->stat);
    531out:
    532	return rpc_success;
    533}
    534
    535/*
    536 * Remove a directory
    537 */
    538static __be32
    539nfsd_proc_rmdir(struct svc_rqst *rqstp)
    540{
    541	struct nfsd_diropargs *argp = rqstp->rq_argp;
    542	struct nfsd_stat *resp = rqstp->rq_resp;
    543
    544	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
    545
    546	resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
    547				   argp->name, argp->len);
    548	fh_put(&argp->fh);
    549	return rpc_success;
    550}
    551
    552static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
    553				    struct nfsd_readdirres *resp,
    554				    u32 count)
    555{
    556	struct xdr_buf *buf = &resp->dirlist;
    557	struct xdr_stream *xdr = &resp->xdr;
    558
    559	count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
    560
    561	memset(buf, 0, sizeof(*buf));
    562
    563	/* Reserve room for the NULL ptr & eof flag (-2 words) */
    564	buf->buflen = count - XDR_UNIT * 2;
    565	buf->pages = rqstp->rq_next_page;
    566	rqstp->rq_next_page++;
    567
    568	/* This is xdr_init_encode(), but it assumes that
    569	 * the head kvec has already been consumed. */
    570	xdr_set_scratch_buffer(xdr, NULL, 0);
    571	xdr->buf = buf;
    572	xdr->page_ptr = buf->pages;
    573	xdr->iov = NULL;
    574	xdr->p = page_address(*buf->pages);
    575	xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
    576	xdr->rqst = NULL;
    577}
    578
    579/*
    580 * Read a portion of a directory.
    581 */
    582static __be32
    583nfsd_proc_readdir(struct svc_rqst *rqstp)
    584{
    585	struct nfsd_readdirargs *argp = rqstp->rq_argp;
    586	struct nfsd_readdirres *resp = rqstp->rq_resp;
    587	loff_t		offset;
    588
    589	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
    590		SVCFH_fmt(&argp->fh),		
    591		argp->count, argp->cookie);
    592
    593	nfsd_init_dirlist_pages(rqstp, resp, argp->count);
    594
    595	resp->common.err = nfs_ok;
    596	resp->cookie_offset = 0;
    597	offset = argp->cookie;
    598	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
    599				    &resp->common, nfssvc_encode_entry);
    600	nfssvc_encode_nfscookie(resp, offset);
    601
    602	fh_put(&argp->fh);
    603	return rpc_success;
    604}
    605
    606/*
    607 * Get file system info
    608 */
    609static __be32
    610nfsd_proc_statfs(struct svc_rqst *rqstp)
    611{
    612	struct nfsd_fhandle *argp = rqstp->rq_argp;
    613	struct nfsd_statfsres *resp = rqstp->rq_resp;
    614
    615	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
    616
    617	resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
    618				   NFSD_MAY_BYPASS_GSS_ON_ROOT);
    619	fh_put(&argp->fh);
    620	return rpc_success;
    621}
    622
    623/*
    624 * NFSv2 Server procedures.
    625 * Only the results of non-idempotent operations are cached.
    626 */
    627
    628#define ST 1		/* status */
    629#define FH 8		/* filehandle */
    630#define	AT 18		/* attributes */
    631
    632static const struct svc_procedure nfsd_procedures2[18] = {
    633	[NFSPROC_NULL] = {
    634		.pc_func = nfsd_proc_null,
    635		.pc_decode = nfssvc_decode_voidarg,
    636		.pc_encode = nfssvc_encode_voidres,
    637		.pc_argsize = sizeof(struct nfsd_voidargs),
    638		.pc_ressize = sizeof(struct nfsd_voidres),
    639		.pc_cachetype = RC_NOCACHE,
    640		.pc_xdrressize = 0,
    641		.pc_name = "NULL",
    642	},
    643	[NFSPROC_GETATTR] = {
    644		.pc_func = nfsd_proc_getattr,
    645		.pc_decode = nfssvc_decode_fhandleargs,
    646		.pc_encode = nfssvc_encode_attrstatres,
    647		.pc_release = nfssvc_release_attrstat,
    648		.pc_argsize = sizeof(struct nfsd_fhandle),
    649		.pc_ressize = sizeof(struct nfsd_attrstat),
    650		.pc_cachetype = RC_NOCACHE,
    651		.pc_xdrressize = ST+AT,
    652		.pc_name = "GETATTR",
    653	},
    654	[NFSPROC_SETATTR] = {
    655		.pc_func = nfsd_proc_setattr,
    656		.pc_decode = nfssvc_decode_sattrargs,
    657		.pc_encode = nfssvc_encode_attrstatres,
    658		.pc_release = nfssvc_release_attrstat,
    659		.pc_argsize = sizeof(struct nfsd_sattrargs),
    660		.pc_ressize = sizeof(struct nfsd_attrstat),
    661		.pc_cachetype = RC_REPLBUFF,
    662		.pc_xdrressize = ST+AT,
    663		.pc_name = "SETATTR",
    664	},
    665	[NFSPROC_ROOT] = {
    666		.pc_func = nfsd_proc_root,
    667		.pc_decode = nfssvc_decode_voidarg,
    668		.pc_encode = nfssvc_encode_voidres,
    669		.pc_argsize = sizeof(struct nfsd_voidargs),
    670		.pc_ressize = sizeof(struct nfsd_voidres),
    671		.pc_cachetype = RC_NOCACHE,
    672		.pc_xdrressize = 0,
    673		.pc_name = "ROOT",
    674	},
    675	[NFSPROC_LOOKUP] = {
    676		.pc_func = nfsd_proc_lookup,
    677		.pc_decode = nfssvc_decode_diropargs,
    678		.pc_encode = nfssvc_encode_diropres,
    679		.pc_release = nfssvc_release_diropres,
    680		.pc_argsize = sizeof(struct nfsd_diropargs),
    681		.pc_ressize = sizeof(struct nfsd_diropres),
    682		.pc_cachetype = RC_NOCACHE,
    683		.pc_xdrressize = ST+FH+AT,
    684		.pc_name = "LOOKUP",
    685	},
    686	[NFSPROC_READLINK] = {
    687		.pc_func = nfsd_proc_readlink,
    688		.pc_decode = nfssvc_decode_fhandleargs,
    689		.pc_encode = nfssvc_encode_readlinkres,
    690		.pc_argsize = sizeof(struct nfsd_fhandle),
    691		.pc_ressize = sizeof(struct nfsd_readlinkres),
    692		.pc_cachetype = RC_NOCACHE,
    693		.pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
    694		.pc_name = "READLINK",
    695	},
    696	[NFSPROC_READ] = {
    697		.pc_func = nfsd_proc_read,
    698		.pc_decode = nfssvc_decode_readargs,
    699		.pc_encode = nfssvc_encode_readres,
    700		.pc_release = nfssvc_release_readres,
    701		.pc_argsize = sizeof(struct nfsd_readargs),
    702		.pc_ressize = sizeof(struct nfsd_readres),
    703		.pc_cachetype = RC_NOCACHE,
    704		.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
    705		.pc_name = "READ",
    706	},
    707	[NFSPROC_WRITECACHE] = {
    708		.pc_func = nfsd_proc_writecache,
    709		.pc_decode = nfssvc_decode_voidarg,
    710		.pc_encode = nfssvc_encode_voidres,
    711		.pc_argsize = sizeof(struct nfsd_voidargs),
    712		.pc_ressize = sizeof(struct nfsd_voidres),
    713		.pc_cachetype = RC_NOCACHE,
    714		.pc_xdrressize = 0,
    715		.pc_name = "WRITECACHE",
    716	},
    717	[NFSPROC_WRITE] = {
    718		.pc_func = nfsd_proc_write,
    719		.pc_decode = nfssvc_decode_writeargs,
    720		.pc_encode = nfssvc_encode_attrstatres,
    721		.pc_release = nfssvc_release_attrstat,
    722		.pc_argsize = sizeof(struct nfsd_writeargs),
    723		.pc_ressize = sizeof(struct nfsd_attrstat),
    724		.pc_cachetype = RC_REPLBUFF,
    725		.pc_xdrressize = ST+AT,
    726		.pc_name = "WRITE",
    727	},
    728	[NFSPROC_CREATE] = {
    729		.pc_func = nfsd_proc_create,
    730		.pc_decode = nfssvc_decode_createargs,
    731		.pc_encode = nfssvc_encode_diropres,
    732		.pc_release = nfssvc_release_diropres,
    733		.pc_argsize = sizeof(struct nfsd_createargs),
    734		.pc_ressize = sizeof(struct nfsd_diropres),
    735		.pc_cachetype = RC_REPLBUFF,
    736		.pc_xdrressize = ST+FH+AT,
    737		.pc_name = "CREATE",
    738	},
    739	[NFSPROC_REMOVE] = {
    740		.pc_func = nfsd_proc_remove,
    741		.pc_decode = nfssvc_decode_diropargs,
    742		.pc_encode = nfssvc_encode_statres,
    743		.pc_argsize = sizeof(struct nfsd_diropargs),
    744		.pc_ressize = sizeof(struct nfsd_stat),
    745		.pc_cachetype = RC_REPLSTAT,
    746		.pc_xdrressize = ST,
    747		.pc_name = "REMOVE",
    748	},
    749	[NFSPROC_RENAME] = {
    750		.pc_func = nfsd_proc_rename,
    751		.pc_decode = nfssvc_decode_renameargs,
    752		.pc_encode = nfssvc_encode_statres,
    753		.pc_argsize = sizeof(struct nfsd_renameargs),
    754		.pc_ressize = sizeof(struct nfsd_stat),
    755		.pc_cachetype = RC_REPLSTAT,
    756		.pc_xdrressize = ST,
    757		.pc_name = "RENAME",
    758	},
    759	[NFSPROC_LINK] = {
    760		.pc_func = nfsd_proc_link,
    761		.pc_decode = nfssvc_decode_linkargs,
    762		.pc_encode = nfssvc_encode_statres,
    763		.pc_argsize = sizeof(struct nfsd_linkargs),
    764		.pc_ressize = sizeof(struct nfsd_stat),
    765		.pc_cachetype = RC_REPLSTAT,
    766		.pc_xdrressize = ST,
    767		.pc_name = "LINK",
    768	},
    769	[NFSPROC_SYMLINK] = {
    770		.pc_func = nfsd_proc_symlink,
    771		.pc_decode = nfssvc_decode_symlinkargs,
    772		.pc_encode = nfssvc_encode_statres,
    773		.pc_argsize = sizeof(struct nfsd_symlinkargs),
    774		.pc_ressize = sizeof(struct nfsd_stat),
    775		.pc_cachetype = RC_REPLSTAT,
    776		.pc_xdrressize = ST,
    777		.pc_name = "SYMLINK",
    778	},
    779	[NFSPROC_MKDIR] = {
    780		.pc_func = nfsd_proc_mkdir,
    781		.pc_decode = nfssvc_decode_createargs,
    782		.pc_encode = nfssvc_encode_diropres,
    783		.pc_release = nfssvc_release_diropres,
    784		.pc_argsize = sizeof(struct nfsd_createargs),
    785		.pc_ressize = sizeof(struct nfsd_diropres),
    786		.pc_cachetype = RC_REPLBUFF,
    787		.pc_xdrressize = ST+FH+AT,
    788		.pc_name = "MKDIR",
    789	},
    790	[NFSPROC_RMDIR] = {
    791		.pc_func = nfsd_proc_rmdir,
    792		.pc_decode = nfssvc_decode_diropargs,
    793		.pc_encode = nfssvc_encode_statres,
    794		.pc_argsize = sizeof(struct nfsd_diropargs),
    795		.pc_ressize = sizeof(struct nfsd_stat),
    796		.pc_cachetype = RC_REPLSTAT,
    797		.pc_xdrressize = ST,
    798		.pc_name = "RMDIR",
    799	},
    800	[NFSPROC_READDIR] = {
    801		.pc_func = nfsd_proc_readdir,
    802		.pc_decode = nfssvc_decode_readdirargs,
    803		.pc_encode = nfssvc_encode_readdirres,
    804		.pc_argsize = sizeof(struct nfsd_readdirargs),
    805		.pc_ressize = sizeof(struct nfsd_readdirres),
    806		.pc_cachetype = RC_NOCACHE,
    807		.pc_name = "READDIR",
    808	},
    809	[NFSPROC_STATFS] = {
    810		.pc_func = nfsd_proc_statfs,
    811		.pc_decode = nfssvc_decode_fhandleargs,
    812		.pc_encode = nfssvc_encode_statfsres,
    813		.pc_argsize = sizeof(struct nfsd_fhandle),
    814		.pc_ressize = sizeof(struct nfsd_statfsres),
    815		.pc_cachetype = RC_NOCACHE,
    816		.pc_xdrressize = ST+5,
    817		.pc_name = "STATFS",
    818	},
    819};
    820
    821
    822static unsigned int nfsd_count2[ARRAY_SIZE(nfsd_procedures2)];
    823const struct svc_version nfsd_version2 = {
    824	.vs_vers	= 2,
    825	.vs_nproc	= 18,
    826	.vs_proc	= nfsd_procedures2,
    827	.vs_count	= nfsd_count2,
    828	.vs_dispatch	= nfsd_dispatch,
    829	.vs_xdrsize	= NFS2_SVC_XDRSIZE,
    830};
    831
    832/*
    833 * Map errnos to NFS errnos.
    834 */
    835__be32
    836nfserrno (int errno)
    837{
    838	static struct {
    839		__be32	nfserr;
    840		int	syserr;
    841	} nfs_errtbl[] = {
    842		{ nfs_ok, 0 },
    843		{ nfserr_perm, -EPERM },
    844		{ nfserr_noent, -ENOENT },
    845		{ nfserr_io, -EIO },
    846		{ nfserr_nxio, -ENXIO },
    847		{ nfserr_fbig, -E2BIG },
    848		{ nfserr_stale, -EBADF },
    849		{ nfserr_acces, -EACCES },
    850		{ nfserr_exist, -EEXIST },
    851		{ nfserr_xdev, -EXDEV },
    852		{ nfserr_mlink, -EMLINK },
    853		{ nfserr_nodev, -ENODEV },
    854		{ nfserr_notdir, -ENOTDIR },
    855		{ nfserr_isdir, -EISDIR },
    856		{ nfserr_inval, -EINVAL },
    857		{ nfserr_fbig, -EFBIG },
    858		{ nfserr_nospc, -ENOSPC },
    859		{ nfserr_rofs, -EROFS },
    860		{ nfserr_mlink, -EMLINK },
    861		{ nfserr_nametoolong, -ENAMETOOLONG },
    862		{ nfserr_notempty, -ENOTEMPTY },
    863#ifdef EDQUOT
    864		{ nfserr_dquot, -EDQUOT },
    865#endif
    866		{ nfserr_stale, -ESTALE },
    867		{ nfserr_jukebox, -ETIMEDOUT },
    868		{ nfserr_jukebox, -ERESTARTSYS },
    869		{ nfserr_jukebox, -EAGAIN },
    870		{ nfserr_jukebox, -EWOULDBLOCK },
    871		{ nfserr_jukebox, -ENOMEM },
    872		{ nfserr_io, -ETXTBSY },
    873		{ nfserr_notsupp, -EOPNOTSUPP },
    874		{ nfserr_toosmall, -ETOOSMALL },
    875		{ nfserr_serverfault, -ESERVERFAULT },
    876		{ nfserr_serverfault, -ENFILE },
    877		{ nfserr_io, -EREMOTEIO },
    878		{ nfserr_stale, -EOPENSTALE },
    879		{ nfserr_io, -EUCLEAN },
    880		{ nfserr_perm, -ENOKEY },
    881		{ nfserr_no_grace, -ENOGRACE},
    882	};
    883	int	i;
    884
    885	for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
    886		if (nfs_errtbl[i].syserr == errno)
    887			return nfs_errtbl[i].nfserr;
    888	}
    889	WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
    890	return nfserr_io;
    891}
    892