1 /* $FreeBSD$ */
2 /* $Id: nfs_socket.c,v 1.12 2003/11/05 14:59:01 rees Exp $ */
3
4 /*-
5 * copyright (c) 2003
6 * the regents of the university of michigan
7 * all rights reserved
8 *
9 * permission is granted to use, copy, create derivative works and redistribute
10 * this software and such derivative works for any purpose, so long as the name
11 * of the university of michigan is not used in any advertising or publicity
12 * pertaining to the use or distribution of this software without specific,
13 * written prior authorization. if the above copyright notice or any other
14 * identification of the university of michigan is included in any copy of any
15 * portion of this software, then the disclaimer below must also be included.
16 *
17 * this software is provided as is, without representation from the university
18 * of michigan as to its fitness for any purpose, and without warranty by the
19 * university of michigan of any kind, either express or implied, including
20 * without limitation the implied warranties of merchantability and fitness for
21 * a particular purpose. the regents of the university of michigan shall not be
22 * liable for any damages, including special, indirect, incidental, or
23 * consequential damages, with respect to any claim arising out of or in
24 * connection with the use of the software, even if it has been or is hereafter
25 * advised of the possibility of such damages.
26 */
27
28 /*-
29 * Copyright (c) 1989, 1991, 1993, 1995
30 * The Regents of the University of California. All rights reserved.
31 *
32 * This code is derived from software contributed to Berkeley by
33 * Rick Macklem at The University of Guelph.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95
60 */
61
62 #include <sys/cdefs.h>
63 __FBSDID("$FreeBSD$");
64
65 /*
66 * Socket operations for use by nfs
67 */
68
69 #include "opt_inet6.h"
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/lock.h>
75 #include <sys/malloc.h>
76 #include <sys/mbuf.h>
77 #include <sys/mount.h>
78 #include <sys/mutex.h>
79 #include <sys/proc.h>
80 #include <sys/protosw.h>
81 #include <sys/signalvar.h>
82 #include <sys/socket.h>
83 #include <sys/socketvar.h>
84 #include <sys/syslog.h>
85 #include <sys/vnode.h>
86
87 #include <netinet/in.h>
88 #include <netinet/tcp.h>
89
90 #include <rpc/rpcclnt.h>
91
92 #include <nfs/rpcv2.h>
93 #include <nfs/nfsproto.h>
94 #include <nfsclient/nfs.h>
95 #include <nfs4client/nfs4.h>
96 #include <nfs/xdr_subs.h>
97 #include <nfsclient/nfsm_subs.h>
98 #include <nfsclient/nfsmount.h>
99
100 #ifdef NFS4_USE_RPCCLNT
101 #include <rpc/rpcclnt.h>
102 #include <rpc/rpcm_subs.h>
103 #endif
104
105 #ifdef NFS4_USE_RPCCLNT
106 static struct rpc_program nfs_program = {
107 NFS_PROG, NFS_VER4, "NFSv4"
108 };
109 #endif
110
111
112 static struct {
113 short nfserr;
114 short syserr;
115 } nfs_errtbl[] = {
116 { NFS_OK, 0 },
117 { NFSERR_PERM, EPERM },
118 { NFSERR_NOENT, ENOENT },
119 { NFSERR_IO, EIO },
120 { NFSERR_NXIO, ENXIO },
121 { NFSERR_ACCES, EACCES },
122 { NFSERR_EXIST, EEXIST },
123 { NFSERR_XDEV, EXDEV },
124 { NFSERR_MLINK, EMLINK },
125 { NFSERR_NODEV, ENODEV },
126 { NFSERR_NOTDIR, ENOTDIR },
127 { NFSERR_ISDIR, EISDIR },
128 { NFSERR_INVAL, EINVAL },
129 { NFSERR_FBIG, EFBIG },
130 { NFSERR_NOSPC, ENOSPC },
131 { NFSERR_ROFS, EROFS },
132 { NFSERR_MLINK, EMLINK },
133 { NFSERR_NAMETOL, ENAMETOOLONG },
134 { NFSERR_NOTEMPTY, ENOTEMPTY },
135 { NFSERR_NOTSUPP, EOPNOTSUPP },
136 #ifdef EDQUOT
137 { NFSERR_DQUOT, EDQUOT },
138 #endif
139 { NFSERR_STALE, ESTALE },
140 { NFSERR_DENIED, EAGAIN },
141 { NFSERR_SYMLINK, ELOOP },
142 { NFSERR_BADXDR, EBADRPC },
143 { NFSERR_WRONGSEC, EPERM },
144 { -1, EIO }
145 };
146
147 static int
148 nfs4_nfserr_to_syserr(int nfserr)
149 {
150 int i, syserr;
151
152 /* XXX : not the optimal algorithm, but will do for now! */
153 for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
154 if (nfs_errtbl[i].nfserr == nfserr)
155 break;
156 }
157 #ifdef NFS4_MAP_UNKNOWN_ERR
158 syserr = nfs_errtbl[i].syserr;
159 #else
160 if (nfs_errtbl[i].nfserr != -1)
161 syserr = nfs_errtbl[i].syserr;
162 else
163 syserr = nfserr;
164 #endif
165 return syserr;
166 }
167
168 int
169 nfs4_connect(struct nfsmount *nmp)
170 {
171 struct rpcclnt * rpc = &nmp->nm_rpcclnt;
172 struct rpc_auth * auth;
173 int flag = 0;
174 int error;
175
176 /* XXX hack! */
177 #ifdef __OpenBSD__
178 struct proc * td = curproc;
179 #else
180 struct thread * td = curthread;
181 #endif
182
183 MALLOC(auth, struct rpc_auth *, sizeof(struct rpc_auth), M_TEMP, M_WAITOK);
184 auth->auth_type = RPCAUTH_UNIX;
185
186 /* translate nfs flags -> rpcclnt flags */
187 if (nmp->nm_flag & NFSMNT_SOFT)
188 flag |= RPCCLNT_SOFT;
189
190 if (nmp->nm_flag & NFSMNT_INT)
191 flag |= RPCCLNT_INT;
192
193 if (nmp->nm_flag & NFSMNT_NOCONN)
194 flag |= RPCCLNT_NOCONN;
195
196 if (nmp->nm_flag & NFSMNT_DUMBTIMR)
197 flag |= RPCCLNT_DUMBTIMR;
198
199 /* rpc->rc_servername = nmp->nm_mountp->mnt_stat.f_mntfromname; */
200
201 error = rpcclnt_setup(rpc, &nfs_program, nmp->nm_nam, nmp->nm_sotype,
202 nmp->nm_soproto, auth,
203 /* XXX: check nmp->nm_flag to make sure these are set */
204 (nmp->nm_rsize > nmp->nm_readdirsize) ? nmp->nm_rsize : nmp->nm_readdirsize,
205 nmp->nm_wsize, flag);
206
207 /* set deadthresh, timeo, retry */
208 rpc->rc_deadthresh = nmp->nm_deadthresh;
209 rpc->rc_timeo = nmp->nm_timeo;
210 rpc->rc_retry = nmp->nm_retry;
211
212
213 if (error)
214 return error;
215
216 return rpcclnt_connect(rpc, td);
217 }
218
219 /*
220 * NFS disconnect. Clean up and unlink.
221 */
222 void
223 nfs4_disconnect(struct nfsmount *nmp)
224 {
225 rpcclnt_disconnect(&nmp->nm_rpcclnt);
226 }
227
228 void
229 nfs4_safedisconnect(struct nfsmount *nmp)
230 {
231 rpcclnt_safedisconnect(&nmp->nm_rpcclnt);
232 }
233
234 /*
235 * nfs_request - goes something like this
236 * - fill in request struct
237 * - links it into list
238 * - calls nfs_send() for first transmit
239 * - calls nfs_receive() to get reply
240 * - break down rpc header and return with nfs reply pointed to
241 * by mrep or error
242 * nb: always frees up mreq mbuf list
243 */
244 /* XXX overloaded before */
245 #define NQ_TRYLATERDEL 15 /* Initial try later delay (sec) */
246
247 int
248 nfs4_request(struct vnode *vp, struct mbuf *mrest, int procnum,
249 struct thread *td, struct ucred *cred, struct mbuf **mrp,
250 struct mbuf **mdp, caddr_t *dposp)
251 {
252 int error;
253
254 error = nfs4_request_mnt(VFSTONFS(vp->v_mount), mrest, procnum,
255 td, cred, mrp, mdp, dposp);
256
257 /*
258 ** If the File Handle was stale, invalidate the
259 ** lookup cache, just in case.
260 **/
261 if (error == ESTALE)
262 cache_purge(vp);
263
264 return (error);
265 }
266
267
268 int
269 nfs4_request_mnt(struct nfsmount *nmp, struct mbuf *mrest, int procnum,
270 struct thread *td, struct ucred *cred, struct mbuf **mrp,
271 struct mbuf **mdp, caddr_t *dposp)
272 {
273 int error;
274 u_int32_t *tl;
275 struct rpcclnt * clnt = &nmp->nm_rpcclnt;
276 struct mbuf *md, *mrep;
277 caddr_t dpos;
278 struct rpc_reply reply;
279
280 if ((error = rpcclnt_request(clnt, mrest, procnum, td, cred,
281 &reply)) != 0) {
282 goto out;
283 }
284
285 /* XXX: don't free mrest if an error occured, to allow caller to retry*/
286 m_freem(mrest);
287 mrep = reply.mrep;
288 md = reply.result_md;
289 dpos = reply.result_dpos;
290
291 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
292 if (*tl != 0) {
293 error = fxdr_unsigned(int, *tl);
294 #if 0
295 if ((nmp->nm_flag & NFSMNT_NFSV3) &&
296 error == NFSERR_TRYLATER) {
297 m_freem(mrep);
298 error = 0;
299 waituntil = time_second + trylater_delay;
300 while (time_second < waituntil)
301 (void) tsleep(&lbolt, PSOCK, "nqnfstry", 0);
302 trylater_delay *= nfs_backoff[trylater_cnt];
303 if (trylater_cnt < NFS_NBACKOFF - 1)
304 trylater_cnt++;
305 goto tryagain;
306 }
307 #endif
308 goto out;
309 }
310
311 *mrp = mrep;
312 *mdp = md;
313 *dposp = dpos;
314 return (0);
315 nfsmout:
316 out:
317 m_freem(reply.mrep);
318 *mrp = NULL;
319 *mdp = NULL;
320 return (nfs4_nfserr_to_syserr(error));
321 }
322
323
324 /*
325 * Mark all of an nfs mount's outstanding requests with R_SOFTTERM and
326 * wait for all requests to complete. This is used by forced unmounts
327 * to terminate any outstanding RPCs.
328 */
329 int
330 nfs4_nmcancelreqs(nmp)
331 struct nfsmount *nmp;
332 {
333 return rpcclnt_cancelreqs(&nmp->nm_rpcclnt);
334 }
335
336 /*
337 * Test for a termination condition pending on the process.
338 * This is used for NFSMNT_INT mounts.
339 */
340 int
341 nfs4_sigintr(struct nfsmount *nmp, struct nfsreq *rep, struct thread *td)
342 {
343 if (rep != NULL) {
344 printf("nfs_sigintr: attempting to use nfsreq != NULL\n");
345 return EINTR;
346 }
347 return rpcclnt_sigintr(&nmp->nm_rpcclnt, NULL, td);
348 }
Cache object: 84ebe34a89f743adab7f06890ca3789e
|