]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/nfs4client/nfs4_socket.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / nfs4client / nfs4_socket.c
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 }