proc.c 22.9 KB
Newer Older
1 2 3
/*
 *  linux/fs/nfs/proc.c
 *
Linus Torvalds's avatar
Linus Torvalds committed
4
 *  Copyright (C) 1992, 1993, 1994  Rick Sladkey
5 6
 *
 *  OS-independent nfs remote procedure call functions
Linus Torvalds's avatar
Linus Torvalds committed
7 8 9 10 11
 *
 *  Tuned by Alan Cox <A.Cox@swansea.ac.uk> for >3K buffers
 *  so at last we can have decent(ish) throughput off a 
 *  Sun server.
 *
Linus Torvalds's avatar
Linus Torvalds committed
12 13 14 15
 *  Coding optimized and cleaned up by Florian La Roche.
 *  Note: Error returns are optimized for NFS_OK, which isn't translated via
 *  nfs_stat_to_errno(), but happens to be already the right return code.
 *
Linus Torvalds's avatar
Linus Torvalds committed
16 17 18 19
 *  FixMe: We ought to define a sensible small max size for
 *  things like getattr that are tiny packets and use the
 *  old get_free_page stuff with it.
 *
Linus Torvalds's avatar
Linus Torvalds committed
20 21 22
 *  Also, the code currently doesn't check the size of the packet, when
 *  it decodes the packet.
 *
Linus Torvalds's avatar
Linus Torvalds committed
23
 *  Feel free to fix it and mail me the diffs if it worries you.
24 25 26 27 28 29 30 31
 */

/*
 * Defining NFS_PROC_DEBUG causes a lookup of a file named
 * "xyzzy" to toggle debugging.  Just cd to an NFS-mounted
 * filesystem and type 'ls xyzzy' to turn on debugging.
 */

32
#if 0
33
#define NFS_PROC_DEBUG
34
#endif
35

36
#include <linux/config.h>
37 38 39
#include <linux/param.h>
#include <linux/sched.h>
#include <linux/mm.h>
Linus Torvalds's avatar
Linus Torvalds committed
40
#include <linux/malloc.h>
41 42 43 44
#include <linux/nfs_fs.h>
#include <linux/utsname.h>
#include <linux/errno.h>
#include <linux/string.h>
45
#include <linux/in.h>
Linus Torvalds's avatar
Linus Torvalds committed
46
#include <asm/segment.h>
47

48
#ifdef NFS_PROC_DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
49

50
static int proc_debug = 0;
Linus Torvalds's avatar
Linus Torvalds committed
51 52 53 54 55 56 57 58 59
#define PRINTK(format, args...) \
	do {						\
		if (proc_debug)				\
			printk(format , ## args);	\
	} while (0)

#else /* !NFS_PROC_DEBUG */

#define PRINTK(format, args...) do ; while (0)
60

Linus Torvalds's avatar
Linus Torvalds committed
61
#endif /* !NFS_PROC_DEBUG */
62

Linus Torvalds's avatar
Linus Torvalds committed
63 64 65
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO

Linus Torvalds's avatar
Linus Torvalds committed
66
static int *nfs_rpc_header(int *p, int procedure, int ruid);
67 68 69
static int *nfs_rpc_verify(int *p);
static int nfs_stat_to_errno(int stat);

Linus Torvalds's avatar
Linus Torvalds committed
70 71 72
/*
 * Our memory allocation and release functions.
 */
Linus Torvalds's avatar
Linus Torvalds committed
73 74
 
#define NFS_SLACK_SPACE		1024	/* Total overkill */ 
Linus Torvalds's avatar
Linus Torvalds committed
75 76
/* !!! Be careful, this constant is now also used in sock.c...
   We should easily convert to not using it anymore for most cases... */
Linus Torvalds's avatar
Linus Torvalds committed
77

Linus Torvalds's avatar
Linus Torvalds committed
78
static inline int *nfs_rpc_alloc(int size)
Linus Torvalds's avatar
Linus Torvalds committed
79
{
Linus Torvalds's avatar
Linus Torvalds committed
80 81 82
#if 1
	/* Allow for the NFS crap as well as buffer */
	return (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
83
#else 
Linus Torvalds's avatar
Linus Torvalds committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
	/* If kmalloc fails, then we will give an EIO to user level.
	   (Please correct me, I am wron here... ??) This is not
	   desirable, but it is also not desirable to execute the
	   following code: Just loop until we get memory, call schedule(),
	   so that other processes are run inbetween (and hopefully give
	   some memory back).		Florian
	*/
	int i;

	while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_KERNEL))) {
		/* printk("NFS: call schedule\n"); */
		schedule();
	}
	return i;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
99 100 101 102
}

static inline void nfs_rpc_free(int *p)
{
Linus Torvalds's avatar
Linus Torvalds committed
103
	kfree((void *)p);
Linus Torvalds's avatar
Linus Torvalds committed
104 105
}

106 107 108 109 110
/*
 * Here are a bunch of xdr encode/decode functions that convert
 * between machine dependent and xdr data formats.
 */

Linus Torvalds's avatar
Linus Torvalds committed
111 112
#define QUADLEN(len) (((len) + 3) >> 2)

113 114 115
static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle)
{
	*((struct nfs_fh *) p) = *fhandle;
Linus Torvalds's avatar
Linus Torvalds committed
116
	return p + QUADLEN(sizeof(*fhandle));
117 118 119 120 121
}

static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle)
{
	*fhandle = *((struct nfs_fh *) p);
Linus Torvalds's avatar
Linus Torvalds committed
122
	return p + QUADLEN(sizeof(*fhandle));
123 124
}

125
static inline int *xdr_encode_string(int *p, const char *string)
126
{
Linus Torvalds's avatar
Linus Torvalds committed
127 128 129 130
	int len = strlen(string);
	int quadlen = QUADLEN(len);

	p[quadlen] = 0;
131
	*p++ = htonl(len);
Linus Torvalds's avatar
Linus Torvalds committed
132 133
	memcpy(p, string, len);
	return p + quadlen;
134 135
}

Linus Torvalds's avatar
Linus Torvalds committed
136
static inline int *xdr_decode_string(int *p, char *string, unsigned int maxlen)
137
{
Linus Torvalds's avatar
Linus Torvalds committed
138
	unsigned int len = ntohl(*p++);
139 140
	if (len > maxlen)
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
141
	memcpy(string, p, len);
142
	string[len] = '\0';
Linus Torvalds's avatar
Linus Torvalds committed
143 144 145 146 147 148 149 150 151 152 153
	return p + QUADLEN(len);
}

static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len,
			unsigned int maxlen)
{
	*len = ntohl(*p++);
	if (*len > maxlen)
		return NULL;
	*string = (char *) p;
	return p + QUADLEN(*len);
154 155
}

Linus Torvalds's avatar
Linus Torvalds committed
156

157 158
static inline int *xdr_encode_data(int *p, char *data, int len)
{
Linus Torvalds's avatar
Linus Torvalds committed
159
	int quadlen = QUADLEN(len);
160
	
Linus Torvalds's avatar
Linus Torvalds committed
161
	p[quadlen] = 0;
162
	*p++ = htonl(len);
Linus Torvalds's avatar
Linus Torvalds committed
163 164
	memcpy_fromfs(p, data, len);
	return p + quadlen;
165 166
}

Linus Torvalds's avatar
Linus Torvalds committed
167 168
static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen,
			int fs)
169
{
Linus Torvalds's avatar
Linus Torvalds committed
170
	unsigned len = *lenp = ntohl(*p++);
171 172
	if (len > maxlen)
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
173 174 175 176 177
	if (fs)
		memcpy_tofs(data, p, len);
	else
		memcpy(data, p, len);
	return p + QUADLEN(len);
178 179 180 181
}

static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr)
{
Linus Torvalds's avatar
Linus Torvalds committed
182
	fattr->type = (enum nfs_ftype) ntohl(*p++);
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
	fattr->mode = ntohl(*p++);
	fattr->nlink = ntohl(*p++);
	fattr->uid = ntohl(*p++);
	fattr->gid = ntohl(*p++);
	fattr->size = ntohl(*p++);
	fattr->blocksize = ntohl(*p++);
	fattr->rdev = ntohl(*p++);
	fattr->blocks = ntohl(*p++);
	fattr->fsid = ntohl(*p++);
	fattr->fileid = ntohl(*p++);
	fattr->atime.seconds = ntohl(*p++);
	fattr->atime.useconds = ntohl(*p++);
	fattr->mtime.seconds = ntohl(*p++);
	fattr->mtime.useconds = ntohl(*p++);
	fattr->ctime.seconds = ntohl(*p++);
	fattr->ctime.useconds = ntohl(*p++);
	return p;
}

static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr)
{
	*p++ = htonl(sattr->mode);
	*p++ = htonl(sattr->uid);
	*p++ = htonl(sattr->gid);
	*p++ = htonl(sattr->size);
	*p++ = htonl(sattr->atime.seconds);
	*p++ = htonl(sattr->atime.useconds);
	*p++ = htonl(sattr->mtime.seconds);
	*p++ = htonl(sattr->mtime.useconds);
	return p;
}

static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
{
	entry->fileid = ntohl(*p++);
218 219
	if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN)))
		return NULL;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	entry->cookie = ntohl(*p++);
	entry->eof = 0;
	return p;
}

static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res)
{
	res->tsize = ntohl(*p++);
	res->bsize = ntohl(*p++);
	res->blocks = ntohl(*p++);
	res->bfree = ntohl(*p++);
	res->bavail = ntohl(*p++);
	return p;
}

Linus Torvalds's avatar
Linus Torvalds committed
235 236 237 238
/*
 * One function for each procedure in the NFS protocol.
 */

239 240 241 242 243
int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
		     struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
244
	int ruid = 0;
245 246

	PRINTK("NFS call  getattr\n");
Linus Torvalds's avatar
Linus Torvalds committed
247
	if (!(p0 = nfs_rpc_alloc(server->rsize)))
Linus Torvalds's avatar
Linus Torvalds committed
248
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
249 250
retry:
	p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
251
	p = xdr_encode_fhandle(p, fhandle);
Linus Torvalds's avatar
Linus Torvalds committed
252
	if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
253
		nfs_rpc_free(p0);
254 255 256
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
257
		status = -errno_NFSERR_IO;
258 259 260
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply getattr\n");
Linus Torvalds's avatar
Linus Torvalds committed
261
		/* status = 0; */
262
	}
Linus Torvalds's avatar
Linus Torvalds committed
263
	else {
Linus Torvalds's avatar
Linus Torvalds committed
264
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
265 266 267
			ruid = 1;
			goto retry;
		}
268
		PRINTK("NFS reply getattr failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
269
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
270
	}
Linus Torvalds's avatar
Linus Torvalds committed
271
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
272
	return status;
273 274 275 276 277 278 279
}

int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
		     struct nfs_sattr *sattr, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
280
	int ruid = 0;
281 282

	PRINTK("NFS call  setattr\n");
Linus Torvalds's avatar
Linus Torvalds committed
283
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
284
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
285 286
retry:
	p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
287 288
	p = xdr_encode_fhandle(p, fhandle);
	p = xdr_encode_sattr(p, sattr);
Linus Torvalds's avatar
Linus Torvalds committed
289
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
290
		nfs_rpc_free(p0);
291 292 293
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
294
		status = -errno_NFSERR_IO;
295 296 297
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply setattr\n");
Linus Torvalds's avatar
Linus Torvalds committed
298
		/* status = 0; */
299
	}
Linus Torvalds's avatar
Linus Torvalds committed
300
	else {
Linus Torvalds's avatar
Linus Torvalds committed
301
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
302 303 304
			ruid = 1;
			goto retry;
		}
305
		PRINTK("NFS reply setattr failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
306
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
307
	}
Linus Torvalds's avatar
Linus Torvalds committed
308
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
309
	return status;
310 311
}

312
int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
313 314 315 316
		    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
317
	int ruid = 0;
318 319 320 321 322 323

	PRINTK("NFS call  lookup %s\n", name);
#ifdef NFS_PROC_DEBUG
	if (!strcmp(name, "xyzzy"))
		proc_debug = 1 - proc_debug;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
324
	if (!(p0 = nfs_rpc_alloc(server->rsize)))
Linus Torvalds's avatar
Linus Torvalds committed
325
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
326 327
retry:
	p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
328 329
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
Linus Torvalds's avatar
Linus Torvalds committed
330
	if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
331
		nfs_rpc_free(p0);
332 333 334
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
335
		status = -errno_NFSERR_IO;
336 337 338 339
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fhandle(p, fhandle);
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply lookup\n");
Linus Torvalds's avatar
Linus Torvalds committed
340
		/* status = 0; */
341
	}
Linus Torvalds's avatar
Linus Torvalds committed
342
	else {
Linus Torvalds's avatar
Linus Torvalds committed
343
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
344 345 346
			ruid = 1;
			goto retry;
		}
347
		PRINTK("NFS reply lookup failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
348
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
349
	}
Linus Torvalds's avatar
Linus Torvalds committed
350
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
351
	return status;
352 353 354
}

int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
Linus Torvalds's avatar
Linus Torvalds committed
355
		int **p0, char **string, unsigned int *len, unsigned int maxlen)
356
{
Linus Torvalds's avatar
Linus Torvalds committed
357 358
	int *p;
	int status, ruid = 0;
359 360

	PRINTK("NFS call  readlink\n");
Linus Torvalds's avatar
Linus Torvalds committed
361
	if (!(*p0 = nfs_rpc_alloc(server->rsize)))
Linus Torvalds's avatar
Linus Torvalds committed
362
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
363
retry:
Linus Torvalds's avatar
Linus Torvalds committed
364
	p = nfs_rpc_header(*p0, NFSPROC_READLINK, ruid);
365
	p = xdr_encode_fhandle(p, fhandle);
Linus Torvalds's avatar
Linus Torvalds committed
366
	if ((status = nfs_rpc_call(server, *p0, p, server->rsize)) < 0)
367
		return status;
Linus Torvalds's avatar
Linus Torvalds committed
368 369
	if (!(p = nfs_rpc_verify(*p0)))
		status = -errno_NFSERR_IO;
370
	else if ((status = ntohl(*p++)) == NFS_OK) {
Linus Torvalds's avatar
Linus Torvalds committed
371
		if (!(p = xdr_decode_string2(p, string, len, maxlen))) {
372
			printk("nfs_proc_readlink: giant pathname\n");
Linus Torvalds's avatar
Linus Torvalds committed
373
			status = -errno_NFSERR_IO;
374
		}
Linus Torvalds's avatar
Linus Torvalds committed
375 376
		else	/* status = 0, */
			PRINTK("NFS reply readlink\n");
377
	}
Linus Torvalds's avatar
Linus Torvalds committed
378
	else {
Linus Torvalds's avatar
Linus Torvalds committed
379
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
380 381 382
			ruid = 1;
			goto retry;
		}
383
		PRINTK("NFS reply readlink failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
384
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
385
	}
Linus Torvalds's avatar
Linus Torvalds committed
386
	return status;
387 388 389
}

int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
Linus Torvalds's avatar
Linus Torvalds committed
390
	  int offset, int count, char *data, struct nfs_fattr *fattr, int fs)
391 392 393
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
394
	int ruid = 0;
Linus Torvalds's avatar
Linus Torvalds committed
395
	int len;
396 397

	PRINTK("NFS call  read %d @ %d\n", count, offset);
Linus Torvalds's avatar
Linus Torvalds committed
398
	if (!(p0 = nfs_rpc_alloc(server->rsize)))
Linus Torvalds's avatar
Linus Torvalds committed
399
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
400 401
retry:
	p = nfs_rpc_header(p0, NFSPROC_READ, ruid);
402 403 404 405
	p = xdr_encode_fhandle(p, fhandle);
	*p++ = htonl(offset);
	*p++ = htonl(count);
	*p++ = htonl(count); /* traditional, could be any value */
Linus Torvalds's avatar
Linus Torvalds committed
406
	if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
407
		nfs_rpc_free(p0);
408 409 410
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
411
		status = -errno_NFSERR_IO;
412 413
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fattr(p, fattr);
Linus Torvalds's avatar
Linus Torvalds committed
414
		if (!(p = xdr_decode_data(p, data, &len, count, fs))) {
415
			printk("nfs_proc_read: giant data size\n"); 
Linus Torvalds's avatar
Linus Torvalds committed
416
			status = -errno_NFSERR_IO;
417
		}
Linus Torvalds's avatar
Linus Torvalds committed
418 419
		else {
			status = len;
420
			PRINTK("NFS reply read %d\n", len);
Linus Torvalds's avatar
Linus Torvalds committed
421
		}
422
	}
Linus Torvalds's avatar
Linus Torvalds committed
423
	else {
Linus Torvalds's avatar
Linus Torvalds committed
424
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
425 426 427
			ruid = 1;
			goto retry;
		}
428
		PRINTK("NFS reply read failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
429
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
430
	}
Linus Torvalds's avatar
Linus Torvalds committed
431
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
432
	return status;
433 434 435 436 437 438 439
}

int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
		   int offset, int count, char *data, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
440
	int ruid = 0;
441 442

	PRINTK("NFS call  write %d @ %d\n", count, offset);
Linus Torvalds's avatar
Linus Torvalds committed
443
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
444
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
445 446
retry:
	p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid);
447 448 449 450 451
	p = xdr_encode_fhandle(p, fhandle);
	*p++ = htonl(offset); /* traditional, could be any value */
	*p++ = htonl(offset);
	*p++ = htonl(count); /* traditional, could be any value */
	p = xdr_encode_data(p, data, count);
Linus Torvalds's avatar
Linus Torvalds committed
452
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
453
		nfs_rpc_free(p0);
454 455 456
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
457
		status = -errno_NFSERR_IO;
458 459 460
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply write\n");
Linus Torvalds's avatar
Linus Torvalds committed
461
		/* status = 0; */
462
	}
Linus Torvalds's avatar
Linus Torvalds committed
463
	else {
Linus Torvalds's avatar
Linus Torvalds committed
464
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
465 466 467
			ruid = 1;
			goto retry;
		}
468
		PRINTK("NFS reply write failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
469
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
470
	}
Linus Torvalds's avatar
Linus Torvalds committed
471
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
472
	return status;
473 474 475
}

int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
476
		    const char *name, struct nfs_sattr *sattr,
477 478 479 480
		    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
481
	int ruid = 0;
482 483

	PRINTK("NFS call  create %s\n", name);
Linus Torvalds's avatar
Linus Torvalds committed
484
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
485
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
486 487
retry:
	p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
488 489 490
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	p = xdr_encode_sattr(p, sattr);
Linus Torvalds's avatar
Linus Torvalds committed
491
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
492
		nfs_rpc_free(p0);
493 494 495
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
496
		status = -errno_NFSERR_IO;
497 498 499 500
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fhandle(p, fhandle);
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply create\n");
Linus Torvalds's avatar
Linus Torvalds committed
501
		/* status = 0; */
502
	}
Linus Torvalds's avatar
Linus Torvalds committed
503
	else {
Linus Torvalds's avatar
Linus Torvalds committed
504
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
505 506 507
			ruid = 1;
			goto retry;
		}
508
		PRINTK("NFS reply create failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
509
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
510
	}
Linus Torvalds's avatar
Linus Torvalds committed
511
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
512
	return status;
513 514
}

515
int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
516 517 518
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
519
	int ruid = 0;
520 521

	PRINTK("NFS call  remove %s\n", name);
Linus Torvalds's avatar
Linus Torvalds committed
522
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
523
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
524 525
retry:
	p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
526 527
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
Linus Torvalds's avatar
Linus Torvalds committed
528
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
529
		nfs_rpc_free(p0);
530 531 532
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
533
		status = -errno_NFSERR_IO;
534 535
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply remove\n");
Linus Torvalds's avatar
Linus Torvalds committed
536
		/* status = 0; */
537
	}
Linus Torvalds's avatar
Linus Torvalds committed
538
	else {
Linus Torvalds's avatar
Linus Torvalds committed
539
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
540 541 542
			ruid = 1;
			goto retry;
		}
543
		PRINTK("NFS reply remove failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
544
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
545
	}
Linus Torvalds's avatar
Linus Torvalds committed
546
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
547
	return status;
548 549 550
}

int nfs_proc_rename(struct nfs_server *server,
551 552
		    struct nfs_fh *old_dir, const char *old_name,
		    struct nfs_fh *new_dir, const char *new_name)
553 554 555
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
556
	int ruid = 0;
557 558

	PRINTK("NFS call  rename %s -> %s\n", old_name, new_name);
Linus Torvalds's avatar
Linus Torvalds committed
559
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
560
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
561 562
retry:
	p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
563 564 565 566
	p = xdr_encode_fhandle(p, old_dir);
	p = xdr_encode_string(p, old_name);
	p = xdr_encode_fhandle(p, new_dir);
	p = xdr_encode_string(p, new_name);
Linus Torvalds's avatar
Linus Torvalds committed
567
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
568
		nfs_rpc_free(p0);
569 570 571
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
572
		status = -errno_NFSERR_IO;
573 574
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply rename\n");
Linus Torvalds's avatar
Linus Torvalds committed
575
		/* status = 0; */
576
	}
Linus Torvalds's avatar
Linus Torvalds committed
577
	else {
Linus Torvalds's avatar
Linus Torvalds committed
578
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
579 580 581
			ruid = 1;
			goto retry;
		}
582
		PRINTK("NFS reply rename failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
583
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
584
	}
Linus Torvalds's avatar
Linus Torvalds committed
585
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
586
	return status;
587 588 589
}

int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
590
		  struct nfs_fh *dir, const char *name)
591 592 593
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
594
	int ruid = 0;
595 596

	PRINTK("NFS call  link %s\n", name);
Linus Torvalds's avatar
Linus Torvalds committed
597
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
598
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
599 600
retry:
	p = nfs_rpc_header(p0, NFSPROC_LINK, ruid);
601 602 603
	p = xdr_encode_fhandle(p, fhandle);
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
Linus Torvalds's avatar
Linus Torvalds committed
604
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
605
		nfs_rpc_free(p0);
606 607 608
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
609
		status = -errno_NFSERR_IO;
610 611
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply link\n");
Linus Torvalds's avatar
Linus Torvalds committed
612
		/* status = 0; */
613
	}
Linus Torvalds's avatar
Linus Torvalds committed
614
	else {
Linus Torvalds's avatar
Linus Torvalds committed
615
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
616 617 618
			ruid = 1;
			goto retry;
		}
619
		PRINTK("NFS reply link failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
620
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
621
	}
Linus Torvalds's avatar
Linus Torvalds committed
622
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
623
	return status;
624 625 626
}

int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
627
		     const char *name, const char *path, struct nfs_sattr *sattr)
628 629 630
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
631
	int ruid = 0;
632 633

	PRINTK("NFS call  symlink %s -> %s\n", name, path);
Linus Torvalds's avatar
Linus Torvalds committed
634
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
635
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
636 637
retry:
	p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
638 639 640 641
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	p = xdr_encode_string(p, path);
	p = xdr_encode_sattr(p, sattr);
Linus Torvalds's avatar
Linus Torvalds committed
642
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
643
		nfs_rpc_free(p0);
644 645 646
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
647
		status = -errno_NFSERR_IO;
648 649
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply symlink\n");
Linus Torvalds's avatar
Linus Torvalds committed
650
		/* status = 0; */
651
	}
Linus Torvalds's avatar
Linus Torvalds committed
652
	else {
Linus Torvalds's avatar
Linus Torvalds committed
653
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
654 655 656
			ruid = 1;
			goto retry;
		}
657
		PRINTK("NFS reply symlink failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
658
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
659
	}
Linus Torvalds's avatar
Linus Torvalds committed
660
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
661
	return status;
662 663 664
}

int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
665
		   const char *name, struct nfs_sattr *sattr,
666 667 668 669
		   struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
670
	int ruid = 0;
671 672

	PRINTK("NFS call  mkdir %s\n", name);
Linus Torvalds's avatar
Linus Torvalds committed
673
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
674
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
675 676
retry:
	p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid);
677 678 679
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	p = xdr_encode_sattr(p, sattr);
Linus Torvalds's avatar
Linus Torvalds committed
680
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
681
		nfs_rpc_free(p0);
682 683 684
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
685
		status = -errno_NFSERR_IO;
686 687 688 689
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fhandle(p, fhandle);
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply mkdir\n");
Linus Torvalds's avatar
Linus Torvalds committed
690
		/* status = 0; */
691
	}
Linus Torvalds's avatar
Linus Torvalds committed
692
	else {
Linus Torvalds's avatar
Linus Torvalds committed
693
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
694 695 696
			ruid = 1;
			goto retry;
		}
697
		PRINTK("NFS reply mkdir failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
698
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
699
	}
Linus Torvalds's avatar
Linus Torvalds committed
700
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
701
	return status;
702 703
}

704
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
705 706 707
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
708
	int ruid = 0;
709 710

	PRINTK("NFS call  rmdir %s\n", name);
Linus Torvalds's avatar
Linus Torvalds committed
711
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
Linus Torvalds's avatar
Linus Torvalds committed
712
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
713 714
retry:
	p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
715 716
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
Linus Torvalds's avatar
Linus Torvalds committed
717
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
718
		nfs_rpc_free(p0);
719 720 721
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
722
		status = -errno_NFSERR_IO;
723 724
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply rmdir\n");
Linus Torvalds's avatar
Linus Torvalds committed
725
		/* status = 0; */
726
	}
Linus Torvalds's avatar
Linus Torvalds committed
727
	else {
Linus Torvalds's avatar
Linus Torvalds committed
728
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
729 730 731
			ruid = 1;
			goto retry;
		}
732
		PRINTK("NFS reply rmdir failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
733
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
734
	}
Linus Torvalds's avatar
Linus Torvalds committed
735
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
736
	return status;
737 738 739 740 741 742 743
}

int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
		     int cookie, int count, struct nfs_entry *entry)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
744
	int ruid = 0;
Linus Torvalds's avatar
Linus Torvalds committed
745
	int i;
746 747 748 749 750
	int size;
	int eof;

	PRINTK("NFS call  readdir %d @ %d\n", count, cookie);
	size = server->rsize;
Linus Torvalds's avatar
Linus Torvalds committed
751
	if (!(p0 = nfs_rpc_alloc(server->rsize)))
Linus Torvalds's avatar
Linus Torvalds committed
752
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
753 754
retry:
	p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid);
755 756 757
	p = xdr_encode_fhandle(p, fhandle);
	*p++ = htonl(cookie);
	*p++ = htonl(size);
Linus Torvalds's avatar
Linus Torvalds committed
758
	if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
759
		nfs_rpc_free(p0);
760 761 762
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
763
		status = -errno_NFSERR_IO;
764
	else if ((status = ntohl(*p++)) == NFS_OK) {
765 766 767 768 769 770
		for (i = 0; i < count && *p++; i++) {
			if (!(p = xdr_decode_entry(p, entry++)))
				break;
		}
		if (!p) {
			printk("nfs_proc_readdir: giant filename\n");
Linus Torvalds's avatar
Linus Torvalds committed
771
			status = -errno_NFSERR_IO;
772 773 774 775 776 777 778 779
		}
		else {
			eof = (i == count && !*p++ && *p++)
			      || (i < count && *p++);
			if (eof && i)
				entry[-1].eof = 1;
			PRINTK("NFS reply readdir %d %s\n", i,
			       eof ? "eof" : "");
Linus Torvalds's avatar
Linus Torvalds committed
780
			status = i;
781 782
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
783
	else {
Linus Torvalds's avatar
Linus Torvalds committed
784
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
785 786 787
			ruid = 1;
			goto retry;
		}
788
		PRINTK("NFS reply readdir failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
789
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
790
	}
Linus Torvalds's avatar
Linus Torvalds committed
791
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
792
	return status;
793 794 795 796 797 798 799
}

int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
		    struct nfs_fsinfo *res)
{
	int *p, *p0;
	int status;
Linus Torvalds's avatar
Linus Torvalds committed
800
	int ruid = 0;
801 802

	PRINTK("NFS call  statfs\n");
Linus Torvalds's avatar
Linus Torvalds committed
803
	if (!(p0 = nfs_rpc_alloc(server->rsize)))
Linus Torvalds's avatar
Linus Torvalds committed
804
		return -EIO;
Linus Torvalds's avatar
Linus Torvalds committed
805 806
retry:
	p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
807
	p = xdr_encode_fhandle(p, fhandle);
Linus Torvalds's avatar
Linus Torvalds committed
808
	if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
809
		nfs_rpc_free(p0);
810 811 812
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
Linus Torvalds's avatar
Linus Torvalds committed
813
		status = -errno_NFSERR_IO;
814 815 816
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fsinfo(p, res);
		PRINTK("NFS reply statfs\n");
Linus Torvalds's avatar
Linus Torvalds committed
817
		/* status = 0; */
818
	}
Linus Torvalds's avatar
Linus Torvalds committed
819
	else {
Linus Torvalds's avatar
Linus Torvalds committed
820
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
Linus Torvalds's avatar
Linus Torvalds committed
821 822 823
			ruid = 1;
			goto retry;
		}
824
		PRINTK("NFS reply statfs failed = %d\n", status);
Linus Torvalds's avatar
Linus Torvalds committed
825
		status = -nfs_stat_to_errno(status);
Linus Torvalds's avatar
Linus Torvalds committed
826
	}
Linus Torvalds's avatar
Linus Torvalds committed
827
	nfs_rpc_free(p0);
Linus Torvalds's avatar
Linus Torvalds committed
828
	return status;
829 830 831 832 833 834
}

/*
 * Here are a few RPC-assist functions.
 */

Linus Torvalds's avatar
Linus Torvalds committed
835
static int *nfs_rpc_header(int *p, int procedure, int ruid)
836 837 838 839
{
	int *p1, *p2;
	int i;
	static int xid = 0;
840
	unsigned char *sys = (unsigned char *) system_utsname.nodename;
841 842 843 844 845 846 847 848 849 850 851 852 853 854

	if (xid == 0) {
		xid = CURRENT_TIME;
		xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0];
	}
	*p++ = htonl(++xid);
	*p++ = htonl(RPC_CALL);
	*p++ = htonl(RPC_VERSION);
	*p++ = htonl(NFS_PROGRAM);
	*p++ = htonl(NFS_VERSION);
	*p++ = htonl(procedure);
	*p++ = htonl(RPC_AUTH_UNIX);
	p1 = p++;
	*p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
855
	p = xdr_encode_string(p, (char *) sys);
Linus Torvalds's avatar
Linus Torvalds committed
856
	*p++ = htonl(ruid ? current->uid : current->fsuid);
857 858 859 860 861 862 863 864 865 866 867 868 869
	*p++ = htonl(current->egid);
	p2 = p++;
	for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++)
		*p++ = htonl(current->groups[i]);
	*p2 = htonl(i);
	*p1 = htonl((p - (p1 + 1)) << 2);
	*p++ = htonl(RPC_AUTH_NULL);
	*p++ = htonl(0);
	return p;
}

static int *nfs_rpc_verify(int *p)
{
870
	unsigned int n;
871 872

	p++;
873 874
	if ((n = ntohl(*p++)) != RPC_REPLY) {
		printk("nfs_rpc_verify: not an RPC reply: %d\n", n);
875
		return NULL;
876
	}
877 878
	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
		printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
879 880 881 882 883 884 885 886
		return NULL;
	}
	switch (n = ntohl(*p++)) {
	case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT:
		break;
	default:
		printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n);
		return NULL;
887
	}
888 889 890
	if ((n = ntohl(*p++)) > 400) {
		printk("nfs_rpc_verify: giant auth size\n");
		return NULL;
891
	}
Linus Torvalds's avatar
Linus Torvalds committed
892
	p += QUADLEN(n);
893 894
	if ((n = ntohl(*p++)) != RPC_SUCCESS) {
		printk("nfs_rpc_verify: RPC call failed: %d\n", n);
895
		return NULL;
896 897 898 899 900 901 902 903 904 905
	}
	return p;
}
	
/*
 * We need to translate between nfs status return values and
 * the local errno values which may not be the same.
 */

static struct {
906
	int stat;
907 908
	int errno;
} nfs_errtbl[] = {
909 910 911
	{ NFS_OK,		0		},
	{ NFSERR_PERM,		EPERM		},
	{ NFSERR_NOENT,		ENOENT		},
Linus Torvalds's avatar
Linus Torvalds committed
912
	{ NFSERR_IO,		errno_NFSERR_IO	},
913 914 915 916 917 918
	{ NFSERR_NXIO,		ENXIO		},
	{ NFSERR_ACCES,		EACCES		},
	{ NFSERR_EXIST,		EEXIST		},
	{ NFSERR_NODEV,		ENODEV		},
	{ NFSERR_NOTDIR,	ENOTDIR		},
	{ NFSERR_ISDIR,		EISDIR		},
Linus Torvalds's avatar
Linus Torvalds committed
919
	{ NFSERR_INVAL,		EINVAL		},
920 921 922 923 924 925 926 927 928 929 930
	{ NFSERR_FBIG,		EFBIG		},
	{ NFSERR_NOSPC,		ENOSPC		},
	{ NFSERR_ROFS,		EROFS		},
	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
	{ NFSERR_DQUOT,		EDQUOT		},
	{ NFSERR_STALE,		ESTALE		},
#ifdef EWFLUSH
	{ NFSERR_WFLUSH,	EWFLUSH		},
#endif
	{ -1,			EIO		}
931 932 933 934 935 936 937
};

static int nfs_stat_to_errno(int stat)
{
	int i;

	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
938 939
		if (nfs_errtbl[i].stat == stat)
			return nfs_errtbl[i].errno;
940
	}
941 942
	printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
	return nfs_errtbl[i].errno;
943 944
}