nfsproc.c 21.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 * Process version 2 NFS requests.
 *
 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
 */

#include <linux/namei.h>

9 10
#include "cache.h"
#include "xdr.h"
11
#include "vfs.h"
L
Linus Torvalds 已提交
12 13 14 15 16 17 18

typedef struct svc_rqst	svc_rqst;
typedef struct svc_buf	svc_buf;

#define NFSDDBG_FACILITY		NFSDDBG_PROC


A
Al Viro 已提交
19
static __be32
20
nfsd_proc_null(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
21 22 23 24
{
	return nfs_ok;
}

25 26
static __be32
nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
27 28
{
	if (err) return err;
A
Al Viro 已提交
29
	return fh_getattr(&resp->fh, &resp->stat);
30
}
31 32
static __be32
nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
33 34
{
	if (err) return err;
A
Al Viro 已提交
35
	return fh_getattr(&resp->fh, &resp->stat);
36
}
L
Linus Torvalds 已提交
37 38 39 40
/*
 * Get a file's attributes
 * N.B. After this call resp->fh needs an fh_put
 */
A
Al Viro 已提交
41
static __be32
42
nfsd_proc_getattr(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
43
{
44 45
	struct nfsd_fhandle *argp = rqstp->rq_argp;
	struct nfsd_attrstat *resp = rqstp->rq_resp;
46
	__be32 nfserr;
L
Linus Torvalds 已提交
47 48 49
	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));

	fh_copy(&resp->fh, &argp->fh);
50 51
	nfserr = fh_verify(rqstp, &resp->fh, 0,
			NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
52
	return nfsd_return_attrs(nfserr, resp);
L
Linus Torvalds 已提交
53 54 55 56 57 58
}

/*
 * Set a file's attributes
 * N.B. After this call resp->fh needs an fh_put
 */
A
Al Viro 已提交
59
static __be32
60
nfsd_proc_setattr(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
61
{
62 63
	struct nfsd_sattrargs *argp = rqstp->rq_argp;
	struct nfsd_attrstat *resp = rqstp->rq_resp;
64 65
	struct iattr *iap = &argp->attrs;
	struct svc_fh *fhp;
66
	__be32 nfserr;
67

L
Linus Torvalds 已提交
68 69 70 71
	dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
		SVCFH_fmt(&argp->fh),
		argp->attrs.ia_valid, (long) argp->attrs.ia_size);

72 73 74 75 76 77 78
	fhp = fh_copy(&resp->fh, &argp->fh);

	/*
	 * NFSv2 does not differentiate between "set-[ac]time-to-now"
	 * which only requires access, and "set-[ac]time-to-X" which
	 * requires ownership.
	 * So if it looks like it might be "set both to the same time which
79
	 * is close to now", and if setattr_prepare fails, then we
80 81
	 * convert to "set to now" instead of "set to explicit time"
	 *
82
	 * We only call setattr_prepare as the last test as technically
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
	 * it is not an interface that we should be using.
	 */
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
#define	MAX_TOUCH_TIME_ERROR (30*60)
	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
	    iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
		/*
		 * Looks probable.
		 *
		 * Now just make sure time is in the right ballpark.
		 * Solaris, at least, doesn't seem to care what the time
		 * request is.  We require it be within 30 minutes of now.
		 */
		time_t delta = iap->ia_atime.tv_sec - get_seconds();

		nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
		if (nfserr)
			goto done;

		if (delta < 0)
			delta = -delta;
		if (delta < MAX_TOUCH_TIME_ERROR &&
105
		    setattr_prepare(fhp->fh_dentry, iap) != 0) {
106 107 108 109 110 111 112 113 114 115 116
			/*
			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
			 * This will cause notify_change to set these times
			 * to "now"
			 */
			iap->ia_valid &= ~BOTH_TIME_SET;
		}
	}

	nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time_t)0);
done:
117
	return nfsd_return_attrs(nfserr, resp);
L
Linus Torvalds 已提交
118 119 120 121 122 123 124 125
}

/*
 * Look up a path name component
 * Note: the dentry in the resp->fh may be negative if the file
 * doesn't exist yet.
 * N.B. After this call resp->fh needs an fh_put
 */
A
Al Viro 已提交
126
static __be32
127
nfsd_proc_lookup(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
128
{
129 130
	struct nfsd_diropargs *argp = rqstp->rq_argp;
	struct nfsd_diropres *resp = rqstp->rq_resp;
131
	__be32	nfserr;
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140

	dprintk("nfsd: LOOKUP   %s %.*s\n",
		SVCFH_fmt(&argp->fh), argp->len, argp->name);

	fh_init(&resp->fh, NFS_FHSIZE);
	nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
				 &resp->fh);

	fh_put(&argp->fh);
141
	return nfsd_return_dirop(nfserr, resp);
L
Linus Torvalds 已提交
142 143 144 145 146
}

/*
 * Read a symlink.
 */
A
Al Viro 已提交
147
static __be32
148
nfsd_proc_readlink(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
149
{
150 151
	struct nfsd_readlinkargs *argp = rqstp->rq_argp;
	struct nfsd_readlinkres *resp = rqstp->rq_resp;
152
	__be32	nfserr;
L
Linus Torvalds 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));

	/* Read the symlink. */
	resp->len = NFS_MAXPATHLEN;
	nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);

	fh_put(&argp->fh);
	return nfserr;
}

/*
 * Read a portion of a file.
 * N.B. After this call resp->fh needs an fh_put
 */
A
Al Viro 已提交
168
static __be32
169
nfsd_proc_read(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
170
{
171 172
	struct nfsd_readargs *argp = rqstp->rq_argp;
	struct nfsd_readres *resp = rqstp->rq_resp;
173
	__be32	nfserr;
L
Linus Torvalds 已提交
174 175 176 177 178 179 180 181 182

	dprintk("nfsd: READ    %s %d bytes at %d\n",
		SVCFH_fmt(&argp->fh),
		argp->count, argp->offset);

	/* Obtain buffer pointer for payload. 19 is 1 word for
	 * status, 17 words for fattr, and 1 word for the byte count.
	 */

183
	if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
184
		char buf[RPC_MAX_ADDRBUFLEN];
L
Linus Torvalds 已提交
185
		printk(KERN_NOTICE
186 187
			"oversized read request from %s (%d bytes)\n",
				svc_print_addr(rqstp, buf, sizeof(buf)),
L
Linus Torvalds 已提交
188
				argp->count);
189
		argp->count = NFSSVC_MAXBLKSIZE_V2;
L
Linus Torvalds 已提交
190
	}
191
	svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
L
Linus Torvalds 已提交
192 193

	resp->count = argp->count;
194
	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
L
Linus Torvalds 已提交
195
				  argp->offset,
196
			   	  rqstp->rq_vec, argp->vlen,
L
Linus Torvalds 已提交
197 198
				  &resp->count);

199
	if (nfserr) return nfserr;
A
Al Viro 已提交
200
	return fh_getattr(&resp->fh, &resp->stat);
L
Linus Torvalds 已提交
201 202 203 204 205 206
}

/*
 * Write data to a file
 * N.B. After this call resp->fh needs an fh_put
 */
A
Al Viro 已提交
207
static __be32
208
nfsd_proc_write(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
209
{
210 211
	struct nfsd_writeargs *argp = rqstp->rq_argp;
	struct nfsd_attrstat *resp = rqstp->rq_resp;
212
	__be32	nfserr;
213
	unsigned long cnt = argp->len;
L
Linus Torvalds 已提交
214 215 216 217 218

	dprintk("nfsd: WRITE    %s %d bytes at %d\n",
		SVCFH_fmt(&argp->fh),
		argp->len, argp->offset);

219 220
	nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), argp->offset,
				rqstp->rq_vec, argp->vlen, &cnt, NFS_DATA_SYNC);
221
	return nfsd_return_attrs(nfserr, resp);
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229
}

/*
 * CREATE processing is complicated. The keyword here is `overloaded.'
 * The parent directory is kept locked between the check for existence
 * and the actual create() call in compliance with VFS protocols.
 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
 */
A
Al Viro 已提交
230
static __be32
231
nfsd_proc_create(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
232
{
233 234
	struct nfsd_createargs *argp = rqstp->rq_argp;
	struct nfsd_diropres *resp = rqstp->rq_resp;
L
Linus Torvalds 已提交
235 236 237 238 239
	svc_fh		*dirfhp = &argp->fh;
	svc_fh		*newfhp = &resp->fh;
	struct iattr	*attr = &argp->attrs;
	struct inode	*inode;
	struct dentry	*dchild;
240 241
	int		type, mode;
	__be32		nfserr;
242
	int		hosterr;
L
Linus Torvalds 已提交
243 244 245 246 247 248
	dev_t		rdev = 0, wanted = new_decode_dev(attr->ia_size);

	dprintk("nfsd: CREATE   %s %.*s\n",
		SVCFH_fmt(dirfhp), argp->len, argp->name);

	/* First verify the parent file handle */
M
Miklos Szeredi 已提交
249
	nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
L
Linus Torvalds 已提交
250 251 252
	if (nfserr)
		goto done; /* must fh_put dirfhp even on error */

M
Miklos Szeredi 已提交
253
	/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
L
Linus Torvalds 已提交
254 255 256 257

	nfserr = nfserr_exist;
	if (isdotent(argp->name, argp->len))
		goto done;
258 259 260 261 262 263
	hosterr = fh_want_write(dirfhp);
	if (hosterr) {
		nfserr = nfserrno(hosterr);
		goto done;
	}

264
	fh_lock_nested(dirfhp, I_MUTEX_PARENT);
L
Linus Torvalds 已提交
265 266 267 268 269 270 271
	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
	if (IS_ERR(dchild)) {
		nfserr = nfserrno(PTR_ERR(dchild));
		goto out_unlock;
	}
	fh_init(newfhp, NFS_FHSIZE);
	nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
272
	if (!nfserr && d_really_is_negative(dchild))
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
		nfserr = nfserr_noent;
	dput(dchild);
	if (nfserr) {
		if (nfserr != nfserr_noent)
			goto out_unlock;
		/*
		 * If the new file handle wasn't verified, we can't tell
		 * whether the file exists or not. Time to bail ...
		 */
		nfserr = nfserr_acces;
		if (!newfhp->fh_dentry) {
			printk(KERN_WARNING 
				"nfsd_proc_create: file handle not verified\n");
			goto out_unlock;
		}
	}

290
	inode = d_inode(newfhp->fh_dentry);
L
Linus Torvalds 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

	/* Unfudge the mode bits */
	if (attr->ia_valid & ATTR_MODE) {
		type = attr->ia_mode & S_IFMT;
		mode = attr->ia_mode & ~S_IFMT;
		if (!type) {
			/* no type, so if target exists, assume same as that,
			 * else assume a file */
			if (inode) {
				type = inode->i_mode & S_IFMT;
				switch(type) {
				case S_IFCHR:
				case S_IFBLK:
					/* reserve rdev for later checking */
					rdev = inode->i_rdev;
					attr->ia_valid |= ATTR_SIZE;

					/* FALLTHROUGH */
				case S_IFIFO:
					/* this is probably a permission check..
					 * at least IRIX implements perm checking on
					 *   echo thing > device-special-file-or-pipe
					 * by doing a CREATE with type==0
					 */
315 316
					nfserr = nfsd_permission(rqstp,
								 newfhp->fh_export,
L
Linus Torvalds 已提交
317
								 newfhp->fh_dentry,
M
Miklos Szeredi 已提交
318
								 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
L
Linus Torvalds 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
					if (nfserr && nfserr != nfserr_rofs)
						goto out_unlock;
				}
			} else
				type = S_IFREG;
		}
	} else if (inode) {
		type = inode->i_mode & S_IFMT;
		mode = inode->i_mode & ~S_IFMT;
	} else {
		type = S_IFREG;
		mode = 0;	/* ??? */
	}

	attr->ia_valid |= ATTR_MODE;
	attr->ia_mode = mode;

	/* Special treatment for non-regular files according to the
	 * gospel of sun micro
	 */
	if (type != S_IFREG) {
		if (type != S_IFBLK && type != S_IFCHR) {
			rdev = 0;
		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
			/* If you think you've seen the worst, grok this. */
			type = S_IFIFO;
		} else {
			/* Okay, char or block special */
			if (!rdev)
				rdev = wanted;
		}

		/* we've used the SIZE information, so discard it */
		attr->ia_valid &= ~ATTR_SIZE;

		/* Make sure the type and device matches */
		nfserr = nfserr_exist;
		if (inode && type != (inode->i_mode & S_IFMT))
			goto out_unlock;
	}

	nfserr = 0;
	if (!inode) {
		/* File doesn't exist. Create it and set attrs */
J
J. Bruce Fields 已提交
363 364
		nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name,
					argp->len, attr, type, rdev, newfhp);
L
Linus Torvalds 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	} else if (type == S_IFREG) {
		dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
			argp->name, attr->ia_valid, (long) attr->ia_size);
		/* File already exists. We ignore all attributes except
		 * size, so that creat() behaves exactly like
		 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
		 */
		attr->ia_valid &= ATTR_SIZE;
		if (attr->ia_valid)
			nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0);
	}

out_unlock:
	/* We don't really need to unlock, as fh_put does it. */
	fh_unlock(dirfhp);
380
	fh_drop_write(dirfhp);
L
Linus Torvalds 已提交
381 382
done:
	fh_put(dirfhp);
383
	return nfsd_return_dirop(nfserr, resp);
L
Linus Torvalds 已提交
384 385
}

A
Al Viro 已提交
386
static __be32
387
nfsd_proc_remove(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
388
{
389
	struct nfsd_diropargs *argp = rqstp->rq_argp;
390
	__be32	nfserr;
L
Linus Torvalds 已提交
391 392 393 394 395 396 397 398 399 400

	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
		argp->len, argp->name);

	/* Unlink. -SIFDIR means file must not be a directory */
	nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
	fh_put(&argp->fh);
	return nfserr;
}

A
Al Viro 已提交
401
static __be32
402
nfsd_proc_rename(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
403
{
404
	struct nfsd_renameargs *argp = rqstp->rq_argp;
405
	__be32	nfserr;
L
Linus Torvalds 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418

	dprintk("nfsd: RENAME   %s %.*s -> \n",
		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
	dprintk("nfsd:        ->  %s %.*s\n",
		SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);

	nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
				    &argp->tfh, argp->tname, argp->tlen);
	fh_put(&argp->ffh);
	fh_put(&argp->tfh);
	return nfserr;
}

A
Al Viro 已提交
419
static __be32
420
nfsd_proc_link(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
421
{
422
	struct nfsd_linkargs *argp = rqstp->rq_argp;
423
	__be32	nfserr;
L
Linus Torvalds 已提交
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438

	dprintk("nfsd: LINK     %s ->\n",
		SVCFH_fmt(&argp->ffh));
	dprintk("nfsd:    %s %.*s\n",
		SVCFH_fmt(&argp->tfh),
		argp->tlen,
		argp->tname);

	nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
				  &argp->ffh);
	fh_put(&argp->ffh);
	fh_put(&argp->tfh);
	return nfserr;
}

A
Al Viro 已提交
439
static __be32
440
nfsd_proc_symlink(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
441
{
442
	struct nfsd_symlinkargs *argp = rqstp->rq_argp;
L
Linus Torvalds 已提交
443
	struct svc_fh	newfh;
444
	__be32		nfserr;
L
Linus Torvalds 已提交
445 446 447 448 449 450 451

	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
		argp->tlen, argp->tname);

	fh_init(&newfh, NFS_FHSIZE);
	/*
452 453 454
	 * Crazy hack: the request fits in a page, and already-decoded
	 * attributes follow argp->tname, so it's safe to just write a
	 * null to ensure it's null-terminated:
L
Linus Torvalds 已提交
455
	 */
456
	argp->tname[argp->tlen] = '\0';
L
Linus Torvalds 已提交
457
	nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
458
						 argp->tname, &newfh);
L
Linus Torvalds 已提交
459 460 461 462 463 464 465 466 467 468

	fh_put(&argp->ffh);
	fh_put(&newfh);
	return nfserr;
}

/*
 * Make directory. This operation is not idempotent.
 * N.B. After this call resp->fh needs an fh_put
 */
A
Al Viro 已提交
469
static __be32
470
nfsd_proc_mkdir(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
471
{
472 473
	struct nfsd_createargs *argp = rqstp->rq_argp;
	struct nfsd_diropres *resp = rqstp->rq_resp;
474
	__be32	nfserr;
L
Linus Torvalds 已提交
475 476 477 478 479 480 481 482 483 484 485 486 487

	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);

	if (resp->fh.fh_dentry) {
		printk(KERN_WARNING
			"nfsd_proc_mkdir: response already verified??\n");
	}

	argp->attrs.ia_valid &= ~ATTR_SIZE;
	fh_init(&resp->fh, NFS_FHSIZE);
	nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
				    &argp->attrs, S_IFDIR, 0, &resp->fh);
	fh_put(&argp->fh);
488
	return nfsd_return_dirop(nfserr, resp);
L
Linus Torvalds 已提交
489 490 491 492 493
}

/*
 * Remove a directory
 */
A
Al Viro 已提交
494
static __be32
495
nfsd_proc_rmdir(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
496
{
497
	struct nfsd_diropargs *argp = rqstp->rq_argp;
498
	__be32	nfserr;
L
Linus Torvalds 已提交
499 500 501 502 503 504 505 506 507 508 509

	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);

	nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
	fh_put(&argp->fh);
	return nfserr;
}

/*
 * Read a portion of a directory.
 */
A
Al Viro 已提交
510
static __be32
511
nfsd_proc_readdir(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
512
{
513 514
	struct nfsd_readdirargs *argp = rqstp->rq_argp;
	struct nfsd_readdirres *resp = rqstp->rq_resp;
515 516
	int		count;
	__be32		nfserr;
L
Linus Torvalds 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
	loff_t		offset;

	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
		SVCFH_fmt(&argp->fh),		
		argp->count, argp->cookie);

	/* Shrink to the client read size */
	count = (argp->count >> 2) - 2;

	/* Make sure we've room for the NULL ptr & eof flag */
	count -= 2;
	if (count < 0)
		count = 0;

	resp->buffer = argp->buffer;
	resp->offset = NULL;
	resp->buflen = count;
	resp->common.err = nfs_ok;
	/* Read directory and encode entries on the fly */
	offset = argp->cookie;
	nfserr = nfsd_readdir(rqstp, &argp->fh, &offset, 
			      &resp->common, nfssvc_encode_entry);

	resp->count = resp->buffer - argp->buffer;
	if (resp->offset)
		*resp->offset = htonl(offset);

	fh_put(&argp->fh);
	return nfserr;
}

/*
 * Get file system info
 */
A
Al Viro 已提交
551
static __be32
552
nfsd_proc_statfs(struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
553
{
554 555
	struct nfsd_fhandle *argp = rqstp->rq_argp;
	struct nfsd_statfsres *resp = rqstp->rq_resp;
556
	__be32	nfserr;
L
Linus Torvalds 已提交
557 558 559

	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));

560 561
	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
			NFSD_MAY_BYPASS_GSS_ON_ROOT);
L
Linus Torvalds 已提交
562 563 564 565 566 567 568 569 570 571 572 573 574 575
	fh_put(&argp->fh);
	return nfserr;
}

/*
 * NFSv2 Server procedures.
 * Only the results of non-idempotent operations are cached.
 */
struct nfsd_void { int dummy; };

#define ST 1		/* status */
#define FH 8		/* filehandle */
#define	AT 18		/* attributes */

576
static const struct svc_procedure nfsd_procedures2[18] = {
577
	[NFSPROC_NULL] = {
578
		.pc_func = nfsd_proc_null,
579
		.pc_decode = nfssvc_decode_void,
580
		.pc_encode = nfssvc_encode_void,
581 582 583 584 585 586
		.pc_argsize = sizeof(struct nfsd_void),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST,
	},
	[NFSPROC_GETATTR] = {
587
		.pc_func = nfsd_proc_getattr,
588
		.pc_decode = nfssvc_decode_fhandle,
589
		.pc_encode = nfssvc_encode_attrstat,
590
		.pc_release = nfssvc_release_fhandle,
591 592 593 594 595 596
		.pc_argsize = sizeof(struct nfsd_fhandle),
		.pc_ressize = sizeof(struct nfsd_attrstat),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST+AT,
	},
	[NFSPROC_SETATTR] = {
597
		.pc_func = nfsd_proc_setattr,
598
		.pc_decode = nfssvc_decode_sattrargs,
599
		.pc_encode = nfssvc_encode_attrstat,
600
		.pc_release = nfssvc_release_fhandle,
601 602 603 604 605 606
		.pc_argsize = sizeof(struct nfsd_sattrargs),
		.pc_ressize = sizeof(struct nfsd_attrstat),
		.pc_cachetype = RC_REPLBUFF,
		.pc_xdrressize = ST+AT,
	},
	[NFSPROC_ROOT] = {
607
		.pc_decode = nfssvc_decode_void,
608
		.pc_encode = nfssvc_encode_void,
609 610 611 612 613 614
		.pc_argsize = sizeof(struct nfsd_void),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST,
	},
	[NFSPROC_LOOKUP] = {
615
		.pc_func = nfsd_proc_lookup,
616
		.pc_decode = nfssvc_decode_diropargs,
617
		.pc_encode = nfssvc_encode_diropres,
618
		.pc_release = nfssvc_release_fhandle,
619 620 621 622 623 624
		.pc_argsize = sizeof(struct nfsd_diropargs),
		.pc_ressize = sizeof(struct nfsd_diropres),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST+FH+AT,
	},
	[NFSPROC_READLINK] = {
625
		.pc_func = nfsd_proc_readlink,
626
		.pc_decode = nfssvc_decode_readlinkargs,
627
		.pc_encode = nfssvc_encode_readlinkres,
628 629 630 631 632 633
		.pc_argsize = sizeof(struct nfsd_readlinkargs),
		.pc_ressize = sizeof(struct nfsd_readlinkres),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
	},
	[NFSPROC_READ] = {
634
		.pc_func = nfsd_proc_read,
635
		.pc_decode = nfssvc_decode_readargs,
636
		.pc_encode = nfssvc_encode_readres,
637
		.pc_release = nfssvc_release_fhandle,
638 639 640 641 642 643
		.pc_argsize = sizeof(struct nfsd_readargs),
		.pc_ressize = sizeof(struct nfsd_readres),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
	},
	[NFSPROC_WRITECACHE] = {
644
		.pc_decode = nfssvc_decode_void,
645
		.pc_encode = nfssvc_encode_void,
646 647 648 649 650 651
		.pc_argsize = sizeof(struct nfsd_void),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST,
	},
	[NFSPROC_WRITE] = {
652
		.pc_func = nfsd_proc_write,
653
		.pc_decode = nfssvc_decode_writeargs,
654
		.pc_encode = nfssvc_encode_attrstat,
655
		.pc_release = nfssvc_release_fhandle,
656 657 658 659 660 661
		.pc_argsize = sizeof(struct nfsd_writeargs),
		.pc_ressize = sizeof(struct nfsd_attrstat),
		.pc_cachetype = RC_REPLBUFF,
		.pc_xdrressize = ST+AT,
	},
	[NFSPROC_CREATE] = {
662
		.pc_func = nfsd_proc_create,
663
		.pc_decode = nfssvc_decode_createargs,
664
		.pc_encode = nfssvc_encode_diropres,
665
		.pc_release = nfssvc_release_fhandle,
666 667 668 669 670 671
		.pc_argsize = sizeof(struct nfsd_createargs),
		.pc_ressize = sizeof(struct nfsd_diropres),
		.pc_cachetype = RC_REPLBUFF,
		.pc_xdrressize = ST+FH+AT,
	},
	[NFSPROC_REMOVE] = {
672
		.pc_func = nfsd_proc_remove,
673
		.pc_decode = nfssvc_decode_diropargs,
674
		.pc_encode = nfssvc_encode_void,
675 676 677 678 679 680
		.pc_argsize = sizeof(struct nfsd_diropargs),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_REPLSTAT,
		.pc_xdrressize = ST,
	},
	[NFSPROC_RENAME] = {
681
		.pc_func = nfsd_proc_rename,
682
		.pc_decode = nfssvc_decode_renameargs,
683
		.pc_encode = nfssvc_encode_void,
684 685 686 687 688 689
		.pc_argsize = sizeof(struct nfsd_renameargs),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_REPLSTAT,
		.pc_xdrressize = ST,
	},
	[NFSPROC_LINK] = {
690
		.pc_func = nfsd_proc_link,
691
		.pc_decode = nfssvc_decode_linkargs,
692
		.pc_encode = nfssvc_encode_void,
693 694 695 696 697 698
		.pc_argsize = sizeof(struct nfsd_linkargs),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_REPLSTAT,
		.pc_xdrressize = ST,
	},
	[NFSPROC_SYMLINK] = {
699
		.pc_func = nfsd_proc_symlink,
700
		.pc_decode = nfssvc_decode_symlinkargs,
701
		.pc_encode = nfssvc_encode_void,
702 703 704 705 706 707
		.pc_argsize = sizeof(struct nfsd_symlinkargs),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_REPLSTAT,
		.pc_xdrressize = ST,
	},
	[NFSPROC_MKDIR] = {
708
		.pc_func = nfsd_proc_mkdir,
709
		.pc_decode = nfssvc_decode_createargs,
710
		.pc_encode = nfssvc_encode_diropres,
711
		.pc_release = nfssvc_release_fhandle,
712 713 714 715 716 717
		.pc_argsize = sizeof(struct nfsd_createargs),
		.pc_ressize = sizeof(struct nfsd_diropres),
		.pc_cachetype = RC_REPLBUFF,
		.pc_xdrressize = ST+FH+AT,
	},
	[NFSPROC_RMDIR] = {
718
		.pc_func = nfsd_proc_rmdir,
719
		.pc_decode = nfssvc_decode_diropargs,
720
		.pc_encode = nfssvc_encode_void,
721 722 723 724 725 726
		.pc_argsize = sizeof(struct nfsd_diropargs),
		.pc_ressize = sizeof(struct nfsd_void),
		.pc_cachetype = RC_REPLSTAT,
		.pc_xdrressize = ST,
	},
	[NFSPROC_READDIR] = {
727
		.pc_func = nfsd_proc_readdir,
728
		.pc_decode = nfssvc_decode_readdirargs,
729
		.pc_encode = nfssvc_encode_readdirres,
730 731 732 733 734
		.pc_argsize = sizeof(struct nfsd_readdirargs),
		.pc_ressize = sizeof(struct nfsd_readdirres),
		.pc_cachetype = RC_NOCACHE,
	},
	[NFSPROC_STATFS] = {
735
		.pc_func = nfsd_proc_statfs,
736
		.pc_decode = nfssvc_decode_fhandle,
737
		.pc_encode = nfssvc_encode_statfsres,
738 739 740 741 742
		.pc_argsize = sizeof(struct nfsd_fhandle),
		.pc_ressize = sizeof(struct nfsd_statfsres),
		.pc_cachetype = RC_NOCACHE,
		.pc_xdrressize = ST+5,
	},
L
Linus Torvalds 已提交
743 744 745
};


746
static unsigned int nfsd_count2[ARRAY_SIZE(nfsd_procedures2)];
L
Linus Torvalds 已提交
747 748 749 750
struct svc_version	nfsd_version2 = {
		.vs_vers	= 2,
		.vs_nproc	= 18,
		.vs_proc	= nfsd_procedures2,
751
		.vs_count	= nfsd_count2,
L
Linus Torvalds 已提交
752 753 754 755 756 757 758
		.vs_dispatch	= nfsd_dispatch,
		.vs_xdrsize	= NFS2_SVC_XDRSIZE,
};

/*
 * Map errnos to NFS errnos.
 */
759
__be32
L
Linus Torvalds 已提交
760 761 762
nfserrno (int errno)
{
	static struct {
763
		__be32	nfserr;
L
Linus Torvalds 已提交
764 765 766 767 768 769 770
		int	syserr;
	} nfs_errtbl[] = {
		{ nfs_ok, 0 },
		{ nfserr_perm, -EPERM },
		{ nfserr_noent, -ENOENT },
		{ nfserr_io, -EIO },
		{ nfserr_nxio, -ENXIO },
771
		{ nfserr_fbig, -E2BIG },
L
Linus Torvalds 已提交
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
		{ nfserr_acces, -EACCES },
		{ nfserr_exist, -EEXIST },
		{ nfserr_xdev, -EXDEV },
		{ nfserr_mlink, -EMLINK },
		{ nfserr_nodev, -ENODEV },
		{ nfserr_notdir, -ENOTDIR },
		{ nfserr_isdir, -EISDIR },
		{ nfserr_inval, -EINVAL },
		{ nfserr_fbig, -EFBIG },
		{ nfserr_nospc, -ENOSPC },
		{ nfserr_rofs, -EROFS },
		{ nfserr_mlink, -EMLINK },
		{ nfserr_nametoolong, -ENAMETOOLONG },
		{ nfserr_notempty, -ENOTEMPTY },
#ifdef EDQUOT
		{ nfserr_dquot, -EDQUOT },
#endif
		{ nfserr_stale, -ESTALE },
		{ nfserr_jukebox, -ETIMEDOUT },
791
		{ nfserr_jukebox, -ERESTARTSYS },
792 793
		{ nfserr_jukebox, -EAGAIN },
		{ nfserr_jukebox, -EWOULDBLOCK },
794
		{ nfserr_jukebox, -ENOMEM },
L
Linus Torvalds 已提交
795
		{ nfserr_io, -ETXTBSY },
796
		{ nfserr_notsupp, -EOPNOTSUPP },
797
		{ nfserr_toosmall, -ETOOSMALL },
798
		{ nfserr_serverfault, -ESERVERFAULT },
799
		{ nfserr_serverfault, -ENFILE },
J
J. Bruce Fields 已提交
800
		{ nfserr_io, -EUCLEAN },
801
		{ nfserr_perm, -ENOKEY },
L
Linus Torvalds 已提交
802 803 804
	};
	int	i;

805
	for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
L
Linus Torvalds 已提交
806 807 808
		if (nfs_errtbl[i].syserr == errno)
			return nfs_errtbl[i].nfserr;
	}
809
	WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
L
Linus Torvalds 已提交
810 811 812
	return nfserr_io;
}