xref: /openbmc/linux/fs/nfs/mount_clnt.c (revision 643d1f7f)
1 /*
2  * In-kernel MOUNT protocol client
3  *
4  * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
5  */
6 
7 #include <linux/types.h>
8 #include <linux/socket.h>
9 #include <linux/kernel.h>
10 #include <linux/errno.h>
11 #include <linux/uio.h>
12 #include <linux/net.h>
13 #include <linux/in.h>
14 #include <linux/sunrpc/clnt.h>
15 #include <linux/sunrpc/sched.h>
16 #include <linux/nfs_fs.h>
17 
18 #ifdef RPC_DEBUG
19 # define NFSDBG_FACILITY	NFSDBG_MOUNT
20 #endif
21 
22 static struct rpc_program	mnt_program;
23 
24 struct mnt_fhstatus {
25 	u32 status;
26 	struct nfs_fh *fh;
27 };
28 
29 /**
30  * nfs_mount - Obtain an NFS file handle for the given host and path
31  * @addr: pointer to server's address
32  * @len: size of server's address
33  * @hostname: name of server host, or NULL
34  * @path: pointer to string containing export path to mount
35  * @version: mount version to use for this request
36  * @protocol: transport protocol to use for thie request
37  * @fh: pointer to location to place returned file handle
38  *
39  * Uses default timeout parameters specified by underlying transport.
40  */
41 int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path,
42 	      int version, int protocol, struct nfs_fh *fh)
43 {
44 	struct mnt_fhstatus	result = {
45 		.fh		= fh
46 	};
47 	struct rpc_message msg	= {
48 		.rpc_argp	= path,
49 		.rpc_resp	= &result,
50 	};
51 	struct rpc_create_args args = {
52 		.protocol	= protocol,
53 		.address	= addr,
54 		.addrsize	= len,
55 		.servername	= hostname,
56 		.program	= &mnt_program,
57 		.version	= version,
58 		.authflavor	= RPC_AUTH_UNIX,
59 		.flags		= 0,
60 	};
61 	struct rpc_clnt		*mnt_clnt;
62 	int			status;
63 
64 	dprintk("NFS: sending MNT request for %s:%s\n",
65 		(hostname ? hostname : "server"), path);
66 
67 	mnt_clnt = rpc_create(&args);
68 	if (IS_ERR(mnt_clnt))
69 		goto out_clnt_err;
70 
71 	if (version == NFS_MNT3_VERSION)
72 		msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
73 	else
74 		msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
75 
76 	status = rpc_call_sync(mnt_clnt, &msg, 0);
77 	rpc_shutdown_client(mnt_clnt);
78 
79 	if (status < 0)
80 		goto out_call_err;
81 	if (result.status != 0)
82 		goto out_mnt_err;
83 
84 	dprintk("NFS: MNT request succeeded\n");
85 	status = 0;
86 
87 out:
88 	return status;
89 
90 out_clnt_err:
91 	status = PTR_ERR(mnt_clnt);
92 	dprintk("NFS: failed to create RPC client, status=%d\n", status);
93 	goto out;
94 
95 out_call_err:
96 	dprintk("NFS: failed to start MNT request, status=%d\n", status);
97 	goto out;
98 
99 out_mnt_err:
100 	dprintk("NFS: MNT server returned result %d\n", result.status);
101 	status = -EACCES;
102 	goto out;
103 }
104 
105 /*
106  * XDR encode/decode functions for MOUNT
107  */
108 static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p,
109 			      const char *path)
110 {
111 	p = xdr_encode_string(p, path);
112 
113 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
114 	return 0;
115 }
116 
117 static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p,
118 			       struct mnt_fhstatus *res)
119 {
120 	struct nfs_fh *fh = res->fh;
121 
122 	if ((res->status = ntohl(*p++)) == 0) {
123 		fh->size = NFS2_FHSIZE;
124 		memcpy(fh->data, p, NFS2_FHSIZE);
125 	}
126 	return 0;
127 }
128 
129 static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p,
130 				struct mnt_fhstatus *res)
131 {
132 	struct nfs_fh *fh = res->fh;
133 
134 	if ((res->status = ntohl(*p++)) == 0) {
135 		int size = ntohl(*p++);
136 		if (size <= NFS3_FHSIZE) {
137 			fh->size = size;
138 			memcpy(fh->data, p, size);
139 		} else
140 			res->status = -EBADHANDLE;
141 	}
142 	return 0;
143 }
144 
145 #define MNT_dirpath_sz		(1 + 256)
146 #define MNT_fhstatus_sz		(1 + 8)
147 #define MNT_fhstatus3_sz	(1 + 16)
148 
149 static struct rpc_procinfo mnt_procedures[] = {
150 	[MNTPROC_MNT] = {
151 		.p_proc		= MNTPROC_MNT,
152 		.p_encode	= (kxdrproc_t) xdr_encode_dirpath,
153 		.p_decode	= (kxdrproc_t) xdr_decode_fhstatus,
154 		.p_arglen	= MNT_dirpath_sz,
155 		.p_replen	= MNT_fhstatus_sz,
156 		.p_statidx	= MNTPROC_MNT,
157 		.p_name		= "MOUNT",
158 	},
159 };
160 
161 static struct rpc_procinfo mnt3_procedures[] = {
162 	[MOUNTPROC3_MNT] = {
163 		.p_proc		= MOUNTPROC3_MNT,
164 		.p_encode	= (kxdrproc_t) xdr_encode_dirpath,
165 		.p_decode	= (kxdrproc_t) xdr_decode_fhstatus3,
166 		.p_arglen	= MNT_dirpath_sz,
167 		.p_replen	= MNT_fhstatus3_sz,
168 		.p_statidx	= MOUNTPROC3_MNT,
169 		.p_name		= "MOUNT",
170 	},
171 };
172 
173 
174 static struct rpc_version mnt_version1 = {
175 	.number		= 1,
176 	.nrprocs	= 2,
177 	.procs		= mnt_procedures,
178 };
179 
180 static struct rpc_version mnt_version3 = {
181 	.number		= 3,
182 	.nrprocs	= 2,
183 	.procs		= mnt3_procedures,
184 };
185 
186 static struct rpc_version *mnt_version[] = {
187 	NULL,
188 	&mnt_version1,
189 	NULL,
190 	&mnt_version3,
191 };
192 
193 static struct rpc_stat mnt_stats;
194 
195 static struct rpc_program mnt_program = {
196 	.name		= "mount",
197 	.number		= NFS_MNT_PROGRAM,
198 	.nrvers		= ARRAY_SIZE(mnt_version),
199 	.version	= mnt_version,
200 	.stats		= &mnt_stats,
201 };
202