xref: /OK3568_Linux_fs/kernel/fs/nfs/mount_clnt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * In-kernel MOUNT protocol client
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/types.h>
9*4882a593Smuzhiyun #include <linux/socket.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/uio.h>
13*4882a593Smuzhiyun #include <linux/net.h>
14*4882a593Smuzhiyun #include <linux/in.h>
15*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
16*4882a593Smuzhiyun #include <linux/sunrpc/sched.h>
17*4882a593Smuzhiyun #include <linux/nfs_fs.h>
18*4882a593Smuzhiyun #include "internal.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define NFSDBG_FACILITY	NFSDBG_MOUNT
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun #define MNTPATHLEN		(1024)
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * XDR data type sizes
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun #define encode_dirpath_sz	(1 + XDR_QUADLEN(MNTPATHLEN))
31*4882a593Smuzhiyun #define MNT_status_sz		(1)
32*4882a593Smuzhiyun #define MNT_fhandle_sz		XDR_QUADLEN(NFS2_FHSIZE)
33*4882a593Smuzhiyun #define MNT_fhandlev3_sz	XDR_QUADLEN(NFS3_FHSIZE)
34*4882a593Smuzhiyun #define MNT_authflav3_sz	(1 + NFS_MAX_SECFLAVORS)
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun  * XDR argument and result sizes
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun #define MNT_enc_dirpath_sz	encode_dirpath_sz
40*4882a593Smuzhiyun #define MNT_dec_mountres_sz	(MNT_status_sz + MNT_fhandle_sz)
41*4882a593Smuzhiyun #define MNT_dec_mountres3_sz	(MNT_status_sz + MNT_fhandlev3_sz + \
42*4882a593Smuzhiyun 				 MNT_authflav3_sz)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun  * Defined by RFC 1094, section A.5
46*4882a593Smuzhiyun  */
47*4882a593Smuzhiyun enum {
48*4882a593Smuzhiyun 	MOUNTPROC_NULL		= 0,
49*4882a593Smuzhiyun 	MOUNTPROC_MNT		= 1,
50*4882a593Smuzhiyun 	MOUNTPROC_DUMP		= 2,
51*4882a593Smuzhiyun 	MOUNTPROC_UMNT		= 3,
52*4882a593Smuzhiyun 	MOUNTPROC_UMNTALL	= 4,
53*4882a593Smuzhiyun 	MOUNTPROC_EXPORT	= 5,
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /*
57*4882a593Smuzhiyun  * Defined by RFC 1813, section 5.2
58*4882a593Smuzhiyun  */
59*4882a593Smuzhiyun enum {
60*4882a593Smuzhiyun 	MOUNTPROC3_NULL		= 0,
61*4882a593Smuzhiyun 	MOUNTPROC3_MNT		= 1,
62*4882a593Smuzhiyun 	MOUNTPROC3_DUMP		= 2,
63*4882a593Smuzhiyun 	MOUNTPROC3_UMNT		= 3,
64*4882a593Smuzhiyun 	MOUNTPROC3_UMNTALL	= 4,
65*4882a593Smuzhiyun 	MOUNTPROC3_EXPORT	= 5,
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun static const struct rpc_program mnt_program;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun  * Defined by OpenGroup XNFS Version 3W, chapter 8
72*4882a593Smuzhiyun  */
73*4882a593Smuzhiyun enum mountstat {
74*4882a593Smuzhiyun 	MNT_OK			= 0,
75*4882a593Smuzhiyun 	MNT_EPERM		= 1,
76*4882a593Smuzhiyun 	MNT_ENOENT		= 2,
77*4882a593Smuzhiyun 	MNT_EACCES		= 13,
78*4882a593Smuzhiyun 	MNT_EINVAL		= 22,
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static struct {
82*4882a593Smuzhiyun 	u32 status;
83*4882a593Smuzhiyun 	int errno;
84*4882a593Smuzhiyun } mnt_errtbl[] = {
85*4882a593Smuzhiyun 	{ .status = MNT_OK,			.errno = 0,		},
86*4882a593Smuzhiyun 	{ .status = MNT_EPERM,			.errno = -EPERM,	},
87*4882a593Smuzhiyun 	{ .status = MNT_ENOENT,			.errno = -ENOENT,	},
88*4882a593Smuzhiyun 	{ .status = MNT_EACCES,			.errno = -EACCES,	},
89*4882a593Smuzhiyun 	{ .status = MNT_EINVAL,			.errno = -EINVAL,	},
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun /*
93*4882a593Smuzhiyun  * Defined by RFC 1813, section 5.1.5
94*4882a593Smuzhiyun  */
95*4882a593Smuzhiyun enum mountstat3 {
96*4882a593Smuzhiyun 	MNT3_OK			= 0,		/* no error */
97*4882a593Smuzhiyun 	MNT3ERR_PERM		= 1,		/* Not owner */
98*4882a593Smuzhiyun 	MNT3ERR_NOENT		= 2,		/* No such file or directory */
99*4882a593Smuzhiyun 	MNT3ERR_IO		= 5,		/* I/O error */
100*4882a593Smuzhiyun 	MNT3ERR_ACCES		= 13,		/* Permission denied */
101*4882a593Smuzhiyun 	MNT3ERR_NOTDIR		= 20,		/* Not a directory */
102*4882a593Smuzhiyun 	MNT3ERR_INVAL		= 22,		/* Invalid argument */
103*4882a593Smuzhiyun 	MNT3ERR_NAMETOOLONG	= 63,		/* Filename too long */
104*4882a593Smuzhiyun 	MNT3ERR_NOTSUPP		= 10004,	/* Operation not supported */
105*4882a593Smuzhiyun 	MNT3ERR_SERVERFAULT	= 10006,	/* A failure on the server */
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun static struct {
109*4882a593Smuzhiyun 	u32 status;
110*4882a593Smuzhiyun 	int errno;
111*4882a593Smuzhiyun } mnt3_errtbl[] = {
112*4882a593Smuzhiyun 	{ .status = MNT3_OK,			.errno = 0,		},
113*4882a593Smuzhiyun 	{ .status = MNT3ERR_PERM,		.errno = -EPERM,	},
114*4882a593Smuzhiyun 	{ .status = MNT3ERR_NOENT,		.errno = -ENOENT,	},
115*4882a593Smuzhiyun 	{ .status = MNT3ERR_IO,			.errno = -EIO,		},
116*4882a593Smuzhiyun 	{ .status = MNT3ERR_ACCES,		.errno = -EACCES,	},
117*4882a593Smuzhiyun 	{ .status = MNT3ERR_NOTDIR,		.errno = -ENOTDIR,	},
118*4882a593Smuzhiyun 	{ .status = MNT3ERR_INVAL,		.errno = -EINVAL,	},
119*4882a593Smuzhiyun 	{ .status = MNT3ERR_NAMETOOLONG,	.errno = -ENAMETOOLONG,	},
120*4882a593Smuzhiyun 	{ .status = MNT3ERR_NOTSUPP,		.errno = -ENOTSUPP,	},
121*4882a593Smuzhiyun 	{ .status = MNT3ERR_SERVERFAULT,	.errno = -EREMOTEIO,	},
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun struct mountres {
125*4882a593Smuzhiyun 	int errno;
126*4882a593Smuzhiyun 	struct nfs_fh *fh;
127*4882a593Smuzhiyun 	unsigned int *auth_count;
128*4882a593Smuzhiyun 	rpc_authflavor_t *auth_flavors;
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun struct mnt_fhstatus {
132*4882a593Smuzhiyun 	u32 status;
133*4882a593Smuzhiyun 	struct nfs_fh *fh;
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /**
137*4882a593Smuzhiyun  * nfs_mount - Obtain an NFS file handle for the given host and path
138*4882a593Smuzhiyun  * @info: pointer to mount request arguments
139*4882a593Smuzhiyun  *
140*4882a593Smuzhiyun  * Uses default timeout parameters specified by underlying transport. On
141*4882a593Smuzhiyun  * successful return, the auth_flavs list and auth_flav_len will be populated
142*4882a593Smuzhiyun  * with the list from the server or a faked-up list if the server didn't
143*4882a593Smuzhiyun  * provide one.
144*4882a593Smuzhiyun  */
nfs_mount(struct nfs_mount_request * info)145*4882a593Smuzhiyun int nfs_mount(struct nfs_mount_request *info)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct mountres	result = {
148*4882a593Smuzhiyun 		.fh		= info->fh,
149*4882a593Smuzhiyun 		.auth_count	= info->auth_flav_len,
150*4882a593Smuzhiyun 		.auth_flavors	= info->auth_flavs,
151*4882a593Smuzhiyun 	};
152*4882a593Smuzhiyun 	struct rpc_message msg	= {
153*4882a593Smuzhiyun 		.rpc_argp	= info->dirpath,
154*4882a593Smuzhiyun 		.rpc_resp	= &result,
155*4882a593Smuzhiyun 	};
156*4882a593Smuzhiyun 	struct rpc_create_args args = {
157*4882a593Smuzhiyun 		.net		= info->net,
158*4882a593Smuzhiyun 		.protocol	= info->protocol,
159*4882a593Smuzhiyun 		.address	= info->sap,
160*4882a593Smuzhiyun 		.addrsize	= info->salen,
161*4882a593Smuzhiyun 		.servername	= info->hostname,
162*4882a593Smuzhiyun 		.program	= &mnt_program,
163*4882a593Smuzhiyun 		.version	= info->version,
164*4882a593Smuzhiyun 		.authflavor	= RPC_AUTH_UNIX,
165*4882a593Smuzhiyun 		.cred		= current_cred(),
166*4882a593Smuzhiyun 	};
167*4882a593Smuzhiyun 	struct rpc_clnt		*mnt_clnt;
168*4882a593Smuzhiyun 	int			status;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	dprintk("NFS: sending MNT request for %s:%s\n",
171*4882a593Smuzhiyun 		(info->hostname ? info->hostname : "server"),
172*4882a593Smuzhiyun 			info->dirpath);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (strlen(info->dirpath) > MNTPATHLEN)
175*4882a593Smuzhiyun 		return -ENAMETOOLONG;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (info->noresvport)
178*4882a593Smuzhiyun 		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	mnt_clnt = rpc_create(&args);
181*4882a593Smuzhiyun 	if (IS_ERR(mnt_clnt))
182*4882a593Smuzhiyun 		goto out_clnt_err;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (info->version == NFS_MNT3_VERSION)
185*4882a593Smuzhiyun 		msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
186*4882a593Smuzhiyun 	else
187*4882a593Smuzhiyun 		msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
190*4882a593Smuzhiyun 	rpc_shutdown_client(mnt_clnt);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	if (status < 0)
193*4882a593Smuzhiyun 		goto out_call_err;
194*4882a593Smuzhiyun 	if (result.errno != 0)
195*4882a593Smuzhiyun 		goto out_mnt_err;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	dprintk("NFS: MNT request succeeded\n");
198*4882a593Smuzhiyun 	status = 0;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	/*
201*4882a593Smuzhiyun 	 * If the server didn't provide a flavor list, allow the
202*4882a593Smuzhiyun 	 * client to try any flavor.
203*4882a593Smuzhiyun 	 */
204*4882a593Smuzhiyun 	if (info->version != NFS_MNT3_VERSION || *info->auth_flav_len == 0) {
205*4882a593Smuzhiyun 		dprintk("NFS: Faking up auth_flavs list\n");
206*4882a593Smuzhiyun 		info->auth_flavs[0] = RPC_AUTH_NULL;
207*4882a593Smuzhiyun 		*info->auth_flav_len = 1;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun out:
210*4882a593Smuzhiyun 	return status;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun out_clnt_err:
213*4882a593Smuzhiyun 	status = PTR_ERR(mnt_clnt);
214*4882a593Smuzhiyun 	dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
215*4882a593Smuzhiyun 	goto out;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun out_call_err:
218*4882a593Smuzhiyun 	dprintk("NFS: MNT request failed, status=%d\n", status);
219*4882a593Smuzhiyun 	goto out;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun out_mnt_err:
222*4882a593Smuzhiyun 	dprintk("NFS: MNT server returned result %d\n", result.errno);
223*4882a593Smuzhiyun 	status = result.errno;
224*4882a593Smuzhiyun 	goto out;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun /**
228*4882a593Smuzhiyun  * nfs_umount - Notify a server that we have unmounted this export
229*4882a593Smuzhiyun  * @info: pointer to umount request arguments
230*4882a593Smuzhiyun  *
231*4882a593Smuzhiyun  * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
232*4882a593Smuzhiyun  * use UDP.
233*4882a593Smuzhiyun  */
nfs_umount(const struct nfs_mount_request * info)234*4882a593Smuzhiyun void nfs_umount(const struct nfs_mount_request *info)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	static const struct rpc_timeout nfs_umnt_timeout = {
237*4882a593Smuzhiyun 		.to_initval = 1 * HZ,
238*4882a593Smuzhiyun 		.to_maxval = 3 * HZ,
239*4882a593Smuzhiyun 		.to_retries = 2,
240*4882a593Smuzhiyun 	};
241*4882a593Smuzhiyun 	struct rpc_create_args args = {
242*4882a593Smuzhiyun 		.net		= info->net,
243*4882a593Smuzhiyun 		.protocol	= IPPROTO_UDP,
244*4882a593Smuzhiyun 		.address	= info->sap,
245*4882a593Smuzhiyun 		.addrsize	= info->salen,
246*4882a593Smuzhiyun 		.timeout	= &nfs_umnt_timeout,
247*4882a593Smuzhiyun 		.servername	= info->hostname,
248*4882a593Smuzhiyun 		.program	= &mnt_program,
249*4882a593Smuzhiyun 		.version	= info->version,
250*4882a593Smuzhiyun 		.authflavor	= RPC_AUTH_UNIX,
251*4882a593Smuzhiyun 		.flags		= RPC_CLNT_CREATE_NOPING,
252*4882a593Smuzhiyun 		.cred		= current_cred(),
253*4882a593Smuzhiyun 	};
254*4882a593Smuzhiyun 	struct rpc_message msg	= {
255*4882a593Smuzhiyun 		.rpc_argp	= info->dirpath,
256*4882a593Smuzhiyun 	};
257*4882a593Smuzhiyun 	struct rpc_clnt *clnt;
258*4882a593Smuzhiyun 	int status;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (strlen(info->dirpath) > MNTPATHLEN)
261*4882a593Smuzhiyun 		return;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (info->noresvport)
264*4882a593Smuzhiyun 		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	clnt = rpc_create(&args);
267*4882a593Smuzhiyun 	if (IS_ERR(clnt))
268*4882a593Smuzhiyun 		goto out_clnt_err;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	dprintk("NFS: sending UMNT request for %s:%s\n",
271*4882a593Smuzhiyun 		(info->hostname ? info->hostname : "server"), info->dirpath);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (info->version == NFS_MNT3_VERSION)
274*4882a593Smuzhiyun 		msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
275*4882a593Smuzhiyun 	else
276*4882a593Smuzhiyun 		msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	status = rpc_call_sync(clnt, &msg, 0);
279*4882a593Smuzhiyun 	rpc_shutdown_client(clnt);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (unlikely(status < 0))
282*4882a593Smuzhiyun 		goto out_call_err;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	return;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun out_clnt_err:
287*4882a593Smuzhiyun 	dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
288*4882a593Smuzhiyun 			PTR_ERR(clnt));
289*4882a593Smuzhiyun 	return;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun out_call_err:
292*4882a593Smuzhiyun 	dprintk("NFS: UMNT request failed, status=%d\n", status);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun  * XDR encode/decode functions for MOUNT
297*4882a593Smuzhiyun  */
298*4882a593Smuzhiyun 
encode_mntdirpath(struct xdr_stream * xdr,const char * pathname)299*4882a593Smuzhiyun static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	const u32 pathname_len = strlen(pathname);
302*4882a593Smuzhiyun 	__be32 *p;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, 4 + pathname_len);
305*4882a593Smuzhiyun 	xdr_encode_opaque(p, pathname, pathname_len);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
mnt_xdr_enc_dirpath(struct rpc_rqst * req,struct xdr_stream * xdr,const void * dirpath)308*4882a593Smuzhiyun static void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr,
309*4882a593Smuzhiyun 				const void *dirpath)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	encode_mntdirpath(xdr, dirpath);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun /*
315*4882a593Smuzhiyun  * RFC 1094: "A non-zero status indicates some sort of error.  In this
316*4882a593Smuzhiyun  * case, the status is a UNIX error number."  This can be problematic
317*4882a593Smuzhiyun  * if the server and client use different errno values for the same
318*4882a593Smuzhiyun  * error.
319*4882a593Smuzhiyun  *
320*4882a593Smuzhiyun  * However, the OpenGroup XNFS spec provides a simple mapping that is
321*4882a593Smuzhiyun  * independent of local errno values on the server and the client.
322*4882a593Smuzhiyun  */
decode_status(struct xdr_stream * xdr,struct mountres * res)323*4882a593Smuzhiyun static int decode_status(struct xdr_stream *xdr, struct mountres *res)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	unsigned int i;
326*4882a593Smuzhiyun 	u32 status;
327*4882a593Smuzhiyun 	__be32 *p;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
330*4882a593Smuzhiyun 	if (unlikely(p == NULL))
331*4882a593Smuzhiyun 		return -EIO;
332*4882a593Smuzhiyun 	status = be32_to_cpup(p);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
335*4882a593Smuzhiyun 		if (mnt_errtbl[i].status == status) {
336*4882a593Smuzhiyun 			res->errno = mnt_errtbl[i].errno;
337*4882a593Smuzhiyun 			return 0;
338*4882a593Smuzhiyun 		}
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	dprintk("NFS: unrecognized MNT status code: %u\n", status);
342*4882a593Smuzhiyun 	res->errno = -EACCES;
343*4882a593Smuzhiyun 	return 0;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
decode_fhandle(struct xdr_stream * xdr,struct mountres * res)346*4882a593Smuzhiyun static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	struct nfs_fh *fh = res->fh;
349*4882a593Smuzhiyun 	__be32 *p;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, NFS2_FHSIZE);
352*4882a593Smuzhiyun 	if (unlikely(p == NULL))
353*4882a593Smuzhiyun 		return -EIO;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	fh->size = NFS2_FHSIZE;
356*4882a593Smuzhiyun 	memcpy(fh->data, p, NFS2_FHSIZE);
357*4882a593Smuzhiyun 	return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
mnt_xdr_dec_mountres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)360*4882a593Smuzhiyun static int mnt_xdr_dec_mountres(struct rpc_rqst *req,
361*4882a593Smuzhiyun 				struct xdr_stream *xdr,
362*4882a593Smuzhiyun 				void *data)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	struct mountres *res = data;
365*4882a593Smuzhiyun 	int status;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	status = decode_status(xdr, res);
368*4882a593Smuzhiyun 	if (unlikely(status != 0 || res->errno != 0))
369*4882a593Smuzhiyun 		return status;
370*4882a593Smuzhiyun 	return decode_fhandle(xdr, res);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
decode_fhs_status(struct xdr_stream * xdr,struct mountres * res)373*4882a593Smuzhiyun static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	unsigned int i;
376*4882a593Smuzhiyun 	u32 status;
377*4882a593Smuzhiyun 	__be32 *p;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
380*4882a593Smuzhiyun 	if (unlikely(p == NULL))
381*4882a593Smuzhiyun 		return -EIO;
382*4882a593Smuzhiyun 	status = be32_to_cpup(p);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
385*4882a593Smuzhiyun 		if (mnt3_errtbl[i].status == status) {
386*4882a593Smuzhiyun 			res->errno = mnt3_errtbl[i].errno;
387*4882a593Smuzhiyun 			return 0;
388*4882a593Smuzhiyun 		}
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
392*4882a593Smuzhiyun 	res->errno = -EACCES;
393*4882a593Smuzhiyun 	return 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
decode_fhandle3(struct xdr_stream * xdr,struct mountres * res)396*4882a593Smuzhiyun static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct nfs_fh *fh = res->fh;
399*4882a593Smuzhiyun 	u32 size;
400*4882a593Smuzhiyun 	__be32 *p;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
403*4882a593Smuzhiyun 	if (unlikely(p == NULL))
404*4882a593Smuzhiyun 		return -EIO;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	size = be32_to_cpup(p);
407*4882a593Smuzhiyun 	if (size > NFS3_FHSIZE || size == 0)
408*4882a593Smuzhiyun 		return -EIO;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, size);
411*4882a593Smuzhiyun 	if (unlikely(p == NULL))
412*4882a593Smuzhiyun 		return -EIO;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	fh->size = size;
415*4882a593Smuzhiyun 	memcpy(fh->data, p, size);
416*4882a593Smuzhiyun 	return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
decode_auth_flavors(struct xdr_stream * xdr,struct mountres * res)419*4882a593Smuzhiyun static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	rpc_authflavor_t *flavors = res->auth_flavors;
422*4882a593Smuzhiyun 	unsigned int *count = res->auth_count;
423*4882a593Smuzhiyun 	u32 entries, i;
424*4882a593Smuzhiyun 	__be32 *p;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (*count == 0)
427*4882a593Smuzhiyun 		return 0;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
430*4882a593Smuzhiyun 	if (unlikely(p == NULL))
431*4882a593Smuzhiyun 		return -EIO;
432*4882a593Smuzhiyun 	entries = be32_to_cpup(p);
433*4882a593Smuzhiyun 	dprintk("NFS: received %u auth flavors\n", entries);
434*4882a593Smuzhiyun 	if (entries > NFS_MAX_SECFLAVORS)
435*4882a593Smuzhiyun 		entries = NFS_MAX_SECFLAVORS;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4 * entries);
438*4882a593Smuzhiyun 	if (unlikely(p == NULL))
439*4882a593Smuzhiyun 		return -EIO;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	if (entries > *count)
442*4882a593Smuzhiyun 		entries = *count;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	for (i = 0; i < entries; i++) {
445*4882a593Smuzhiyun 		flavors[i] = be32_to_cpup(p++);
446*4882a593Smuzhiyun 		dprintk("NFS:   auth flavor[%u]: %d\n", i, flavors[i]);
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 	*count = i;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	return 0;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
mnt_xdr_dec_mountres3(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)453*4882a593Smuzhiyun static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
454*4882a593Smuzhiyun 				 struct xdr_stream *xdr,
455*4882a593Smuzhiyun 				 void *data)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	struct mountres *res = data;
458*4882a593Smuzhiyun 	int status;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	status = decode_fhs_status(xdr, res);
461*4882a593Smuzhiyun 	if (unlikely(status != 0 || res->errno != 0))
462*4882a593Smuzhiyun 		return status;
463*4882a593Smuzhiyun 	status = decode_fhandle3(xdr, res);
464*4882a593Smuzhiyun 	if (unlikely(status != 0)) {
465*4882a593Smuzhiyun 		res->errno = -EBADHANDLE;
466*4882a593Smuzhiyun 		return 0;
467*4882a593Smuzhiyun 	}
468*4882a593Smuzhiyun 	return decode_auth_flavors(xdr, res);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static const struct rpc_procinfo mnt_procedures[] = {
472*4882a593Smuzhiyun 	[MOUNTPROC_MNT] = {
473*4882a593Smuzhiyun 		.p_proc		= MOUNTPROC_MNT,
474*4882a593Smuzhiyun 		.p_encode	= mnt_xdr_enc_dirpath,
475*4882a593Smuzhiyun 		.p_decode	= mnt_xdr_dec_mountres,
476*4882a593Smuzhiyun 		.p_arglen	= MNT_enc_dirpath_sz,
477*4882a593Smuzhiyun 		.p_replen	= MNT_dec_mountres_sz,
478*4882a593Smuzhiyun 		.p_statidx	= MOUNTPROC_MNT,
479*4882a593Smuzhiyun 		.p_name		= "MOUNT",
480*4882a593Smuzhiyun 	},
481*4882a593Smuzhiyun 	[MOUNTPROC_UMNT] = {
482*4882a593Smuzhiyun 		.p_proc		= MOUNTPROC_UMNT,
483*4882a593Smuzhiyun 		.p_encode	= mnt_xdr_enc_dirpath,
484*4882a593Smuzhiyun 		.p_arglen	= MNT_enc_dirpath_sz,
485*4882a593Smuzhiyun 		.p_statidx	= MOUNTPROC_UMNT,
486*4882a593Smuzhiyun 		.p_name		= "UMOUNT",
487*4882a593Smuzhiyun 	},
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun static const struct rpc_procinfo mnt3_procedures[] = {
491*4882a593Smuzhiyun 	[MOUNTPROC3_MNT] = {
492*4882a593Smuzhiyun 		.p_proc		= MOUNTPROC3_MNT,
493*4882a593Smuzhiyun 		.p_encode	= mnt_xdr_enc_dirpath,
494*4882a593Smuzhiyun 		.p_decode	= mnt_xdr_dec_mountres3,
495*4882a593Smuzhiyun 		.p_arglen	= MNT_enc_dirpath_sz,
496*4882a593Smuzhiyun 		.p_replen	= MNT_dec_mountres3_sz,
497*4882a593Smuzhiyun 		.p_statidx	= MOUNTPROC3_MNT,
498*4882a593Smuzhiyun 		.p_name		= "MOUNT",
499*4882a593Smuzhiyun 	},
500*4882a593Smuzhiyun 	[MOUNTPROC3_UMNT] = {
501*4882a593Smuzhiyun 		.p_proc		= MOUNTPROC3_UMNT,
502*4882a593Smuzhiyun 		.p_encode	= mnt_xdr_enc_dirpath,
503*4882a593Smuzhiyun 		.p_arglen	= MNT_enc_dirpath_sz,
504*4882a593Smuzhiyun 		.p_statidx	= MOUNTPROC3_UMNT,
505*4882a593Smuzhiyun 		.p_name		= "UMOUNT",
506*4882a593Smuzhiyun 	},
507*4882a593Smuzhiyun };
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun static unsigned int mnt_counts[ARRAY_SIZE(mnt_procedures)];
510*4882a593Smuzhiyun static const struct rpc_version mnt_version1 = {
511*4882a593Smuzhiyun 	.number		= 1,
512*4882a593Smuzhiyun 	.nrprocs	= ARRAY_SIZE(mnt_procedures),
513*4882a593Smuzhiyun 	.procs		= mnt_procedures,
514*4882a593Smuzhiyun 	.counts		= mnt_counts,
515*4882a593Smuzhiyun };
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun static unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)];
518*4882a593Smuzhiyun static const struct rpc_version mnt_version3 = {
519*4882a593Smuzhiyun 	.number		= 3,
520*4882a593Smuzhiyun 	.nrprocs	= ARRAY_SIZE(mnt3_procedures),
521*4882a593Smuzhiyun 	.procs		= mnt3_procedures,
522*4882a593Smuzhiyun 	.counts		= mnt3_counts,
523*4882a593Smuzhiyun };
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun static const struct rpc_version *mnt_version[] = {
526*4882a593Smuzhiyun 	NULL,
527*4882a593Smuzhiyun 	&mnt_version1,
528*4882a593Smuzhiyun 	NULL,
529*4882a593Smuzhiyun 	&mnt_version3,
530*4882a593Smuzhiyun };
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun static struct rpc_stat mnt_stats;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun static const struct rpc_program mnt_program = {
535*4882a593Smuzhiyun 	.name		= "mount",
536*4882a593Smuzhiyun 	.number		= NFS_MNT_PROGRAM,
537*4882a593Smuzhiyun 	.nrvers		= ARRAY_SIZE(mnt_version),
538*4882a593Smuzhiyun 	.version	= mnt_version,
539*4882a593Smuzhiyun 	.stats		= &mnt_stats,
540*4882a593Smuzhiyun };
541