nfs3proc.c 23.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/*
 *  linux/fs/nfs/nfs3proc.c
 *
 *  Client-side NFSv3 procedures stubs.
 *
 *  Copyright (C) 1997, Olaf Kirch
 */

#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/sunrpc/clnt.h>
13
#include <linux/slab.h>
L
Linus Torvalds 已提交
14 15 16 17 18
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
19
#include <linux/nfs_mount.h>
20
#include <linux/freezer.h>
21
#include <linux/xattr.h>
L
Linus Torvalds 已提交
22

23
#include "iostat.h"
D
David Howells 已提交
24
#include "internal.h"
25

L
Linus Torvalds 已提交
26 27
#define NFSDBG_FACILITY		NFSDBG_PROC

28
/* A wrapper to handle the EJUKEBOX error messages */
L
Linus Torvalds 已提交
29 30 31 32 33 34
static int
nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
{
	int res;
	do {
		res = rpc_call_sync(clnt, msg, flags);
35
		if (res != -EJUKEBOX)
L
Linus Torvalds 已提交
36
			break;
37
		freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME);
L
Linus Torvalds 已提交
38
		res = -ERESTARTSYS;
39
	} while (!fatal_signal_pending(current));
L
Linus Torvalds 已提交
40 41 42
	return res;
}

C
Chuck Lever 已提交
43
#define rpc_call_sync(clnt, msg, flags)	nfs3_rpc_wrapper(clnt, msg, flags)
L
Linus Torvalds 已提交
44 45

static int
46
nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
L
Linus Torvalds 已提交
47
{
48
	if (task->tk_status != -EJUKEBOX)
L
Linus Torvalds 已提交
49
		return 0;
50 51
	if (task->tk_status == -EJUKEBOX)
		nfs_inc_stats(inode, NFSIOS_DELAY);
L
Linus Torvalds 已提交
52 53 54 55 56 57 58
	task->tk_status = 0;
	rpc_restart_call(task);
	rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
	return 1;
}

static int
59 60
do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle,
		 struct nfs_fsinfo *info)
L
Linus Torvalds 已提交
61
{
C
Chuck Lever 已提交
62 63 64 65 66
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_FSINFO],
		.rpc_argp	= fhandle,
		.rpc_resp	= info,
	};
L
Linus Torvalds 已提交
67 68
	int	status;

69
	dprintk("%s: call  fsinfo\n", __func__);
70
	nfs_fattr_init(info->fattr);
C
Chuck Lever 已提交
71
	status = rpc_call_sync(client, &msg, 0);
72
	dprintk("%s: reply fsinfo: %d\n", __func__, status);
73
	if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) {
C
Chuck Lever 已提交
74 75 76
		msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
		msg.rpc_resp = info->fattr;
		status = rpc_call_sync(client, &msg, 0);
77
		dprintk("%s: reply getattr: %d\n", __func__, status);
L
Linus Torvalds 已提交
78 79 80 81
	}
	return status;
}

82
/*
83
 * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
84 85 86 87 88 89 90 91
 */
static int
nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
		   struct nfs_fsinfo *info)
{
	int	status;

	status = do_proc_get_root(server->client, fhandle, info);
92 93
	if (status && server->nfs_client->cl_rpcclient != server->client)
		status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info);
94 95 96
	return status;
}

L
Linus Torvalds 已提交
97 98 99 100 101
/*
 * One function for each procedure in the NFS protocol.
 */
static int
nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
102
		struct nfs_fattr *fattr, struct nfs4_label *label)
L
Linus Torvalds 已提交
103
{
C
Chuck Lever 已提交
104 105 106 107 108
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_GETATTR],
		.rpc_argp	= fhandle,
		.rpc_resp	= fattr,
	};
L
Linus Torvalds 已提交
109 110 111
	int	status;

	dprintk("NFS call  getattr\n");
112
	nfs_fattr_init(fattr);
C
Chuck Lever 已提交
113
	status = rpc_call_sync(server->client, &msg, 0);
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126
	dprintk("NFS reply getattr: %d\n", status);
	return status;
}

static int
nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
			struct iattr *sattr)
{
	struct inode *inode = dentry->d_inode;
	struct nfs3_sattrargs	arg = {
		.fh		= NFS_FH(inode),
		.sattr		= sattr,
	};
C
Chuck Lever 已提交
127 128 129 130 131
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_SETATTR],
		.rpc_argp	= &arg,
		.rpc_resp	= fattr,
	};
L
Linus Torvalds 已提交
132 133 134
	int	status;

	dprintk("NFS call  setattr\n");
135 136
	if (sattr->ia_valid & ATTR_FILE)
		msg.rpc_cred = nfs_file_cred(sattr->ia_file);
137
	nfs_fattr_init(fattr);
C
Chuck Lever 已提交
138
	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
139 140
	if (status == 0)
		nfs_setattr_update_inode(inode, sattr);
L
Linus Torvalds 已提交
141 142 143 144 145
	dprintk("NFS reply setattr: %d\n", status);
	return status;
}

static int
146
nfs3_proc_lookup(struct inode *dir, struct qstr *name,
147 148
		 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
		 struct nfs4_label *label)
L
Linus Torvalds 已提交
149 150 151 152 153 154 155 156 157 158
{
	struct nfs3_diropargs	arg = {
		.fh		= NFS_FH(dir),
		.name		= name->name,
		.len		= name->len
	};
	struct nfs3_diropres	res = {
		.fh		= fhandle,
		.fattr		= fattr
	};
C
Chuck Lever 已提交
159 160 161 162 163
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_LOOKUP],
		.rpc_argp	= &arg,
		.rpc_resp	= &res,
	};
L
Linus Torvalds 已提交
164 165 166
	int			status;

	dprintk("NFS call  lookup %s\n", name->name);
167 168 169 170
	res.dir_attr = nfs_alloc_fattr();
	if (res.dir_attr == NULL)
		return -ENOMEM;

171
	nfs_fattr_init(fattr);
C
Chuck Lever 已提交
172
	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
173
	nfs_refresh_inode(dir, res.dir_attr);
C
Chuck Lever 已提交
174 175 176 177 178 179
	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
		msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
		msg.rpc_argp = fhandle;
		msg.rpc_resp = fattr;
		status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
	}
180
	nfs_free_fattr(res.dir_attr);
L
Linus Torvalds 已提交
181 182 183 184 185 186 187 188 189
	dprintk("NFS reply lookup: %d\n", status);
	return status;
}

static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{
	struct nfs3_accessargs	arg = {
		.fh		= NFS_FH(inode),
	};
190
	struct nfs3_accessres	res;
L
Linus Torvalds 已提交
191 192 193 194
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_ACCESS],
		.rpc_argp	= &arg,
		.rpc_resp	= &res,
C
Chuck Lever 已提交
195
		.rpc_cred	= entry->cred,
L
Linus Torvalds 已提交
196 197
	};
	int mode = entry->mask;
198
	int status = -ENOMEM;
L
Linus Torvalds 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214

	dprintk("NFS call  access\n");

	if (mode & MAY_READ)
		arg.access |= NFS3_ACCESS_READ;
	if (S_ISDIR(inode->i_mode)) {
		if (mode & MAY_WRITE)
			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
		if (mode & MAY_EXEC)
			arg.access |= NFS3_ACCESS_LOOKUP;
	} else {
		if (mode & MAY_WRITE)
			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND;
		if (mode & MAY_EXEC)
			arg.access |= NFS3_ACCESS_EXECUTE;
	}
215 216 217 218 219

	res.fattr = nfs_alloc_fattr();
	if (res.fattr == NULL)
		goto out;

L
Linus Torvalds 已提交
220
	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
221
	nfs_refresh_inode(inode, res.fattr);
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229 230
	if (status == 0) {
		entry->mask = 0;
		if (res.access & NFS3_ACCESS_READ)
			entry->mask |= MAY_READ;
		if (res.access & (NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE))
			entry->mask |= MAY_WRITE;
		if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE))
			entry->mask |= MAY_EXEC;
	}
231 232
	nfs_free_fattr(res.fattr);
out:
L
Linus Torvalds 已提交
233 234 235 236 237 238 239
	dprintk("NFS reply access: %d\n", status);
	return status;
}

static int nfs3_proc_readlink(struct inode *inode, struct page *page,
		unsigned int pgbase, unsigned int pglen)
{
240
	struct nfs_fattr	*fattr;
L
Linus Torvalds 已提交
241 242 243 244 245 246
	struct nfs3_readlinkargs args = {
		.fh		= NFS_FH(inode),
		.pgbase		= pgbase,
		.pglen		= pglen,
		.pages		= &page
	};
C
Chuck Lever 已提交
247 248 249 250
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_READLINK],
		.rpc_argp	= &args,
	};
251
	int status = -ENOMEM;
L
Linus Torvalds 已提交
252 253

	dprintk("NFS call  readlink\n");
254 255 256 257 258
	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		goto out;
	msg.rpc_resp = fattr;

C
Chuck Lever 已提交
259
	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
260 261 262
	nfs_refresh_inode(inode, fattr);
	nfs_free_fattr(fattr);
out:
L
Linus Torvalds 已提交
263 264 265 266
	dprintk("NFS reply readlink: %d\n", status);
	return status;
}

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
struct nfs3_createdata {
	struct rpc_message msg;
	union {
		struct nfs3_createargs create;
		struct nfs3_mkdirargs mkdir;
		struct nfs3_symlinkargs symlink;
		struct nfs3_mknodargs mknod;
	} arg;
	struct nfs3_diropres res;
	struct nfs_fh fh;
	struct nfs_fattr fattr;
	struct nfs_fattr dir_attr;
};

static struct nfs3_createdata *nfs3_alloc_createdata(void)
{
	struct nfs3_createdata *data;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (data != NULL) {
		data->msg.rpc_argp = &data->arg;
		data->msg.rpc_resp = &data->res;
		data->res.fh = &data->fh;
		data->res.fattr = &data->fattr;
		data->res.dir_attr = &data->dir_attr;
		nfs_fattr_init(data->res.fattr);
		nfs_fattr_init(data->res.dir_attr);
	}
	return data;
}

static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_createdata *data)
{
	int status;

	status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
	nfs_post_op_update_inode(dir, data->res.dir_attr);
	if (status == 0)
305
		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
306 307 308 309 310 311 312 313
	return status;
}

static void nfs3_free_createdata(struct nfs3_createdata *data)
{
	kfree(data);
}

L
Linus Torvalds 已提交
314 315 316 317 318
/*
 * Create a regular file.
 */
static int
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
319
		 int flags)
L
Linus Torvalds 已提交
320
{
321
	struct posix_acl *default_acl, *acl;
322 323
	struct nfs3_createdata *data;
	int status = -ENOMEM;
L
Linus Torvalds 已提交
324

325
	dprintk("NFS call  create %pd\n", dentry);
326 327 328 329 330 331 332 333 334 335 336 337

	data = nfs3_alloc_createdata();
	if (data == NULL)
		goto out;

	data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE];
	data->arg.create.fh = NFS_FH(dir);
	data->arg.create.name = dentry->d_name.name;
	data->arg.create.len = dentry->d_name.len;
	data->arg.create.sattr = sattr;

	data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
L
Linus Torvalds 已提交
338
	if (flags & O_EXCL) {
339
		data->arg.create.createmode  = NFS3_CREATE_EXCLUSIVE;
340 341
		data->arg.create.verifier[0] = cpu_to_be32(jiffies);
		data->arg.create.verifier[1] = cpu_to_be32(current->pid);
L
Linus Torvalds 已提交
342 343
	}

344 345 346
	status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
	if (status)
		goto out;
347

348 349
	for (;;) {
		status = nfs3_do_create(dir, dentry, data);
L
Linus Torvalds 已提交
350

351 352 353 354 355
		if (status != -ENOTSUPP)
			break;
		/* If the server doesn't support the exclusive creation
		 * semantics, try again with simple 'guarded' mode. */
		switch (data->arg.create.createmode) {
L
Linus Torvalds 已提交
356
			case NFS3_CREATE_EXCLUSIVE:
357
				data->arg.create.createmode = NFS3_CREATE_GUARDED;
L
Linus Torvalds 已提交
358 359 360
				break;

			case NFS3_CREATE_GUARDED:
361
				data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
L
Linus Torvalds 已提交
362 363 364 365 366
				break;

			case NFS3_CREATE_UNCHECKED:
				goto out;
		}
367 368
		nfs_fattr_init(data->res.dir_attr);
		nfs_fattr_init(data->res.fattr);
L
Linus Torvalds 已提交
369 370 371
	}

	if (status != 0)
372
		goto out_release_acls;
L
Linus Torvalds 已提交
373 374 375

	/* When we created the file with exclusive semantics, make
	 * sure we set the attributes afterwards. */
376
	if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) {
L
Linus Torvalds 已提交
377 378 379 380 381 382 383 384 385 386
		dprintk("NFS call  setattr (post-create)\n");

		if (!(sattr->ia_valid & ATTR_ATIME_SET))
			sattr->ia_valid |= ATTR_ATIME;
		if (!(sattr->ia_valid & ATTR_MTIME_SET))
			sattr->ia_valid |= ATTR_MTIME;

		/* Note: we could use a guarded setattr here, but I'm
		 * not sure this buys us anything (and I'd have
		 * to revamp the NFSv3 XDR code) */
387 388
		status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
		nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
L
Linus Torvalds 已提交
389
		dprintk("NFS reply setattr (post-create): %d\n", status);
390
		if (status != 0)
391
			goto out_release_acls;
L
Linus Torvalds 已提交
392
	}
393 394 395 396 397 398

	status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);

out_release_acls:
	posix_acl_release(acl);
	posix_acl_release(default_acl);
L
Linus Torvalds 已提交
399
out:
400
	nfs3_free_createdata(data);
L
Linus Torvalds 已提交
401 402 403 404 405 406 407
	dprintk("NFS reply create: %d\n", status);
	return status;
}

static int
nfs3_proc_remove(struct inode *dir, struct qstr *name)
{
408 409
	struct nfs_removeargs arg = {
		.fh = NFS_FH(dir),
410
		.name = *name,
L
Linus Torvalds 已提交
411
	};
412 413 414 415 416
	struct nfs_removeres res;
	struct rpc_message msg = {
		.rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE],
		.rpc_argp = &arg,
		.rpc_resp = &res,
L
Linus Torvalds 已提交
417
	};
418
	int status = -ENOMEM;
L
Linus Torvalds 已提交
419 420

	dprintk("NFS call  remove %s\n", name->name);
421 422 423 424
	res.dir_attr = nfs_alloc_fattr();
	if (res.dir_attr == NULL)
		goto out;

L
Linus Torvalds 已提交
425
	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
426 427 428
	nfs_post_op_update_inode(dir, res.dir_attr);
	nfs_free_fattr(res.dir_attr);
out:
L
Linus Torvalds 已提交
429 430 431 432
	dprintk("NFS reply remove: %d\n", status);
	return status;
}

433 434
static void
nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
L
Linus Torvalds 已提交
435 436 437 438
{
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
}

439 440 441 442 443
static void nfs3_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
{
	rpc_call_start(task);
}

L
Linus Torvalds 已提交
444
static int
445
nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
L
Linus Torvalds 已提交
446
{
447 448 449 450
	struct nfs_removeres *res;
	if (nfs3_async_handle_jukebox(task, dir))
		return 0;
	res = task->tk_msg.rpc_resp;
451
	nfs_post_op_update_inode(dir, res->dir_attr);
452
	return 1;
L
Linus Torvalds 已提交
453 454
}

455 456 457 458 459 460
static void
nfs3_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
{
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME];
}

461 462 463 464 465
static void nfs3_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
{
	rpc_call_start(task);
}

466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
static int
nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
		      struct inode *new_dir)
{
	struct nfs_renameres *res;

	if (nfs3_async_handle_jukebox(task, old_dir))
		return 0;
	res = task->tk_msg.rpc_resp;

	nfs_post_op_update_inode(old_dir, res->old_fattr);
	nfs_post_op_update_inode(new_dir, res->new_fattr);
	return 1;
}

L
Linus Torvalds 已提交
481 482 483 484 485 486 487 488 489
static int
nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{
	struct nfs3_linkargs	arg = {
		.fromfh		= NFS_FH(inode),
		.tofh		= NFS_FH(dir),
		.toname		= name->name,
		.tolen		= name->len
	};
490
	struct nfs3_linkres	res;
C
Chuck Lever 已提交
491 492 493 494 495
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_LINK],
		.rpc_argp	= &arg,
		.rpc_resp	= &res,
	};
496
	int status = -ENOMEM;
L
Linus Torvalds 已提交
497 498

	dprintk("NFS call  link %s\n", name->name);
499 500 501 502 503
	res.fattr = nfs_alloc_fattr();
	res.dir_attr = nfs_alloc_fattr();
	if (res.fattr == NULL || res.dir_attr == NULL)
		goto out;

C
Chuck Lever 已提交
504
	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
505 506 507 508 509
	nfs_post_op_update_inode(dir, res.dir_attr);
	nfs_post_op_update_inode(inode, res.fattr);
out:
	nfs_free_fattr(res.dir_attr);
	nfs_free_fattr(res.fattr);
L
Linus Torvalds 已提交
510 511 512 513 514
	dprintk("NFS reply link: %d\n", status);
	return status;
}

static int
515 516
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
		  unsigned int len, struct iattr *sattr)
L
Linus Torvalds 已提交
517
{
518 519
	struct nfs3_createdata *data;
	int status = -ENOMEM;
L
Linus Torvalds 已提交
520

521
	if (len > NFS3_MAXPATHLEN)
L
Linus Torvalds 已提交
522
		return -ENAMETOOLONG;
523

524
	dprintk("NFS call  symlink %pd\n", dentry);
525

526 527
	data = nfs3_alloc_createdata();
	if (data == NULL)
528
		goto out;
529 530 531 532 533 534 535 536 537 538 539
	data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK];
	data->arg.symlink.fromfh = NFS_FH(dir);
	data->arg.symlink.fromname = dentry->d_name.name;
	data->arg.symlink.fromlen = dentry->d_name.len;
	data->arg.symlink.pages = &page;
	data->arg.symlink.pathlen = len;
	data->arg.symlink.sattr = sattr;

	status = nfs3_do_create(dir, dentry, data);

	nfs3_free_createdata(data);
540
out:
L
Linus Torvalds 已提交
541 542 543 544 545 546 547
	dprintk("NFS reply symlink: %d\n", status);
	return status;
}

static int
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
{
548
	struct posix_acl *default_acl, *acl;
549 550
	struct nfs3_createdata *data;
	int status = -ENOMEM;
L
Linus Torvalds 已提交
551

552
	dprintk("NFS call  mkdir %pd\n", dentry);
553

554 555
	data = nfs3_alloc_createdata();
	if (data == NULL)
556
		goto out;
557

558 559 560 561
	status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
	if (status)
		goto out;

562 563 564 565 566 567 568
	data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
	data->arg.mkdir.fh = NFS_FH(dir);
	data->arg.mkdir.name = dentry->d_name.name;
	data->arg.mkdir.len = dentry->d_name.len;
	data->arg.mkdir.sattr = sattr;

	status = nfs3_do_create(dir, dentry, data);
569
	if (status != 0)
570
		goto out_release_acls;
571

572 573 574 575 576
	status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);

out_release_acls:
	posix_acl_release(acl);
	posix_acl_release(default_acl);
577
out:
578
	nfs3_free_createdata(data);
L
Linus Torvalds 已提交
579 580 581 582 583 584 585
	dprintk("NFS reply mkdir: %d\n", status);
	return status;
}

static int
nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
{
586
	struct nfs_fattr	*dir_attr;
L
Linus Torvalds 已提交
587 588 589 590 591
	struct nfs3_diropargs	arg = {
		.fh		= NFS_FH(dir),
		.name		= name->name,
		.len		= name->len
	};
C
Chuck Lever 已提交
592 593 594 595
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_RMDIR],
		.rpc_argp	= &arg,
	};
596
	int status = -ENOMEM;
L
Linus Torvalds 已提交
597 598

	dprintk("NFS call  rmdir %s\n", name->name);
599 600 601 602 603
	dir_attr = nfs_alloc_fattr();
	if (dir_attr == NULL)
		goto out;

	msg.rpc_resp = dir_attr;
C
Chuck Lever 已提交
604
	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
605 606 607
	nfs_post_op_update_inode(dir, dir_attr);
	nfs_free_fattr(dir_attr);
out:
L
Linus Torvalds 已提交
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
	dprintk("NFS reply rmdir: %d\n", status);
	return status;
}

/*
 * The READDIR implementation is somewhat hackish - we pass the user buffer
 * to the encode function, which installs it in the receive iovec.
 * The decode function itself doesn't perform any decoding, it just makes
 * sure the reply is syntactically correct.
 *
 * Also note that this implementation handles both plain readdir and
 * readdirplus.
 */
static int
nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
B
Bryan Schumaker 已提交
623
		  u64 cookie, struct page **pages, unsigned int count, int plus)
L
Linus Torvalds 已提交
624 625
{
	struct inode		*dir = dentry->d_inode;
626
	__be32			*verf = NFS_I(dir)->cookieverf;
L
Linus Torvalds 已提交
627 628 629 630 631 632
	struct nfs3_readdirargs	arg = {
		.fh		= NFS_FH(dir),
		.cookie		= cookie,
		.verf		= {verf[0], verf[1]},
		.plus		= plus,
		.count		= count,
B
Bryan Schumaker 已提交
633
		.pages		= pages
L
Linus Torvalds 已提交
634 635 636 637 638 639 640 641 642 643 644
	};
	struct nfs3_readdirres	res = {
		.verf		= verf,
		.plus		= plus
	};
	struct rpc_message	msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_READDIR],
		.rpc_argp	= &arg,
		.rpc_resp	= &res,
		.rpc_cred	= cred
	};
645
	int status = -ENOMEM;
L
Linus Torvalds 已提交
646 647 648 649 650 651 652

	if (plus)
		msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS];

	dprintk("NFS call  readdir%s %d\n",
			plus? "plus" : "", (unsigned int) cookie);

653 654 655 656
	res.dir_attr = nfs_alloc_fattr();
	if (res.dir_attr == NULL)
		goto out;

L
Linus Torvalds 已提交
657
	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
658 659

	nfs_invalidate_atime(dir);
660
	nfs_refresh_inode(dir, res.dir_attr);
661

662 663
	nfs_free_fattr(res.dir_attr);
out:
664 665
	dprintk("NFS reply readdir%s: %d\n",
			plus? "plus" : "", status);
L
Linus Torvalds 已提交
666 667 668 669 670 671 672
	return status;
}

static int
nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
		dev_t rdev)
{
673
	struct posix_acl *default_acl, *acl;
674 675
	struct nfs3_createdata *data;
	int status = -ENOMEM;
L
Linus Torvalds 已提交
676

677
	dprintk("NFS call  mknod %pd %u:%u\n", dentry,
L
Linus Torvalds 已提交
678
			MAJOR(rdev), MINOR(rdev));
679

680 681
	data = nfs3_alloc_createdata();
	if (data == NULL)
682
		goto out;
683

684 685 686 687
	status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
	if (status)
		goto out;

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
	data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD];
	data->arg.mknod.fh = NFS_FH(dir);
	data->arg.mknod.name = dentry->d_name.name;
	data->arg.mknod.len = dentry->d_name.len;
	data->arg.mknod.sattr = sattr;
	data->arg.mknod.rdev = rdev;

	switch (sattr->ia_mode & S_IFMT) {
	case S_IFBLK:
		data->arg.mknod.type = NF3BLK;
		break;
	case S_IFCHR:
		data->arg.mknod.type = NF3CHR;
		break;
	case S_IFIFO:
		data->arg.mknod.type = NF3FIFO;
		break;
	case S_IFSOCK:
		data->arg.mknod.type = NF3SOCK;
		break;
	default:
		status = -EINVAL;
		goto out;
	}

	status = nfs3_do_create(dir, dentry, data);
714
	if (status != 0)
715 716 717 718 719 720 721
		goto out_release_acls;

	status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);

out_release_acls:
	posix_acl_release(acl);
	posix_acl_release(default_acl);
722
out:
723
	nfs3_free_createdata(data);
L
Linus Torvalds 已提交
724 725 726 727 728 729 730 731
	dprintk("NFS reply mknod: %d\n", status);
	return status;
}

static int
nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
		 struct nfs_fsstat *stat)
{
C
Chuck Lever 已提交
732 733 734 735 736
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_FSSTAT],
		.rpc_argp	= fhandle,
		.rpc_resp	= stat,
	};
L
Linus Torvalds 已提交
737 738 739
	int	status;

	dprintk("NFS call  fsstat\n");
740
	nfs_fattr_init(stat->fattr);
C
Chuck Lever 已提交
741
	status = rpc_call_sync(server->client, &msg, 0);
742
	dprintk("NFS reply fsstat: %d\n", status);
L
Linus Torvalds 已提交
743 744 745 746
	return status;
}

static int
E
EG Keizer 已提交
747
do_proc_fsinfo(struct rpc_clnt *client, struct nfs_fh *fhandle,
L
Linus Torvalds 已提交
748 749
		 struct nfs_fsinfo *info)
{
C
Chuck Lever 已提交
750 751 752 753 754
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_FSINFO],
		.rpc_argp	= fhandle,
		.rpc_resp	= info,
	};
L
Linus Torvalds 已提交
755 756 757
	int	status;

	dprintk("NFS call  fsinfo\n");
758
	nfs_fattr_init(info->fattr);
E
EG Keizer 已提交
759
	status = rpc_call_sync(client, &msg, 0);
L
Linus Torvalds 已提交
760 761 762 763
	dprintk("NFS reply fsinfo: %d\n", status);
	return status;
}

E
EG Keizer 已提交
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
/*
 * Bare-bones access to fsinfo: this is for nfs_get_root/nfs_get_sb via
 * nfs_create_server
 */
static int
nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
		   struct nfs_fsinfo *info)
{
	int	status;

	status = do_proc_fsinfo(server->client, fhandle, info);
	if (status && server->nfs_client->cl_rpcclient != server->client)
		status = do_proc_fsinfo(server->nfs_client->cl_rpcclient, fhandle, info);
	return status;
}

L
Linus Torvalds 已提交
780 781 782 783
static int
nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
		   struct nfs_pathconf *info)
{
C
Chuck Lever 已提交
784 785 786 787 788
	struct rpc_message msg = {
		.rpc_proc	= &nfs3_procedures[NFS3PROC_PATHCONF],
		.rpc_argp	= fhandle,
		.rpc_resp	= info,
	};
L
Linus Torvalds 已提交
789 790 791
	int	status;

	dprintk("NFS call  pathconf\n");
792
	nfs_fattr_init(info->fattr);
C
Chuck Lever 已提交
793
	status = rpc_call_sync(server->client, &msg, 0);
L
Linus Torvalds 已提交
794 795 796 797
	dprintk("NFS reply pathconf: %d\n", status);
	return status;
}

798
static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_data *data)
L
Linus Torvalds 已提交
799
{
800 801 802
	struct inode *inode = data->header->inode;

	if (nfs3_async_handle_jukebox(task, inode))
T
Trond Myklebust 已提交
803
		return -EAGAIN;
804

805 806
	nfs_invalidate_atime(inode);
	nfs_refresh_inode(inode, &data->fattr);
T
Trond Myklebust 已提交
807
	return 0;
L
Linus Torvalds 已提交
808 809
}

810
static void nfs3_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
L
Linus Torvalds 已提交
811
{
812
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
L
Linus Torvalds 已提交
813 814
}

815
static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data)
816 817
{
	rpc_call_start(task);
818
	return 0;
819 820
}

821
static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_data *data)
L
Linus Torvalds 已提交
822
{
823 824 825
	struct inode *inode = data->header->inode;

	if (nfs3_async_handle_jukebox(task, inode))
826
		return -EAGAIN;
L
Linus Torvalds 已提交
827
	if (task->tk_status >= 0)
828
		nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
829
	return 0;
L
Linus Torvalds 已提交
830 831
}

832
static void nfs3_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg)
L
Linus Torvalds 已提交
833
{
834
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
L
Linus Torvalds 已提交
835 836
}

837 838 839 840 841 842
static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
{
	rpc_call_start(task);
}

static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
L
Linus Torvalds 已提交
843
{
844
	if (nfs3_async_handle_jukebox(task, data->inode))
845
		return -EAGAIN;
846
	nfs_refresh_inode(data->inode, data->res.fattr);
847
	return 0;
L
Linus Torvalds 已提交
848 849
}

850
static void nfs3_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg)
L
Linus Torvalds 已提交
851
{
852
	msg->rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT];
L
Linus Torvalds 已提交
853 854 855 856 857
}

static int
nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
A
Al Viro 已提交
858
	struct inode *inode = file_inode(filp);
859 860

	return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
L
Linus Torvalds 已提交
861 862
}

863 864 865 866 867
static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
{
	return 0;
}

868 869 870 871 872 873
static int nfs3_return_delegation(struct inode *inode)
{
	nfs_wb_all(inode);
	return 0;
}

874 875 876 877 878 879 880 881 882 883 884 885 886
static const struct inode_operations nfs3_dir_inode_operations = {
	.create		= nfs_create,
	.lookup		= nfs_lookup,
	.link		= nfs_link,
	.unlink		= nfs_unlink,
	.symlink	= nfs_symlink,
	.mkdir		= nfs_mkdir,
	.rmdir		= nfs_rmdir,
	.mknod		= nfs_mknod,
	.rename		= nfs_rename,
	.permission	= nfs_permission,
	.getattr	= nfs_getattr,
	.setattr	= nfs_setattr,
887
#ifdef CONFIG_NFS_V3_ACL
888
	.listxattr	= nfs3_listxattr,
889 890 891 892 893 894
	.getxattr	= generic_getxattr,
	.setxattr	= generic_setxattr,
	.removexattr	= generic_removexattr,
	.get_acl	= nfs3_get_acl,
	.set_acl	= nfs3_set_acl,
#endif
895 896 897 898 899 900
};

static const struct inode_operations nfs3_file_inode_operations = {
	.permission	= nfs_permission,
	.getattr	= nfs_getattr,
	.setattr	= nfs_setattr,
901
#ifdef CONFIG_NFS_V3_ACL
902
	.listxattr	= nfs3_listxattr,
903 904 905 906 907 908
	.getxattr	= generic_getxattr,
	.setxattr	= generic_setxattr,
	.removexattr	= generic_removexattr,
	.get_acl	= nfs3_get_acl,
	.set_acl	= nfs3_set_acl,
#endif
909 910
};

D
David Howells 已提交
911
const struct nfs_rpc_ops nfs_v3_clientops = {
L
Linus Torvalds 已提交
912 913
	.version	= 3,			/* protocol version */
	.dentry_ops	= &nfs_dentry_operations,
914 915
	.dir_inode_ops	= &nfs3_dir_inode_operations,
	.file_inode_ops	= &nfs3_file_inode_operations,
916
	.file_ops	= &nfs_file_operations,
L
Linus Torvalds 已提交
917
	.getroot	= nfs3_proc_get_root,
B
Bryan Schumaker 已提交
918
	.submount	= nfs_submount,
B
Bryan Schumaker 已提交
919
	.try_mount	= nfs_try_mount,
L
Linus Torvalds 已提交
920 921 922 923 924 925 926 927
	.getattr	= nfs3_proc_getattr,
	.setattr	= nfs3_proc_setattr,
	.lookup		= nfs3_proc_lookup,
	.access		= nfs3_proc_access,
	.readlink	= nfs3_proc_readlink,
	.create		= nfs3_proc_create,
	.remove		= nfs3_proc_remove,
	.unlink_setup	= nfs3_proc_unlink_setup,
928
	.unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
L
Linus Torvalds 已提交
929
	.unlink_done	= nfs3_proc_unlink_done,
930
	.rename_setup	= nfs3_proc_rename_setup,
931
	.rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
932
	.rename_done	= nfs3_proc_rename_done,
L
Linus Torvalds 已提交
933 934 935 936 937 938 939 940 941 942
	.link		= nfs3_proc_link,
	.symlink	= nfs3_proc_symlink,
	.mkdir		= nfs3_proc_mkdir,
	.rmdir		= nfs3_proc_rmdir,
	.readdir	= nfs3_proc_readdir,
	.mknod		= nfs3_proc_mknod,
	.statfs		= nfs3_proc_statfs,
	.fsinfo		= nfs3_proc_fsinfo,
	.pathconf	= nfs3_proc_pathconf,
	.decode_dirent	= nfs3_decode_dirent,
943
	.pgio_rpc_prepare = nfs3_proc_pgio_rpc_prepare,
L
Linus Torvalds 已提交
944
	.read_setup	= nfs3_proc_read_setup,
T
Trond Myklebust 已提交
945
	.read_done	= nfs3_read_done,
L
Linus Torvalds 已提交
946
	.write_setup	= nfs3_proc_write_setup,
947
	.write_done	= nfs3_write_done,
L
Linus Torvalds 已提交
948
	.commit_setup	= nfs3_proc_commit_setup,
949
	.commit_rpc_prepare = nfs3_proc_commit_rpc_prepare,
950
	.commit_done	= nfs3_commit_done,
L
Linus Torvalds 已提交
951
	.lock		= nfs3_proc_lock,
952
	.clear_acl_cache = forget_all_cached_acls,
T
Trond Myklebust 已提交
953
	.close_context	= nfs_close_context,
954
	.have_delegation = nfs3_have_delegation,
955
	.return_delegation = nfs3_return_delegation,
956
	.alloc_client	= nfs_alloc_client,
957
	.init_client	= nfs_init_client,
958
	.free_client	= nfs_free_client,
959 960
	.create_server	= nfs3_create_server,
	.clone_server	= nfs3_clone_server,
L
Linus Torvalds 已提交
961
};