xref: /openbmc/linux/fs/nfs/nfs3proc.c (revision 02a913a7)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/fs/nfs/nfs3proc.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Client-side NFSv3 procedures stubs.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *  Copyright (C) 1997, Olaf Kirch
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/mm.h>
101da177e4SLinus Torvalds #include <linux/utsname.h>
111da177e4SLinus Torvalds #include <linux/errno.h>
121da177e4SLinus Torvalds #include <linux/string.h>
131da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
141da177e4SLinus Torvalds #include <linux/nfs.h>
151da177e4SLinus Torvalds #include <linux/nfs3.h>
161da177e4SLinus Torvalds #include <linux/nfs_fs.h>
171da177e4SLinus Torvalds #include <linux/nfs_page.h>
181da177e4SLinus Torvalds #include <linux/lockd/bind.h>
191da177e4SLinus Torvalds #include <linux/smp_lock.h>
20b7fa0554SAndreas Gruenbacher #include <linux/nfs_mount.h>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_PROC
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds extern struct rpc_procinfo nfs3_procedures[];
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds /* A wrapper to handle the EJUKEBOX error message */
271da177e4SLinus Torvalds static int
281da177e4SLinus Torvalds nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
291da177e4SLinus Torvalds {
301da177e4SLinus Torvalds 	sigset_t oldset;
311da177e4SLinus Torvalds 	int res;
321da177e4SLinus Torvalds 	rpc_clnt_sigmask(clnt, &oldset);
331da177e4SLinus Torvalds 	do {
341da177e4SLinus Torvalds 		res = rpc_call_sync(clnt, msg, flags);
351da177e4SLinus Torvalds 		if (res != -EJUKEBOX)
361da177e4SLinus Torvalds 			break;
37041e0e3bSNishanth Aravamudan 		schedule_timeout_interruptible(NFS_JUKEBOX_RETRY_TIME);
381da177e4SLinus Torvalds 		res = -ERESTARTSYS;
391da177e4SLinus Torvalds 	} while (!signalled());
401da177e4SLinus Torvalds 	rpc_clnt_sigunmask(clnt, &oldset);
411da177e4SLinus Torvalds 	return res;
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds static inline int
451da177e4SLinus Torvalds nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	struct rpc_message msg = {
48b7fa0554SAndreas Gruenbacher 		.rpc_proc	= &clnt->cl_procinfo[proc],
491da177e4SLinus Torvalds 		.rpc_argp	= argp,
501da177e4SLinus Torvalds 		.rpc_resp	= resp,
511da177e4SLinus Torvalds 	};
521da177e4SLinus Torvalds 	return nfs3_rpc_wrapper(clnt, &msg, flags);
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds #define rpc_call(clnt, proc, argp, resp, flags) \
561da177e4SLinus Torvalds 		nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags)
571da177e4SLinus Torvalds #define rpc_call_sync(clnt, msg, flags) \
581da177e4SLinus Torvalds 		nfs3_rpc_wrapper(clnt, msg, flags)
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds static int
611da177e4SLinus Torvalds nfs3_async_handle_jukebox(struct rpc_task *task)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	if (task->tk_status != -EJUKEBOX)
641da177e4SLinus Torvalds 		return 0;
651da177e4SLinus Torvalds 	task->tk_status = 0;
661da177e4SLinus Torvalds 	rpc_restart_call(task);
671da177e4SLinus Torvalds 	rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
681da177e4SLinus Torvalds 	return 1;
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /*
721da177e4SLinus Torvalds  * Bare-bones access to getattr: this is for nfs_read_super.
731da177e4SLinus Torvalds  */
741da177e4SLinus Torvalds static int
751da177e4SLinus Torvalds nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
761da177e4SLinus Torvalds 		   struct nfs_fsinfo *info)
771da177e4SLinus Torvalds {
781da177e4SLinus Torvalds 	int	status;
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 	dprintk("%s: call  fsinfo\n", __FUNCTION__);
811da177e4SLinus Torvalds 	info->fattr->valid = 0;
821da177e4SLinus Torvalds 	status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
831da177e4SLinus Torvalds 	dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status);
841da177e4SLinus Torvalds 	if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
851da177e4SLinus Torvalds 		status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
861da177e4SLinus Torvalds 		dprintk("%s: reply getattr: %d\n", __FUNCTION__, status);
871da177e4SLinus Torvalds 	}
881da177e4SLinus Torvalds 	return status;
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds /*
921da177e4SLinus Torvalds  * One function for each procedure in the NFS protocol.
931da177e4SLinus Torvalds  */
941da177e4SLinus Torvalds static int
951da177e4SLinus Torvalds nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
961da177e4SLinus Torvalds 		struct nfs_fattr *fattr)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	int	status;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	dprintk("NFS call  getattr\n");
1011da177e4SLinus Torvalds 	fattr->valid = 0;
1021da177e4SLinus Torvalds 	status = rpc_call(server->client, NFS3PROC_GETATTR,
1031da177e4SLinus Torvalds 			  fhandle, fattr, 0);
1041da177e4SLinus Torvalds 	dprintk("NFS reply getattr: %d\n", status);
1051da177e4SLinus Torvalds 	return status;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds static int
1091da177e4SLinus Torvalds nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
1101da177e4SLinus Torvalds 			struct iattr *sattr)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds 	struct inode *inode = dentry->d_inode;
1131da177e4SLinus Torvalds 	struct nfs3_sattrargs	arg = {
1141da177e4SLinus Torvalds 		.fh		= NFS_FH(inode),
1151da177e4SLinus Torvalds 		.sattr		= sattr,
1161da177e4SLinus Torvalds 	};
1171da177e4SLinus Torvalds 	int	status;
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	dprintk("NFS call  setattr\n");
1201da177e4SLinus Torvalds 	fattr->valid = 0;
1211da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0);
12265e4308dSTrond Myklebust 	if (status == 0)
12365e4308dSTrond Myklebust 		nfs_setattr_update_inode(inode, sattr);
1241da177e4SLinus Torvalds 	dprintk("NFS reply setattr: %d\n", status);
1251da177e4SLinus Torvalds 	return status;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds static int
1291da177e4SLinus Torvalds nfs3_proc_lookup(struct inode *dir, struct qstr *name,
1301da177e4SLinus Torvalds 		 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr;
1331da177e4SLinus Torvalds 	struct nfs3_diropargs	arg = {
1341da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
1351da177e4SLinus Torvalds 		.name		= name->name,
1361da177e4SLinus Torvalds 		.len		= name->len
1371da177e4SLinus Torvalds 	};
1381da177e4SLinus Torvalds 	struct nfs3_diropres	res = {
1391da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
1401da177e4SLinus Torvalds 		.fh		= fhandle,
1411da177e4SLinus Torvalds 		.fattr		= fattr
1421da177e4SLinus Torvalds 	};
1431da177e4SLinus Torvalds 	int			status;
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	dprintk("NFS call  lookup %s\n", name->name);
1461da177e4SLinus Torvalds 	dir_attr.valid = 0;
1471da177e4SLinus Torvalds 	fattr->valid = 0;
1481da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0);
1491da177e4SLinus Torvalds 	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
1501da177e4SLinus Torvalds 		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR,
1511da177e4SLinus Torvalds 			 fhandle, fattr, 0);
1521da177e4SLinus Torvalds 	dprintk("NFS reply lookup: %d\n", status);
1531da177e4SLinus Torvalds 	if (status >= 0)
1541da177e4SLinus Torvalds 		status = nfs_refresh_inode(dir, &dir_attr);
1551da177e4SLinus Torvalds 	return status;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	struct nfs_fattr	fattr;
1611da177e4SLinus Torvalds 	struct nfs3_accessargs	arg = {
1621da177e4SLinus Torvalds 		.fh		= NFS_FH(inode),
1631da177e4SLinus Torvalds 	};
1641da177e4SLinus Torvalds 	struct nfs3_accessres	res = {
1651da177e4SLinus Torvalds 		.fattr		= &fattr,
1661da177e4SLinus Torvalds 	};
1671da177e4SLinus Torvalds 	struct rpc_message msg = {
1681da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_ACCESS],
1691da177e4SLinus Torvalds 		.rpc_argp	= &arg,
1701da177e4SLinus Torvalds 		.rpc_resp	= &res,
1711da177e4SLinus Torvalds 		.rpc_cred	= entry->cred
1721da177e4SLinus Torvalds 	};
1731da177e4SLinus Torvalds 	int mode = entry->mask;
1741da177e4SLinus Torvalds 	int status;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	dprintk("NFS call  access\n");
1771da177e4SLinus Torvalds 	fattr.valid = 0;
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	if (mode & MAY_READ)
1801da177e4SLinus Torvalds 		arg.access |= NFS3_ACCESS_READ;
1811da177e4SLinus Torvalds 	if (S_ISDIR(inode->i_mode)) {
1821da177e4SLinus Torvalds 		if (mode & MAY_WRITE)
1831da177e4SLinus Torvalds 			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
1841da177e4SLinus Torvalds 		if (mode & MAY_EXEC)
1851da177e4SLinus Torvalds 			arg.access |= NFS3_ACCESS_LOOKUP;
1861da177e4SLinus Torvalds 	} else {
1871da177e4SLinus Torvalds 		if (mode & MAY_WRITE)
1881da177e4SLinus Torvalds 			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND;
1891da177e4SLinus Torvalds 		if (mode & MAY_EXEC)
1901da177e4SLinus Torvalds 			arg.access |= NFS3_ACCESS_EXECUTE;
1911da177e4SLinus Torvalds 	}
1921da177e4SLinus Torvalds 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
1931da177e4SLinus Torvalds 	nfs_refresh_inode(inode, &fattr);
1941da177e4SLinus Torvalds 	if (status == 0) {
1951da177e4SLinus Torvalds 		entry->mask = 0;
1961da177e4SLinus Torvalds 		if (res.access & NFS3_ACCESS_READ)
1971da177e4SLinus Torvalds 			entry->mask |= MAY_READ;
1981da177e4SLinus Torvalds 		if (res.access & (NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE))
1991da177e4SLinus Torvalds 			entry->mask |= MAY_WRITE;
2001da177e4SLinus Torvalds 		if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE))
2011da177e4SLinus Torvalds 			entry->mask |= MAY_EXEC;
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 	dprintk("NFS reply access: %d\n", status);
2041da177e4SLinus Torvalds 	return status;
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds static int nfs3_proc_readlink(struct inode *inode, struct page *page,
2081da177e4SLinus Torvalds 		unsigned int pgbase, unsigned int pglen)
2091da177e4SLinus Torvalds {
2101da177e4SLinus Torvalds 	struct nfs_fattr	fattr;
2111da177e4SLinus Torvalds 	struct nfs3_readlinkargs args = {
2121da177e4SLinus Torvalds 		.fh		= NFS_FH(inode),
2131da177e4SLinus Torvalds 		.pgbase		= pgbase,
2141da177e4SLinus Torvalds 		.pglen		= pglen,
2151da177e4SLinus Torvalds 		.pages		= &page
2161da177e4SLinus Torvalds 	};
2171da177e4SLinus Torvalds 	int			status;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	dprintk("NFS call  readlink\n");
2201da177e4SLinus Torvalds 	fattr.valid = 0;
2211da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
2221da177e4SLinus Torvalds 			  &args, &fattr, 0);
2231da177e4SLinus Torvalds 	nfs_refresh_inode(inode, &fattr);
2241da177e4SLinus Torvalds 	dprintk("NFS reply readlink: %d\n", status);
2251da177e4SLinus Torvalds 	return status;
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds static int nfs3_proc_read(struct nfs_read_data *rdata)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	int			flags = rdata->flags;
2311da177e4SLinus Torvalds 	struct inode *		inode = rdata->inode;
2321da177e4SLinus Torvalds 	struct nfs_fattr *	fattr = rdata->res.fattr;
2331da177e4SLinus Torvalds 	struct rpc_message	msg = {
2341da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_READ],
2351da177e4SLinus Torvalds 		.rpc_argp	= &rdata->args,
2361da177e4SLinus Torvalds 		.rpc_resp	= &rdata->res,
2371da177e4SLinus Torvalds 		.rpc_cred	= rdata->cred,
2381da177e4SLinus Torvalds 	};
2391da177e4SLinus Torvalds 	int			status;
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds 	dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
2421da177e4SLinus Torvalds 			(long long) rdata->args.offset);
2431da177e4SLinus Torvalds 	fattr->valid = 0;
2441da177e4SLinus Torvalds 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
2451da177e4SLinus Torvalds 	if (status >= 0)
2461da177e4SLinus Torvalds 		nfs_refresh_inode(inode, fattr);
2471da177e4SLinus Torvalds 	dprintk("NFS reply read: %d\n", status);
2481da177e4SLinus Torvalds 	return status;
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds static int nfs3_proc_write(struct nfs_write_data *wdata)
2521da177e4SLinus Torvalds {
2531da177e4SLinus Torvalds 	int			rpcflags = wdata->flags;
2541da177e4SLinus Torvalds 	struct inode *		inode = wdata->inode;
2551da177e4SLinus Torvalds 	struct nfs_fattr *	fattr = wdata->res.fattr;
2561da177e4SLinus Torvalds 	struct rpc_message	msg = {
2571da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_WRITE],
2581da177e4SLinus Torvalds 		.rpc_argp	= &wdata->args,
2591da177e4SLinus Torvalds 		.rpc_resp	= &wdata->res,
2601da177e4SLinus Torvalds 		.rpc_cred	= wdata->cred,
2611da177e4SLinus Torvalds 	};
2621da177e4SLinus Torvalds 	int			status;
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 	dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
2651da177e4SLinus Torvalds 			(long long) wdata->args.offset);
2661da177e4SLinus Torvalds 	fattr->valid = 0;
2671da177e4SLinus Torvalds 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
2681da177e4SLinus Torvalds 	if (status >= 0)
2691da177e4SLinus Torvalds 		nfs_refresh_inode(inode, fattr);
2701da177e4SLinus Torvalds 	dprintk("NFS reply write: %d\n", status);
2711da177e4SLinus Torvalds 	return status < 0? status : wdata->res.count;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds static int nfs3_proc_commit(struct nfs_write_data *cdata)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	struct inode *		inode = cdata->inode;
2771da177e4SLinus Torvalds 	struct nfs_fattr *	fattr = cdata->res.fattr;
2781da177e4SLinus Torvalds 	struct rpc_message	msg = {
2791da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_COMMIT],
2801da177e4SLinus Torvalds 		.rpc_argp	= &cdata->args,
2811da177e4SLinus Torvalds 		.rpc_resp	= &cdata->res,
2821da177e4SLinus Torvalds 		.rpc_cred	= cdata->cred,
2831da177e4SLinus Torvalds 	};
2841da177e4SLinus Torvalds 	int			status;
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
2871da177e4SLinus Torvalds 			(long long) cdata->args.offset);
2881da177e4SLinus Torvalds 	fattr->valid = 0;
2891da177e4SLinus Torvalds 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2901da177e4SLinus Torvalds 	if (status >= 0)
2911da177e4SLinus Torvalds 		nfs_refresh_inode(inode, fattr);
2921da177e4SLinus Torvalds 	dprintk("NFS reply commit: %d\n", status);
2931da177e4SLinus Torvalds 	return status;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds /*
2971da177e4SLinus Torvalds  * Create a regular file.
2981da177e4SLinus Torvalds  * For now, we don't implement O_EXCL.
2991da177e4SLinus Torvalds  */
3001da177e4SLinus Torvalds static int
3011da177e4SLinus Torvalds nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
30202a913a7STrond Myklebust 		 int flags, struct nameidata *nd)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds 	struct nfs_fh		fhandle;
3051da177e4SLinus Torvalds 	struct nfs_fattr	fattr;
3061da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr;
3071da177e4SLinus Torvalds 	struct nfs3_createargs	arg = {
3081da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
3091da177e4SLinus Torvalds 		.name		= dentry->d_name.name,
3101da177e4SLinus Torvalds 		.len		= dentry->d_name.len,
3111da177e4SLinus Torvalds 		.sattr		= sattr,
3121da177e4SLinus Torvalds 	};
3131da177e4SLinus Torvalds 	struct nfs3_diropres	res = {
3141da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
3151da177e4SLinus Torvalds 		.fh		= &fhandle,
3161da177e4SLinus Torvalds 		.fattr		= &fattr
3171da177e4SLinus Torvalds 	};
318055ffbeaSAndreas Gruenbacher 	mode_t mode = sattr->ia_mode;
3191da177e4SLinus Torvalds 	int status;
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	dprintk("NFS call  create %s\n", dentry->d_name.name);
3221da177e4SLinus Torvalds 	arg.createmode = NFS3_CREATE_UNCHECKED;
3231da177e4SLinus Torvalds 	if (flags & O_EXCL) {
3241da177e4SLinus Torvalds 		arg.createmode  = NFS3_CREATE_EXCLUSIVE;
3251da177e4SLinus Torvalds 		arg.verifier[0] = jiffies;
3261da177e4SLinus Torvalds 		arg.verifier[1] = current->pid;
3271da177e4SLinus Torvalds 	}
3281da177e4SLinus Torvalds 
329055ffbeaSAndreas Gruenbacher 	sattr->ia_mode &= ~current->fs->umask;
330055ffbeaSAndreas Gruenbacher 
3311da177e4SLinus Torvalds again:
3321da177e4SLinus Torvalds 	dir_attr.valid = 0;
3331da177e4SLinus Torvalds 	fattr.valid = 0;
3341da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0);
3351da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	/* If the server doesn't support the exclusive creation semantics,
3381da177e4SLinus Torvalds 	 * try again with simple 'guarded' mode. */
3391da177e4SLinus Torvalds 	if (status == NFSERR_NOTSUPP) {
3401da177e4SLinus Torvalds 		switch (arg.createmode) {
3411da177e4SLinus Torvalds 			case NFS3_CREATE_EXCLUSIVE:
3421da177e4SLinus Torvalds 				arg.createmode = NFS3_CREATE_GUARDED;
3431da177e4SLinus Torvalds 				break;
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 			case NFS3_CREATE_GUARDED:
3461da177e4SLinus Torvalds 				arg.createmode = NFS3_CREATE_UNCHECKED;
3471da177e4SLinus Torvalds 				break;
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 			case NFS3_CREATE_UNCHECKED:
3501da177e4SLinus Torvalds 				goto out;
3511da177e4SLinus Torvalds 		}
3521da177e4SLinus Torvalds 		goto again;
3531da177e4SLinus Torvalds 	}
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	if (status == 0)
3561da177e4SLinus Torvalds 		status = nfs_instantiate(dentry, &fhandle, &fattr);
3571da177e4SLinus Torvalds 	if (status != 0)
3581da177e4SLinus Torvalds 		goto out;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	/* When we created the file with exclusive semantics, make
3611da177e4SLinus Torvalds 	 * sure we set the attributes afterwards. */
3621da177e4SLinus Torvalds 	if (arg.createmode == NFS3_CREATE_EXCLUSIVE) {
3631da177e4SLinus Torvalds 		dprintk("NFS call  setattr (post-create)\n");
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 		if (!(sattr->ia_valid & ATTR_ATIME_SET))
3661da177e4SLinus Torvalds 			sattr->ia_valid |= ATTR_ATIME;
3671da177e4SLinus Torvalds 		if (!(sattr->ia_valid & ATTR_MTIME_SET))
3681da177e4SLinus Torvalds 			sattr->ia_valid |= ATTR_MTIME;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 		/* Note: we could use a guarded setattr here, but I'm
3711da177e4SLinus Torvalds 		 * not sure this buys us anything (and I'd have
3721da177e4SLinus Torvalds 		 * to revamp the NFSv3 XDR code) */
3731da177e4SLinus Torvalds 		status = nfs3_proc_setattr(dentry, &fattr, sattr);
37465e4308dSTrond Myklebust 		if (status == 0)
37565e4308dSTrond Myklebust 			nfs_setattr_update_inode(dentry->d_inode, sattr);
3761da177e4SLinus Torvalds 		nfs_refresh_inode(dentry->d_inode, &fattr);
3771da177e4SLinus Torvalds 		dprintk("NFS reply setattr (post-create): %d\n", status);
3781da177e4SLinus Torvalds 	}
379055ffbeaSAndreas Gruenbacher 	if (status != 0)
380055ffbeaSAndreas Gruenbacher 		goto out;
381055ffbeaSAndreas Gruenbacher 	status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
3821da177e4SLinus Torvalds out:
3831da177e4SLinus Torvalds 	dprintk("NFS reply create: %d\n", status);
3841da177e4SLinus Torvalds 	return status;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds static int
3881da177e4SLinus Torvalds nfs3_proc_remove(struct inode *dir, struct qstr *name)
3891da177e4SLinus Torvalds {
3901da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr;
3911da177e4SLinus Torvalds 	struct nfs3_diropargs	arg = {
3921da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
3931da177e4SLinus Torvalds 		.name		= name->name,
3941da177e4SLinus Torvalds 		.len		= name->len
3951da177e4SLinus Torvalds 	};
3961da177e4SLinus Torvalds 	struct rpc_message	msg = {
3971da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_REMOVE],
3981da177e4SLinus Torvalds 		.rpc_argp	= &arg,
3991da177e4SLinus Torvalds 		.rpc_resp	= &dir_attr,
4001da177e4SLinus Torvalds 	};
4011da177e4SLinus Torvalds 	int			status;
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 	dprintk("NFS call  remove %s\n", name->name);
4041da177e4SLinus Torvalds 	dir_attr.valid = 0;
4051da177e4SLinus Torvalds 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
4061da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
4071da177e4SLinus Torvalds 	dprintk("NFS reply remove: %d\n", status);
4081da177e4SLinus Torvalds 	return status;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds static int
4121da177e4SLinus Torvalds nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
4131da177e4SLinus Torvalds {
4141da177e4SLinus Torvalds 	struct unlinkxdr {
4151da177e4SLinus Torvalds 		struct nfs3_diropargs arg;
4161da177e4SLinus Torvalds 		struct nfs_fattr res;
4171da177e4SLinus Torvalds 	} *ptr;
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	ptr = (struct unlinkxdr *)kmalloc(sizeof(*ptr), GFP_KERNEL);
4201da177e4SLinus Torvalds 	if (!ptr)
4211da177e4SLinus Torvalds 		return -ENOMEM;
4221da177e4SLinus Torvalds 	ptr->arg.fh = NFS_FH(dir->d_inode);
4231da177e4SLinus Torvalds 	ptr->arg.name = name->name;
4241da177e4SLinus Torvalds 	ptr->arg.len = name->len;
4251da177e4SLinus Torvalds 	ptr->res.valid = 0;
4261da177e4SLinus Torvalds 	msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
4271da177e4SLinus Torvalds 	msg->rpc_argp = &ptr->arg;
4281da177e4SLinus Torvalds 	msg->rpc_resp = &ptr->res;
4291da177e4SLinus Torvalds 	return 0;
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds static int
4331da177e4SLinus Torvalds nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds 	struct rpc_message *msg = &task->tk_msg;
4361da177e4SLinus Torvalds 	struct nfs_fattr	*dir_attr;
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	if (nfs3_async_handle_jukebox(task))
4391da177e4SLinus Torvalds 		return 1;
4401da177e4SLinus Torvalds 	if (msg->rpc_argp) {
4411da177e4SLinus Torvalds 		dir_attr = (struct nfs_fattr*)msg->rpc_resp;
4421da177e4SLinus Torvalds 		nfs_refresh_inode(dir->d_inode, dir_attr);
4431da177e4SLinus Torvalds 		kfree(msg->rpc_argp);
4441da177e4SLinus Torvalds 	}
4451da177e4SLinus Torvalds 	return 0;
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds static int
4491da177e4SLinus Torvalds nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
4501da177e4SLinus Torvalds 		 struct inode *new_dir, struct qstr *new_name)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds 	struct nfs_fattr	old_dir_attr, new_dir_attr;
4531da177e4SLinus Torvalds 	struct nfs3_renameargs	arg = {
4541da177e4SLinus Torvalds 		.fromfh		= NFS_FH(old_dir),
4551da177e4SLinus Torvalds 		.fromname	= old_name->name,
4561da177e4SLinus Torvalds 		.fromlen	= old_name->len,
4571da177e4SLinus Torvalds 		.tofh		= NFS_FH(new_dir),
4581da177e4SLinus Torvalds 		.toname		= new_name->name,
4591da177e4SLinus Torvalds 		.tolen		= new_name->len
4601da177e4SLinus Torvalds 	};
4611da177e4SLinus Torvalds 	struct nfs3_renameres	res = {
4621da177e4SLinus Torvalds 		.fromattr	= &old_dir_attr,
4631da177e4SLinus Torvalds 		.toattr		= &new_dir_attr
4641da177e4SLinus Torvalds 	};
4651da177e4SLinus Torvalds 	int			status;
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds 	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
4681da177e4SLinus Torvalds 	old_dir_attr.valid = 0;
4691da177e4SLinus Torvalds 	new_dir_attr.valid = 0;
4701da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0);
4711da177e4SLinus Torvalds 	nfs_refresh_inode(old_dir, &old_dir_attr);
4721da177e4SLinus Torvalds 	nfs_refresh_inode(new_dir, &new_dir_attr);
4731da177e4SLinus Torvalds 	dprintk("NFS reply rename: %d\n", status);
4741da177e4SLinus Torvalds 	return status;
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds static int
4781da177e4SLinus Torvalds nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
4791da177e4SLinus Torvalds {
4801da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr, fattr;
4811da177e4SLinus Torvalds 	struct nfs3_linkargs	arg = {
4821da177e4SLinus Torvalds 		.fromfh		= NFS_FH(inode),
4831da177e4SLinus Torvalds 		.tofh		= NFS_FH(dir),
4841da177e4SLinus Torvalds 		.toname		= name->name,
4851da177e4SLinus Torvalds 		.tolen		= name->len
4861da177e4SLinus Torvalds 	};
4871da177e4SLinus Torvalds 	struct nfs3_linkres	res = {
4881da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
4891da177e4SLinus Torvalds 		.fattr		= &fattr
4901da177e4SLinus Torvalds 	};
4911da177e4SLinus Torvalds 	int			status;
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	dprintk("NFS call  link %s\n", name->name);
4941da177e4SLinus Torvalds 	dir_attr.valid = 0;
4951da177e4SLinus Torvalds 	fattr.valid = 0;
4961da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0);
4971da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
4981da177e4SLinus Torvalds 	nfs_refresh_inode(inode, &fattr);
4991da177e4SLinus Torvalds 	dprintk("NFS reply link: %d\n", status);
5001da177e4SLinus Torvalds 	return status;
5011da177e4SLinus Torvalds }
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds static int
5041da177e4SLinus Torvalds nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
5051da177e4SLinus Torvalds 		  struct iattr *sattr, struct nfs_fh *fhandle,
5061da177e4SLinus Torvalds 		  struct nfs_fattr *fattr)
5071da177e4SLinus Torvalds {
5081da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr;
5091da177e4SLinus Torvalds 	struct nfs3_symlinkargs	arg = {
5101da177e4SLinus Torvalds 		.fromfh		= NFS_FH(dir),
5111da177e4SLinus Torvalds 		.fromname	= name->name,
5121da177e4SLinus Torvalds 		.fromlen	= name->len,
5131da177e4SLinus Torvalds 		.topath		= path->name,
5141da177e4SLinus Torvalds 		.tolen		= path->len,
5151da177e4SLinus Torvalds 		.sattr		= sattr
5161da177e4SLinus Torvalds 	};
5171da177e4SLinus Torvalds 	struct nfs3_diropres	res = {
5181da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
5191da177e4SLinus Torvalds 		.fh		= fhandle,
5201da177e4SLinus Torvalds 		.fattr		= fattr
5211da177e4SLinus Torvalds 	};
5221da177e4SLinus Torvalds 	int			status;
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	if (path->len > NFS3_MAXPATHLEN)
5251da177e4SLinus Torvalds 		return -ENAMETOOLONG;
5261da177e4SLinus Torvalds 	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
5271da177e4SLinus Torvalds 	dir_attr.valid = 0;
5281da177e4SLinus Torvalds 	fattr->valid = 0;
5291da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0);
5301da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
5311da177e4SLinus Torvalds 	dprintk("NFS reply symlink: %d\n", status);
5321da177e4SLinus Torvalds 	return status;
5331da177e4SLinus Torvalds }
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds static int
5361da177e4SLinus Torvalds nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
5371da177e4SLinus Torvalds {
5381da177e4SLinus Torvalds 	struct nfs_fh fhandle;
5391da177e4SLinus Torvalds 	struct nfs_fattr fattr, dir_attr;
5401da177e4SLinus Torvalds 	struct nfs3_mkdirargs	arg = {
5411da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
5421da177e4SLinus Torvalds 		.name		= dentry->d_name.name,
5431da177e4SLinus Torvalds 		.len		= dentry->d_name.len,
5441da177e4SLinus Torvalds 		.sattr		= sattr
5451da177e4SLinus Torvalds 	};
5461da177e4SLinus Torvalds 	struct nfs3_diropres	res = {
5471da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
5481da177e4SLinus Torvalds 		.fh		= &fhandle,
5491da177e4SLinus Torvalds 		.fattr		= &fattr
5501da177e4SLinus Torvalds 	};
551055ffbeaSAndreas Gruenbacher 	int mode = sattr->ia_mode;
5521da177e4SLinus Torvalds 	int status;
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds 	dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
5551da177e4SLinus Torvalds 	dir_attr.valid = 0;
5561da177e4SLinus Torvalds 	fattr.valid = 0;
557055ffbeaSAndreas Gruenbacher 
558055ffbeaSAndreas Gruenbacher 	sattr->ia_mode &= ~current->fs->umask;
559055ffbeaSAndreas Gruenbacher 
5601da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
5611da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
562055ffbeaSAndreas Gruenbacher 	if (status != 0)
563055ffbeaSAndreas Gruenbacher 		goto out;
5641da177e4SLinus Torvalds 	status = nfs_instantiate(dentry, &fhandle, &fattr);
565055ffbeaSAndreas Gruenbacher 	if (status != 0)
566055ffbeaSAndreas Gruenbacher 		goto out;
567055ffbeaSAndreas Gruenbacher 	status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
568055ffbeaSAndreas Gruenbacher out:
5691da177e4SLinus Torvalds 	dprintk("NFS reply mkdir: %d\n", status);
5701da177e4SLinus Torvalds 	return status;
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds static int
5741da177e4SLinus Torvalds nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
5751da177e4SLinus Torvalds {
5761da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr;
5771da177e4SLinus Torvalds 	struct nfs3_diropargs	arg = {
5781da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
5791da177e4SLinus Torvalds 		.name		= name->name,
5801da177e4SLinus Torvalds 		.len		= name->len
5811da177e4SLinus Torvalds 	};
5821da177e4SLinus Torvalds 	int			status;
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	dprintk("NFS call  rmdir %s\n", name->name);
5851da177e4SLinus Torvalds 	dir_attr.valid = 0;
5861da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
5871da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
5881da177e4SLinus Torvalds 	dprintk("NFS reply rmdir: %d\n", status);
5891da177e4SLinus Torvalds 	return status;
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds /*
5931da177e4SLinus Torvalds  * The READDIR implementation is somewhat hackish - we pass the user buffer
5941da177e4SLinus Torvalds  * to the encode function, which installs it in the receive iovec.
5951da177e4SLinus Torvalds  * The decode function itself doesn't perform any decoding, it just makes
5961da177e4SLinus Torvalds  * sure the reply is syntactically correct.
5971da177e4SLinus Torvalds  *
5981da177e4SLinus Torvalds  * Also note that this implementation handles both plain readdir and
5991da177e4SLinus Torvalds  * readdirplus.
6001da177e4SLinus Torvalds  */
6011da177e4SLinus Torvalds static int
6021da177e4SLinus Torvalds nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
6031da177e4SLinus Torvalds 		  u64 cookie, struct page *page, unsigned int count, int plus)
6041da177e4SLinus Torvalds {
6051da177e4SLinus Torvalds 	struct inode		*dir = dentry->d_inode;
6061da177e4SLinus Torvalds 	struct nfs_fattr	dir_attr;
6071da177e4SLinus Torvalds 	u32			*verf = NFS_COOKIEVERF(dir);
6081da177e4SLinus Torvalds 	struct nfs3_readdirargs	arg = {
6091da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
6101da177e4SLinus Torvalds 		.cookie		= cookie,
6111da177e4SLinus Torvalds 		.verf		= {verf[0], verf[1]},
6121da177e4SLinus Torvalds 		.plus		= plus,
6131da177e4SLinus Torvalds 		.count		= count,
6141da177e4SLinus Torvalds 		.pages		= &page
6151da177e4SLinus Torvalds 	};
6161da177e4SLinus Torvalds 	struct nfs3_readdirres	res = {
6171da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
6181da177e4SLinus Torvalds 		.verf		= verf,
6191da177e4SLinus Torvalds 		.plus		= plus
6201da177e4SLinus Torvalds 	};
6211da177e4SLinus Torvalds 	struct rpc_message	msg = {
6221da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_READDIR],
6231da177e4SLinus Torvalds 		.rpc_argp	= &arg,
6241da177e4SLinus Torvalds 		.rpc_resp	= &res,
6251da177e4SLinus Torvalds 		.rpc_cred	= cred
6261da177e4SLinus Torvalds 	};
6271da177e4SLinus Torvalds 	int			status;
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	lock_kernel();
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	if (plus)
6321da177e4SLinus Torvalds 		msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS];
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds 	dprintk("NFS call  readdir%s %d\n",
6351da177e4SLinus Torvalds 			plus? "plus" : "", (unsigned int) cookie);
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	dir_attr.valid = 0;
6381da177e4SLinus Torvalds 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
6391da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
6401da177e4SLinus Torvalds 	dprintk("NFS reply readdir: %d\n", status);
6411da177e4SLinus Torvalds 	unlock_kernel();
6421da177e4SLinus Torvalds 	return status;
6431da177e4SLinus Torvalds }
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds static int
6461da177e4SLinus Torvalds nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
6471da177e4SLinus Torvalds 		dev_t rdev)
6481da177e4SLinus Torvalds {
6491da177e4SLinus Torvalds 	struct nfs_fh fh;
6501da177e4SLinus Torvalds 	struct nfs_fattr fattr, dir_attr;
6511da177e4SLinus Torvalds 	struct nfs3_mknodargs	arg = {
6521da177e4SLinus Torvalds 		.fh		= NFS_FH(dir),
6531da177e4SLinus Torvalds 		.name		= dentry->d_name.name,
6541da177e4SLinus Torvalds 		.len		= dentry->d_name.len,
6551da177e4SLinus Torvalds 		.sattr		= sattr,
6561da177e4SLinus Torvalds 		.rdev		= rdev
6571da177e4SLinus Torvalds 	};
6581da177e4SLinus Torvalds 	struct nfs3_diropres	res = {
6591da177e4SLinus Torvalds 		.dir_attr	= &dir_attr,
6601da177e4SLinus Torvalds 		.fh		= &fh,
6611da177e4SLinus Torvalds 		.fattr		= &fattr
6621da177e4SLinus Torvalds 	};
663055ffbeaSAndreas Gruenbacher 	mode_t mode = sattr->ia_mode;
6641da177e4SLinus Torvalds 	int status;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	switch (sattr->ia_mode & S_IFMT) {
6671da177e4SLinus Torvalds 	case S_IFBLK:	arg.type = NF3BLK;  break;
6681da177e4SLinus Torvalds 	case S_IFCHR:	arg.type = NF3CHR;  break;
6691da177e4SLinus Torvalds 	case S_IFIFO:	arg.type = NF3FIFO; break;
6701da177e4SLinus Torvalds 	case S_IFSOCK:	arg.type = NF3SOCK; break;
6711da177e4SLinus Torvalds 	default:	return -EINVAL;
6721da177e4SLinus Torvalds 	}
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	dprintk("NFS call  mknod %s %u:%u\n", dentry->d_name.name,
6751da177e4SLinus Torvalds 			MAJOR(rdev), MINOR(rdev));
676055ffbeaSAndreas Gruenbacher 
677055ffbeaSAndreas Gruenbacher 	sattr->ia_mode &= ~current->fs->umask;
678055ffbeaSAndreas Gruenbacher 
6791da177e4SLinus Torvalds 	dir_attr.valid = 0;
6801da177e4SLinus Torvalds 	fattr.valid = 0;
6811da177e4SLinus Torvalds 	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
6821da177e4SLinus Torvalds 	nfs_refresh_inode(dir, &dir_attr);
683055ffbeaSAndreas Gruenbacher 	if (status != 0)
684055ffbeaSAndreas Gruenbacher 		goto out;
6851da177e4SLinus Torvalds 	status = nfs_instantiate(dentry, &fh, &fattr);
686055ffbeaSAndreas Gruenbacher 	if (status != 0)
687055ffbeaSAndreas Gruenbacher 		goto out;
688055ffbeaSAndreas Gruenbacher 	status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
689055ffbeaSAndreas Gruenbacher out:
6901da177e4SLinus Torvalds 	dprintk("NFS reply mknod: %d\n", status);
6911da177e4SLinus Torvalds 	return status;
6921da177e4SLinus Torvalds }
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds static int
6951da177e4SLinus Torvalds nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
6961da177e4SLinus Torvalds 		 struct nfs_fsstat *stat)
6971da177e4SLinus Torvalds {
6981da177e4SLinus Torvalds 	int	status;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	dprintk("NFS call  fsstat\n");
7011da177e4SLinus Torvalds 	stat->fattr->valid = 0;
7021da177e4SLinus Torvalds 	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0);
7031da177e4SLinus Torvalds 	dprintk("NFS reply statfs: %d\n", status);
7041da177e4SLinus Torvalds 	return status;
7051da177e4SLinus Torvalds }
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds static int
7081da177e4SLinus Torvalds nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
7091da177e4SLinus Torvalds 		 struct nfs_fsinfo *info)
7101da177e4SLinus Torvalds {
7111da177e4SLinus Torvalds 	int	status;
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	dprintk("NFS call  fsinfo\n");
7141da177e4SLinus Torvalds 	info->fattr->valid = 0;
7151da177e4SLinus Torvalds 	status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
7161da177e4SLinus Torvalds 	dprintk("NFS reply fsinfo: %d\n", status);
7171da177e4SLinus Torvalds 	return status;
7181da177e4SLinus Torvalds }
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds static int
7211da177e4SLinus Torvalds nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
7221da177e4SLinus Torvalds 		   struct nfs_pathconf *info)
7231da177e4SLinus Torvalds {
7241da177e4SLinus Torvalds 	int	status;
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 	dprintk("NFS call  pathconf\n");
7271da177e4SLinus Torvalds 	info->fattr->valid = 0;
7281da177e4SLinus Torvalds 	status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0);
7291da177e4SLinus Torvalds 	dprintk("NFS reply pathconf: %d\n", status);
7301da177e4SLinus Torvalds 	return status;
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds static void
7361da177e4SLinus Torvalds nfs3_read_done(struct rpc_task *task)
7371da177e4SLinus Torvalds {
7381da177e4SLinus Torvalds 	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
7391da177e4SLinus Torvalds 
7401da177e4SLinus Torvalds 	if (nfs3_async_handle_jukebox(task))
7411da177e4SLinus Torvalds 		return;
7421da177e4SLinus Torvalds 	/* Call back common NFS readpage processing */
7431da177e4SLinus Torvalds 	if (task->tk_status >= 0)
7441da177e4SLinus Torvalds 		nfs_refresh_inode(data->inode, &data->fattr);
7451da177e4SLinus Torvalds 	nfs_readpage_result(task);
7461da177e4SLinus Torvalds }
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds static void
7491da177e4SLinus Torvalds nfs3_proc_read_setup(struct nfs_read_data *data)
7501da177e4SLinus Torvalds {
7511da177e4SLinus Torvalds 	struct rpc_task		*task = &data->task;
7521da177e4SLinus Torvalds 	struct inode		*inode = data->inode;
7531da177e4SLinus Torvalds 	int			flags;
7541da177e4SLinus Torvalds 	struct rpc_message	msg = {
7551da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_READ],
7561da177e4SLinus Torvalds 		.rpc_argp	= &data->args,
7571da177e4SLinus Torvalds 		.rpc_resp	= &data->res,
7581da177e4SLinus Torvalds 		.rpc_cred	= data->cred,
7591da177e4SLinus Torvalds 	};
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds 	/* N.B. Do we need to test? Never called for swapfile inode */
7621da177e4SLinus Torvalds 	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	/* Finalize the task. */
7651da177e4SLinus Torvalds 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags);
7661da177e4SLinus Torvalds 	rpc_call_setup(task, &msg, 0);
7671da177e4SLinus Torvalds }
7681da177e4SLinus Torvalds 
7691da177e4SLinus Torvalds static void
7701da177e4SLinus Torvalds nfs3_write_done(struct rpc_task *task)
7711da177e4SLinus Torvalds {
7721da177e4SLinus Torvalds 	struct nfs_write_data *data;
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds 	if (nfs3_async_handle_jukebox(task))
7751da177e4SLinus Torvalds 		return;
7761da177e4SLinus Torvalds 	data = (struct nfs_write_data *)task->tk_calldata;
7771da177e4SLinus Torvalds 	if (task->tk_status >= 0)
7781da177e4SLinus Torvalds 		nfs_refresh_inode(data->inode, data->res.fattr);
7791da177e4SLinus Torvalds 	nfs_writeback_done(task);
7801da177e4SLinus Torvalds }
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds static void
7831da177e4SLinus Torvalds nfs3_proc_write_setup(struct nfs_write_data *data, int how)
7841da177e4SLinus Torvalds {
7851da177e4SLinus Torvalds 	struct rpc_task		*task = &data->task;
7861da177e4SLinus Torvalds 	struct inode		*inode = data->inode;
7871da177e4SLinus Torvalds 	int			stable;
7881da177e4SLinus Torvalds 	int			flags;
7891da177e4SLinus Torvalds 	struct rpc_message	msg = {
7901da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_WRITE],
7911da177e4SLinus Torvalds 		.rpc_argp	= &data->args,
7921da177e4SLinus Torvalds 		.rpc_resp	= &data->res,
7931da177e4SLinus Torvalds 		.rpc_cred	= data->cred,
7941da177e4SLinus Torvalds 	};
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 	if (how & FLUSH_STABLE) {
7971da177e4SLinus Torvalds 		if (!NFS_I(inode)->ncommit)
7981da177e4SLinus Torvalds 			stable = NFS_FILE_SYNC;
7991da177e4SLinus Torvalds 		else
8001da177e4SLinus Torvalds 			stable = NFS_DATA_SYNC;
8011da177e4SLinus Torvalds 	} else
8021da177e4SLinus Torvalds 		stable = NFS_UNSTABLE;
8031da177e4SLinus Torvalds 	data->args.stable = stable;
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds 	/* Set the initial flags for the task.  */
8061da177e4SLinus Torvalds 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	/* Finalize the task. */
8091da177e4SLinus Torvalds 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags);
8101da177e4SLinus Torvalds 	rpc_call_setup(task, &msg, 0);
8111da177e4SLinus Torvalds }
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds static void
8141da177e4SLinus Torvalds nfs3_commit_done(struct rpc_task *task)
8151da177e4SLinus Torvalds {
8161da177e4SLinus Torvalds 	struct nfs_write_data *data;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 	if (nfs3_async_handle_jukebox(task))
8191da177e4SLinus Torvalds 		return;
8201da177e4SLinus Torvalds 	data = (struct nfs_write_data *)task->tk_calldata;
8211da177e4SLinus Torvalds 	if (task->tk_status >= 0)
8221da177e4SLinus Torvalds 		nfs_refresh_inode(data->inode, data->res.fattr);
8231da177e4SLinus Torvalds 	nfs_commit_done(task);
8241da177e4SLinus Torvalds }
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds static void
8271da177e4SLinus Torvalds nfs3_proc_commit_setup(struct nfs_write_data *data, int how)
8281da177e4SLinus Torvalds {
8291da177e4SLinus Torvalds 	struct rpc_task		*task = &data->task;
8301da177e4SLinus Torvalds 	struct inode		*inode = data->inode;
8311da177e4SLinus Torvalds 	int			flags;
8321da177e4SLinus Torvalds 	struct rpc_message	msg = {
8331da177e4SLinus Torvalds 		.rpc_proc	= &nfs3_procedures[NFS3PROC_COMMIT],
8341da177e4SLinus Torvalds 		.rpc_argp	= &data->args,
8351da177e4SLinus Torvalds 		.rpc_resp	= &data->res,
8361da177e4SLinus Torvalds 		.rpc_cred	= data->cred,
8371da177e4SLinus Torvalds 	};
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	/* Set the initial flags for the task.  */
8401da177e4SLinus Torvalds 	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	/* Finalize the task. */
8431da177e4SLinus Torvalds 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
8441da177e4SLinus Torvalds 	rpc_call_setup(task, &msg, 0);
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds static int
8481da177e4SLinus Torvalds nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
8491da177e4SLinus Torvalds {
8501da177e4SLinus Torvalds 	return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl);
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds struct nfs_rpc_ops	nfs_v3_clientops = {
8541da177e4SLinus Torvalds 	.version	= 3,			/* protocol version */
8551da177e4SLinus Torvalds 	.dentry_ops	= &nfs_dentry_operations,
856b7fa0554SAndreas Gruenbacher 	.dir_inode_ops	= &nfs3_dir_inode_operations,
857b7fa0554SAndreas Gruenbacher 	.file_inode_ops	= &nfs3_file_inode_operations,
8581da177e4SLinus Torvalds 	.getroot	= nfs3_proc_get_root,
8591da177e4SLinus Torvalds 	.getattr	= nfs3_proc_getattr,
8601da177e4SLinus Torvalds 	.setattr	= nfs3_proc_setattr,
8611da177e4SLinus Torvalds 	.lookup		= nfs3_proc_lookup,
8621da177e4SLinus Torvalds 	.access		= nfs3_proc_access,
8631da177e4SLinus Torvalds 	.readlink	= nfs3_proc_readlink,
8641da177e4SLinus Torvalds 	.read		= nfs3_proc_read,
8651da177e4SLinus Torvalds 	.write		= nfs3_proc_write,
8661da177e4SLinus Torvalds 	.commit		= nfs3_proc_commit,
8671da177e4SLinus Torvalds 	.create		= nfs3_proc_create,
8681da177e4SLinus Torvalds 	.remove		= nfs3_proc_remove,
8691da177e4SLinus Torvalds 	.unlink_setup	= nfs3_proc_unlink_setup,
8701da177e4SLinus Torvalds 	.unlink_done	= nfs3_proc_unlink_done,
8711da177e4SLinus Torvalds 	.rename		= nfs3_proc_rename,
8721da177e4SLinus Torvalds 	.link		= nfs3_proc_link,
8731da177e4SLinus Torvalds 	.symlink	= nfs3_proc_symlink,
8741da177e4SLinus Torvalds 	.mkdir		= nfs3_proc_mkdir,
8751da177e4SLinus Torvalds 	.rmdir		= nfs3_proc_rmdir,
8761da177e4SLinus Torvalds 	.readdir	= nfs3_proc_readdir,
8771da177e4SLinus Torvalds 	.mknod		= nfs3_proc_mknod,
8781da177e4SLinus Torvalds 	.statfs		= nfs3_proc_statfs,
8791da177e4SLinus Torvalds 	.fsinfo		= nfs3_proc_fsinfo,
8801da177e4SLinus Torvalds 	.pathconf	= nfs3_proc_pathconf,
8811da177e4SLinus Torvalds 	.decode_dirent	= nfs3_decode_dirent,
8821da177e4SLinus Torvalds 	.read_setup	= nfs3_proc_read_setup,
8831da177e4SLinus Torvalds 	.write_setup	= nfs3_proc_write_setup,
8841da177e4SLinus Torvalds 	.commit_setup	= nfs3_proc_commit_setup,
8851da177e4SLinus Torvalds 	.file_open	= nfs_open,
8861da177e4SLinus Torvalds 	.file_release	= nfs_release,
8871da177e4SLinus Torvalds 	.lock		= nfs3_proc_lock,
8885c6a9f7dSAndreas Gruenbacher 	.clear_acl_cache = nfs3_forget_cached_acls,
8891da177e4SLinus Torvalds };
890