Commit | Line | Data |
---|---|---|
180c0ba3 KM |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Rick Macklem at The University of Guelph. | |
7 | * | |
dbf0c423 | 8 | * %sccs.include.redist.c% |
180c0ba3 | 9 | * |
ea67b335 | 10 | * @(#)nfs_subs.c 7.52 (Berkeley) %G% |
180c0ba3 KM |
11 | */ |
12 | ||
13 | /* | |
14 | * These functions support the macros and help fiddle mbuf chains for | |
15 | * the nfs op functions. They do things like create the rpc header and | |
16 | * copy data between mbuf chains and uio lists. | |
17 | */ | |
400a1380 KM |
18 | #include <sys/param.h> |
19 | #include <sys/proc.h> | |
20 | #include <sys/filedesc.h> | |
21 | #include <sys/systm.h> | |
22 | #include <sys/kernel.h> | |
23 | #include <sys/mount.h> | |
24 | #include <sys/file.h> | |
25 | #include <sys/vnode.h> | |
26 | #include <sys/namei.h> | |
27 | #include <sys/mbuf.h> | |
28 | #include <sys/map.h> | |
29 | #include <sys/socket.h> | |
30 | ||
31 | #include <vm/vm.h> | |
32 | ||
33 | #include <ufs/ufs/quota.h> | |
34 | #include <ufs/ufs/inode.h> | |
35 | #include <ufs/ufs/ufsmount.h> | |
36 | ||
37 | #include <nfs/rpcv2.h> | |
38 | #include <nfs/nfsv2.h> | |
39 | #include <nfs/nfsnode.h> | |
40 | #include <nfs/nfs.h> | |
41 | #include <nfs/xdr_subs.h> | |
42 | #include <nfs/nfsm_subs.h> | |
43 | #include <nfs/nfsmount.h> | |
44 | #include <nfs/nqnfs.h> | |
45 | #include <nfs/nfsrtt.h> | |
180c0ba3 KM |
46 | |
47 | #define TRUE 1 | |
48 | #define FALSE 0 | |
49 | ||
50 | /* | |
51 | * Data items converted to xdr at startup, since they are constant | |
52 | * This is kinda hokey, but may save a little time doing byte swaps | |
53 | */ | |
54 | u_long nfs_procids[NFS_NPROCS]; | |
55 | u_long nfs_xdrneg1; | |
2c5b44a2 KM |
56 | u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, |
57 | rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, | |
58 | rpc_auth_kerb; | |
180c0ba3 | 59 | u_long nfs_vers, nfs_prog, nfs_true, nfs_false; |
2c5b44a2 | 60 | |
180c0ba3 | 61 | /* And other global data */ |
2c5b44a2 | 62 | static u_long nfs_xid = 0; |
d4e5799e | 63 | enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; |
f0f1cbaa | 64 | extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; |
f0f1cbaa | 65 | extern struct nfsreq nfsreqh; |
2c5b44a2 KM |
66 | extern int nqnfs_piggy[NFS_NPROCS]; |
67 | extern struct nfsrtt nfsrtt; | |
68 | extern union nqsrvthead nqthead; | |
69 | extern union nqsrvthead nqfhead[NQLCHSZ]; | |
70 | extern time_t nqnfsstarttime; | |
71 | extern u_long nqnfs_prog, nqnfs_vers; | |
72 | extern int nqsrv_clockskew; | |
73 | extern int nqsrv_writeslack; | |
74 | extern int nqsrv_maxlease; | |
7a398e6f | 75 | |
180c0ba3 KM |
76 | /* |
77 | * Create the header for an rpc request packet | |
180c0ba3 KM |
78 | * The hsiz is the size of the rest of the nfs request header. |
79 | * (just used to decide if a cluster is a good idea) | |
180c0ba3 | 80 | */ |
2c5b44a2 KM |
81 | struct mbuf * |
82 | nfsm_reqh(vp, procid, hsiz, bposp) | |
83 | struct vnode *vp; | |
0bd503ad | 84 | u_long procid; |
180c0ba3 | 85 | int hsiz; |
2c5b44a2 | 86 | caddr_t *bposp; |
180c0ba3 | 87 | { |
2c5b44a2 | 88 | register struct mbuf *mb; |
25bf04c4 | 89 | register u_long *tl; |
2c5b44a2 KM |
90 | register caddr_t bpos; |
91 | struct mbuf *mb2; | |
92 | struct nfsmount *nmp; | |
93 | int nqflag; | |
180c0ba3 | 94 | |
2c5b44a2 KM |
95 | MGET(mb, M_WAIT, MT_DATA); |
96 | if (hsiz >= MINCLSIZE) | |
97 | MCLGET(mb, M_WAIT); | |
98 | mb->m_len = 0; | |
99 | bpos = mtod(mb, caddr_t); | |
100 | ||
180c0ba3 | 101 | /* |
2c5b44a2 | 102 | * For NQNFS, add lease request. |
180c0ba3 | 103 | */ |
2c5b44a2 KM |
104 | if (vp) { |
105 | nmp = VFSTONFS(vp->v_mount); | |
106 | if (nmp->nm_flag & NFSMNT_NQNFS) { | |
107 | nqflag = NQNFS_NEEDLEASE(vp, procid); | |
108 | if (nqflag) { | |
109 | nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); | |
110 | *tl++ = txdr_unsigned(nqflag); | |
111 | *tl = txdr_unsigned(nmp->nm_leaseterm); | |
112 | } else { | |
113 | nfsm_build(tl, u_long *, NFSX_UNSIGNED); | |
114 | *tl = 0; | |
115 | } | |
116 | } | |
117 | } | |
118 | /* Finally, return values */ | |
119 | *bposp = bpos; | |
120 | return (mb); | |
121 | } | |
122 | ||
123 | /* | |
124 | * Build the RPC header and fill in the authorization info. | |
125 | * The authorization string argument is only used when the credentials | |
126 | * come from outside of the kernel. | |
127 | * Returns the head of the mbuf list. | |
128 | */ | |
129 | struct mbuf * | |
130 | nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, | |
131 | mrest_len, mbp, xidp) | |
132 | register struct ucred *cr; | |
133 | int nqnfs; | |
134 | int procid; | |
135 | int auth_type; | |
136 | int auth_len; | |
137 | char *auth_str; | |
138 | struct mbuf *mrest; | |
139 | int mrest_len; | |
140 | struct mbuf **mbp; | |
141 | u_long *xidp; | |
142 | { | |
143 | register struct mbuf *mb; | |
144 | register u_long *tl; | |
145 | register caddr_t bpos; | |
146 | register int i; | |
147 | struct mbuf *mreq, *mb2; | |
148 | int siz, grpsiz, authsiz; | |
149 | ||
150 | authsiz = nfsm_rndup(auth_len); | |
151 | if (auth_type == RPCAUTH_NQNFS) | |
152 | authsiz += 2 * NFSX_UNSIGNED; | |
153 | MGETHDR(mb, M_WAIT, MT_DATA); | |
154 | if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { | |
155 | MCLGET(mb, M_WAIT); | |
156 | } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { | |
157 | MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); | |
158 | } else { | |
159 | MH_ALIGN(mb, 8*NFSX_UNSIGNED); | |
180c0ba3 | 160 | } |
2c5b44a2 KM |
161 | mb->m_len = 0; |
162 | mreq = mb; | |
163 | bpos = mtod(mb, caddr_t); | |
164 | ||
165 | /* | |
166 | * First the RPC header. | |
167 | */ | |
168 | nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); | |
169 | if (++nfs_xid == 0) | |
170 | nfs_xid++; | |
171 | *tl++ = *xidp = txdr_unsigned(nfs_xid); | |
25bf04c4 KM |
172 | *tl++ = rpc_call; |
173 | *tl++ = rpc_vers; | |
2c5b44a2 KM |
174 | if (nqnfs) { |
175 | *tl++ = txdr_unsigned(NQNFS_PROG); | |
176 | *tl++ = txdr_unsigned(NQNFS_VER1); | |
180c0ba3 | 177 | } else { |
2c5b44a2 KM |
178 | *tl++ = txdr_unsigned(NFS_PROG); |
179 | *tl++ = txdr_unsigned(NFS_VER2); | |
180c0ba3 | 180 | } |
2c5b44a2 KM |
181 | *tl++ = txdr_unsigned(procid); |
182 | ||
183 | /* | |
184 | * And then the authorization cred. | |
185 | */ | |
186 | *tl++ = txdr_unsigned(auth_type); | |
187 | *tl = txdr_unsigned(authsiz); | |
188 | switch (auth_type) { | |
189 | case RPCAUTH_UNIX: | |
190 | nfsm_build(tl, u_long *, auth_len); | |
191 | *tl++ = 0; /* stamp ?? */ | |
192 | *tl++ = 0; /* NULL hostname */ | |
193 | *tl++ = txdr_unsigned(cr->cr_uid); | |
194 | *tl++ = txdr_unsigned(cr->cr_groups[0]); | |
195 | grpsiz = (auth_len >> 2) - 5; | |
196 | *tl++ = txdr_unsigned(grpsiz); | |
197 | for (i = 1; i <= grpsiz; i++) | |
198 | *tl++ = txdr_unsigned(cr->cr_groups[i]); | |
199 | break; | |
200 | case RPCAUTH_NQNFS: | |
201 | nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); | |
202 | *tl++ = txdr_unsigned(cr->cr_uid); | |
203 | *tl = txdr_unsigned(auth_len); | |
204 | siz = auth_len; | |
205 | while (siz > 0) { | |
206 | if (M_TRAILINGSPACE(mb) == 0) { | |
207 | MGET(mb2, M_WAIT, MT_DATA); | |
208 | if (siz >= MINCLSIZE) | |
209 | MCLGET(mb2, M_WAIT); | |
210 | mb->m_next = mb2; | |
211 | mb = mb2; | |
212 | mb->m_len = 0; | |
213 | bpos = mtod(mb, caddr_t); | |
214 | } | |
215 | i = MIN(siz, M_TRAILINGSPACE(mb)); | |
216 | bcopy(auth_str, bpos, i); | |
217 | mb->m_len += i; | |
218 | auth_str += i; | |
219 | bpos += i; | |
220 | siz -= i; | |
221 | } | |
222 | if ((siz = nfsm_rndup(auth_len) - auth_len) > 0) { | |
223 | for (i = 0; i < siz; i++) | |
224 | *bpos++ = '\0'; | |
225 | mb->m_len += siz; | |
226 | } | |
227 | break; | |
228 | }; | |
229 | nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); | |
230 | *tl++ = txdr_unsigned(RPCAUTH_NULL); | |
231 | *tl = 0; | |
232 | mb->m_next = mrest; | |
233 | mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; | |
234 | mreq->m_pkthdr.rcvif = (struct ifnet *)0; | |
235 | *mbp = mb; | |
180c0ba3 KM |
236 | return (mreq); |
237 | } | |
238 | ||
239 | /* | |
240 | * copies mbuf chain to the uio scatter/gather list | |
241 | */ | |
242 | nfsm_mbuftouio(mrep, uiop, siz, dpos) | |
243 | struct mbuf **mrep; | |
170bfd05 | 244 | register struct uio *uiop; |
180c0ba3 KM |
245 | int siz; |
246 | caddr_t *dpos; | |
247 | { | |
170bfd05 | 248 | register char *mbufcp, *uiocp; |
180c0ba3 KM |
249 | register int xfer, left, len; |
250 | register struct mbuf *mp; | |
180c0ba3 | 251 | long uiosiz, rem; |
f0f1cbaa | 252 | int error = 0; |
180c0ba3 KM |
253 | |
254 | mp = *mrep; | |
255 | mbufcp = *dpos; | |
256 | len = mtod(mp, caddr_t)+mp->m_len-mbufcp; | |
257 | rem = nfsm_rndup(siz)-siz; | |
258 | while (siz > 0) { | |
259 | if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) | |
f0f1cbaa | 260 | return (EFBIG); |
180c0ba3 KM |
261 | left = uiop->uio_iov->iov_len; |
262 | uiocp = uiop->uio_iov->iov_base; | |
263 | if (left > siz) | |
264 | left = siz; | |
265 | uiosiz = left; | |
266 | while (left > 0) { | |
267 | while (len == 0) { | |
268 | mp = mp->m_next; | |
269 | if (mp == NULL) | |
270 | return (EBADRPC); | |
271 | mbufcp = mtod(mp, caddr_t); | |
272 | len = mp->m_len; | |
273 | } | |
274 | xfer = (left > len) ? len : left; | |
275 | #ifdef notdef | |
276 | /* Not Yet.. */ | |
277 | if (uiop->uio_iov->iov_op != NULL) | |
278 | (*(uiop->uio_iov->iov_op)) | |
279 | (mbufcp, uiocp, xfer); | |
280 | else | |
281 | #endif | |
282 | if (uiop->uio_segflg == UIO_SYSSPACE) | |
283 | bcopy(mbufcp, uiocp, xfer); | |
284 | else | |
285 | copyout(mbufcp, uiocp, xfer); | |
286 | left -= xfer; | |
287 | len -= xfer; | |
288 | mbufcp += xfer; | |
289 | uiocp += xfer; | |
24c658f0 | 290 | uiop->uio_offset += xfer; |
180c0ba3 KM |
291 | uiop->uio_resid -= xfer; |
292 | } | |
293 | if (uiop->uio_iov->iov_len <= siz) { | |
294 | uiop->uio_iovcnt--; | |
295 | uiop->uio_iov++; | |
296 | } else { | |
297 | uiop->uio_iov->iov_base += uiosiz; | |
298 | uiop->uio_iov->iov_len -= uiosiz; | |
299 | } | |
300 | siz -= uiosiz; | |
301 | } | |
180c0ba3 KM |
302 | *dpos = mbufcp; |
303 | *mrep = mp; | |
f0f1cbaa KM |
304 | if (rem > 0) { |
305 | if (len < rem) | |
306 | error = nfs_adv(mrep, dpos, rem, len); | |
307 | else | |
308 | *dpos += rem; | |
309 | } | |
310 | return (error); | |
180c0ba3 KM |
311 | } |
312 | ||
313 | /* | |
314 | * copies a uio scatter/gather list to an mbuf chain... | |
315 | */ | |
316 | nfsm_uiotombuf(uiop, mq, siz, bpos) | |
317 | register struct uio *uiop; | |
318 | struct mbuf **mq; | |
319 | int siz; | |
320 | caddr_t *bpos; | |
321 | { | |
170bfd05 KM |
322 | register char *uiocp; |
323 | register struct mbuf *mp, *mp2; | |
2c5b44a2 | 324 | register int xfer, left, mlen; |
170bfd05 KM |
325 | int uiosiz, clflg, rem; |
326 | char *cp; | |
180c0ba3 KM |
327 | |
328 | if (siz > MLEN) /* or should it >= MCLBYTES ?? */ | |
329 | clflg = 1; | |
330 | else | |
331 | clflg = 0; | |
332 | rem = nfsm_rndup(siz)-siz; | |
2c5b44a2 | 333 | mp = mp2 = *mq; |
180c0ba3 KM |
334 | while (siz > 0) { |
335 | if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) | |
f0f1cbaa | 336 | return (EINVAL); |
180c0ba3 KM |
337 | left = uiop->uio_iov->iov_len; |
338 | uiocp = uiop->uio_iov->iov_base; | |
339 | if (left > siz) | |
340 | left = siz; | |
341 | uiosiz = left; | |
342 | while (left > 0) { | |
2c5b44a2 KM |
343 | mlen = M_TRAILINGSPACE(mp); |
344 | if (mlen == 0) { | |
345 | MGET(mp, M_WAIT, MT_DATA); | |
346 | if (clflg) | |
347 | MCLGET(mp, M_WAIT); | |
348 | mp->m_len = 0; | |
349 | mp2->m_next = mp; | |
350 | mp2 = mp; | |
351 | mlen = M_TRAILINGSPACE(mp); | |
352 | } | |
353 | xfer = (left > mlen) ? mlen : left; | |
180c0ba3 KM |
354 | #ifdef notdef |
355 | /* Not Yet.. */ | |
356 | if (uiop->uio_iov->iov_op != NULL) | |
357 | (*(uiop->uio_iov->iov_op)) | |
2c5b44a2 | 358 | (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); |
180c0ba3 KM |
359 | else |
360 | #endif | |
361 | if (uiop->uio_segflg == UIO_SYSSPACE) | |
2c5b44a2 | 362 | bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); |
180c0ba3 | 363 | else |
2c5b44a2 KM |
364 | copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); |
365 | mp->m_len += xfer; | |
180c0ba3 KM |
366 | left -= xfer; |
367 | uiocp += xfer; | |
24c658f0 | 368 | uiop->uio_offset += xfer; |
180c0ba3 KM |
369 | uiop->uio_resid -= xfer; |
370 | } | |
371 | if (uiop->uio_iov->iov_len <= siz) { | |
372 | uiop->uio_iovcnt--; | |
373 | uiop->uio_iov++; | |
374 | } else { | |
375 | uiop->uio_iov->iov_base += uiosiz; | |
376 | uiop->uio_iov->iov_len -= uiosiz; | |
377 | } | |
378 | siz -= uiosiz; | |
379 | } | |
380 | if (rem > 0) { | |
2c5b44a2 | 381 | if (rem > M_TRAILINGSPACE(mp)) { |
180c0ba3 KM |
382 | MGET(mp, M_WAIT, MT_DATA); |
383 | mp->m_len = 0; | |
384 | mp2->m_next = mp; | |
385 | } | |
386 | cp = mtod(mp, caddr_t)+mp->m_len; | |
387 | for (left = 0; left < rem; left++) | |
388 | *cp++ = '\0'; | |
389 | mp->m_len += rem; | |
390 | *bpos = cp; | |
391 | } else | |
392 | *bpos = mtod(mp, caddr_t)+mp->m_len; | |
393 | *mq = mp; | |
f0f1cbaa | 394 | return (0); |
180c0ba3 KM |
395 | } |
396 | ||
397 | /* | |
398 | * Help break down an mbuf chain by setting the first siz bytes contiguous | |
399 | * pointed to by returned val. | |
400 | * If Updateflg == True we can overwrite the first part of the mbuf data | |
2c5b44a2 KM |
401 | * (in this case it can never sleep, so it can be called from interrupt level) |
402 | * it may however block when Updateflg == False | |
403 | * This is used by the macros nfsm_dissect and nfsm_dissecton for tough | |
180c0ba3 KM |
404 | * cases. (The macros use the vars. dpos and dpos2) |
405 | */ | |
406 | nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) | |
407 | struct mbuf **mdp; | |
408 | caddr_t *dposp; | |
409 | int siz; | |
410 | int left; | |
411 | int updateflg; | |
412 | caddr_t *cp2; | |
413 | { | |
414 | register struct mbuf *mp, *mp2; | |
415 | register int siz2, xfer; | |
2c5b44a2 | 416 | register caddr_t p; |
180c0ba3 KM |
417 | |
418 | mp = *mdp; | |
419 | while (left == 0) { | |
420 | *mdp = mp = mp->m_next; | |
421 | if (mp == NULL) | |
f0f1cbaa | 422 | return (EBADRPC); |
180c0ba3 KM |
423 | left = mp->m_len; |
424 | *dposp = mtod(mp, caddr_t); | |
425 | } | |
426 | if (left >= siz) { | |
427 | *cp2 = *dposp; | |
428 | *dposp += siz; | |
180c0ba3 | 429 | } else if (mp->m_next == NULL) { |
f0f1cbaa KM |
430 | return (EBADRPC); |
431 | } else if (siz > MHLEN) { | |
180c0ba3 KM |
432 | panic("nfs S too big"); |
433 | } else { | |
434 | /* Iff update, you can overwrite, else must alloc new mbuf */ | |
435 | if (updateflg) { | |
436 | NFSMINOFF(mp); | |
437 | } else { | |
438 | MGET(mp2, M_WAIT, MT_DATA); | |
439 | mp2->m_next = mp->m_next; | |
440 | mp->m_next = mp2; | |
441 | mp->m_len -= left; | |
442 | mp = mp2; | |
443 | } | |
2c5b44a2 KM |
444 | *cp2 = p = mtod(mp, caddr_t); |
445 | bcopy(*dposp, p, left); /* Copy what was left */ | |
180c0ba3 | 446 | siz2 = siz-left; |
2c5b44a2 | 447 | p += left; |
180c0ba3 | 448 | mp2 = mp->m_next; |
f0f1cbaa | 449 | /* Loop around copying up the siz2 bytes */ |
180c0ba3 KM |
450 | while (siz2 > 0) { |
451 | if (mp2 == NULL) | |
452 | return (EBADRPC); | |
453 | xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; | |
f0f1cbaa | 454 | if (xfer > 0) { |
2c5b44a2 | 455 | bcopy(mtod(mp2, caddr_t), p, xfer); |
f0f1cbaa KM |
456 | NFSMADV(mp2, xfer); |
457 | mp2->m_len -= xfer; | |
2c5b44a2 | 458 | p += xfer; |
f0f1cbaa KM |
459 | siz2 -= xfer; |
460 | } | |
180c0ba3 KM |
461 | if (siz2 > 0) |
462 | mp2 = mp2->m_next; | |
463 | } | |
464 | mp->m_len = siz; | |
465 | *mdp = mp2; | |
466 | *dposp = mtod(mp2, caddr_t); | |
180c0ba3 | 467 | } |
0bd503ad | 468 | return (0); |
180c0ba3 KM |
469 | } |
470 | ||
471 | /* | |
f0f1cbaa | 472 | * Advance the position in the mbuf chain. |
180c0ba3 KM |
473 | */ |
474 | nfs_adv(mdp, dposp, offs, left) | |
475 | struct mbuf **mdp; | |
476 | caddr_t *dposp; | |
477 | int offs; | |
478 | int left; | |
479 | { | |
480 | register struct mbuf *m; | |
481 | register int s; | |
482 | ||
483 | m = *mdp; | |
484 | s = left; | |
485 | while (s < offs) { | |
486 | offs -= s; | |
487 | m = m->m_next; | |
488 | if (m == NULL) | |
f0f1cbaa | 489 | return (EBADRPC); |
180c0ba3 KM |
490 | s = m->m_len; |
491 | } | |
492 | *mdp = m; | |
493 | *dposp = mtod(m, caddr_t)+offs; | |
f0f1cbaa | 494 | return (0); |
180c0ba3 KM |
495 | } |
496 | ||
497 | /* | |
498 | * Copy a string into mbufs for the hard cases... | |
499 | */ | |
500 | nfsm_strtmbuf(mb, bpos, cp, siz) | |
501 | struct mbuf **mb; | |
502 | char **bpos; | |
503 | char *cp; | |
504 | long siz; | |
505 | { | |
506 | register struct mbuf *m1, *m2; | |
507 | long left, xfer, len, tlen; | |
25bf04c4 | 508 | u_long *tl; |
180c0ba3 KM |
509 | int putsize; |
510 | ||
511 | putsize = 1; | |
512 | m2 = *mb; | |
2c5b44a2 | 513 | left = M_TRAILINGSPACE(m2); |
180c0ba3 | 514 | if (left > 0) { |
25bf04c4 KM |
515 | tl = ((u_long *)(*bpos)); |
516 | *tl++ = txdr_unsigned(siz); | |
180c0ba3 KM |
517 | putsize = 0; |
518 | left -= NFSX_UNSIGNED; | |
519 | m2->m_len += NFSX_UNSIGNED; | |
520 | if (left > 0) { | |
25bf04c4 | 521 | bcopy(cp, (caddr_t) tl, left); |
180c0ba3 KM |
522 | siz -= left; |
523 | cp += left; | |
524 | m2->m_len += left; | |
525 | left = 0; | |
526 | } | |
527 | } | |
2c5b44a2 | 528 | /* Loop around adding mbufs */ |
180c0ba3 KM |
529 | while (siz > 0) { |
530 | MGET(m1, M_WAIT, MT_DATA); | |
531 | if (siz > MLEN) | |
f0f1cbaa | 532 | MCLGET(m1, M_WAIT); |
180c0ba3 KM |
533 | m1->m_len = NFSMSIZ(m1); |
534 | m2->m_next = m1; | |
535 | m2 = m1; | |
25bf04c4 | 536 | tl = mtod(m1, u_long *); |
180c0ba3 KM |
537 | tlen = 0; |
538 | if (putsize) { | |
25bf04c4 | 539 | *tl++ = txdr_unsigned(siz); |
180c0ba3 KM |
540 | m1->m_len -= NFSX_UNSIGNED; |
541 | tlen = NFSX_UNSIGNED; | |
542 | putsize = 0; | |
543 | } | |
544 | if (siz < m1->m_len) { | |
545 | len = nfsm_rndup(siz); | |
546 | xfer = siz; | |
547 | if (xfer < len) | |
25bf04c4 | 548 | *(tl+(xfer>>2)) = 0; |
180c0ba3 KM |
549 | } else { |
550 | xfer = len = m1->m_len; | |
551 | } | |
25bf04c4 | 552 | bcopy(cp, (caddr_t) tl, xfer); |
180c0ba3 KM |
553 | m1->m_len = len+tlen; |
554 | siz -= xfer; | |
555 | cp += xfer; | |
556 | } | |
557 | *mb = m1; | |
558 | *bpos = mtod(m1, caddr_t)+m1->m_len; | |
f0f1cbaa | 559 | return (0); |
180c0ba3 KM |
560 | } |
561 | ||
562 | /* | |
563 | * Called once to initialize data structures... | |
564 | */ | |
e16a8c9b | 565 | nfs_init() |
180c0ba3 KM |
566 | { |
567 | register int i; | |
2c5b44a2 | 568 | union nqsrvthead *lhp; |
180c0ba3 | 569 | |
2c5b44a2 | 570 | nfsrtt.pos = 0; |
180c0ba3 KM |
571 | rpc_vers = txdr_unsigned(RPC_VER2); |
572 | rpc_call = txdr_unsigned(RPC_CALL); | |
573 | rpc_reply = txdr_unsigned(RPC_REPLY); | |
574 | rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); | |
575 | rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); | |
576 | rpc_mismatch = txdr_unsigned(RPC_MISMATCH); | |
2c5b44a2 KM |
577 | rpc_autherr = txdr_unsigned(RPC_AUTHERR); |
578 | rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); | |
180c0ba3 | 579 | rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); |
2c5b44a2 | 580 | rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); |
180c0ba3 KM |
581 | nfs_vers = txdr_unsigned(NFS_VER2); |
582 | nfs_prog = txdr_unsigned(NFS_PROG); | |
583 | nfs_true = txdr_unsigned(TRUE); | |
584 | nfs_false = txdr_unsigned(FALSE); | |
585 | /* Loop thru nfs procids */ | |
586 | for (i = 0; i < NFS_NPROCS; i++) | |
587 | nfs_procids[i] = txdr_unsigned(i); | |
ffe6f482 | 588 | /* Ensure async daemons disabled */ |
f0f1cbaa | 589 | for (i = 0; i < NFS_MAXASYNCDAEMON; i++) |
ffe6f482 | 590 | nfs_iodwant[i] = (struct proc *)0; |
180c0ba3 KM |
591 | nfs_xdrneg1 = txdr_unsigned(-1); |
592 | nfs_nhinit(); /* Init the nfsnode table */ | |
40316215 | 593 | nfsrv_init(0); /* Init server data structures */ |
e8540f59 | 594 | nfsrv_initcache(); /* Init the server request cache */ |
2c5b44a2 KM |
595 | |
596 | /* | |
597 | * Initialize the nqnfs server stuff. | |
598 | */ | |
599 | if (nqnfsstarttime == 0) { | |
600 | nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease | |
601 | + nqsrv_clockskew + nqsrv_writeslack; | |
602 | NQLOADNOVRAM(nqnfsstarttime); | |
603 | nqnfs_prog = txdr_unsigned(NQNFS_PROG); | |
604 | nqnfs_vers = txdr_unsigned(NQNFS_VER1); | |
605 | nqthead.th_head[0] = &nqthead; | |
606 | nqthead.th_head[1] = &nqthead; | |
607 | for (i = 0; i < NQLCHSZ; i++) { | |
608 | lhp = &nqfhead[i]; | |
609 | lhp->th_head[0] = lhp; | |
610 | lhp->th_head[1] = lhp; | |
611 | } | |
612 | } | |
f0f1cbaa KM |
613 | |
614 | /* | |
615 | * Initialize reply list and start timer | |
616 | */ | |
617 | nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; | |
180c0ba3 KM |
618 | nfs_timer(); |
619 | } | |
620 | ||
180c0ba3 KM |
621 | /* |
622 | * Attribute cache routines. | |
623 | * nfs_loadattrcache() - loads or updates the cache contents from attributes | |
624 | * that are on the mbuf list | |
625 | * nfs_getattrcache() - returns valid attributes if found in cache, returns | |
626 | * error otherwise | |
627 | */ | |
628 | ||
629 | /* | |
e16a8c9b | 630 | * Load the attribute cache (that lives in the nfsnode entry) with |
180c0ba3 KM |
631 | * the values on the mbuf list and |
632 | * Iff vap not NULL | |
633 | * copy the attributes to *vaper | |
634 | */ | |
610357c6 KM |
635 | nfs_loadattrcache(vpp, mdp, dposp, vaper) |
636 | struct vnode **vpp; | |
180c0ba3 KM |
637 | struct mbuf **mdp; |
638 | caddr_t *dposp; | |
639 | struct vattr *vaper; | |
640 | { | |
610357c6 | 641 | register struct vnode *vp = *vpp; |
180c0ba3 | 642 | register struct vattr *vap; |
9238aa59 | 643 | register struct nfsv2_fattr *fp; |
9342689a JH |
644 | extern int (**spec_nfsv2nodeop_p)(); |
645 | extern int (**spec_vnodeop_p)(); | |
610357c6 | 646 | register struct nfsnode *np; |
0bd503ad KM |
647 | register long t1; |
648 | caddr_t dpos, cp2; | |
649 | int error = 0; | |
650 | struct mbuf *md; | |
2c5b44a2 KM |
651 | enum vtype vtyp; |
652 | u_short vmode; | |
d4e5799e | 653 | long rdev; |
e16a8c9b KM |
654 | struct timeval mtime; |
655 | struct vnode *nvp; | |
180c0ba3 KM |
656 | |
657 | md = *mdp; | |
658 | dpos = *dposp; | |
2c5b44a2 | 659 | t1 = (mtod(md, caddr_t) + md->m_len) - dpos; |
180c0ba3 KM |
660 | if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) |
661 | return (error); | |
9238aa59 | 662 | fp = (struct nfsv2_fattr *)cp2; |
2c5b44a2 KM |
663 | vtyp = nfstov_type(fp->fa_type); |
664 | vmode = fxdr_unsigned(u_short, fp->fa_mode); | |
9a97c0c0 | 665 | if (vtyp == VNON || vtyp == VREG) |
2c5b44a2 | 666 | vtyp = IFTOVT(vmode); |
d4e5799e | 667 | rdev = fxdr_unsigned(long, fp->fa_rdev); |
e16a8c9b KM |
668 | fxdr_time(&fp->fa_mtime, &mtime); |
669 | /* | |
670 | * If v_type == VNON it is a new node, so fill in the v_type, | |
671 | * n_mtime fields. Check to see if it represents a special | |
672 | * device, and if so, check for a possible alias. Once the | |
673 | * correct vnode has been obtained, fill in the rest of the | |
674 | * information. | |
675 | */ | |
180c0ba3 | 676 | np = VTONFS(vp); |
e16a8c9b | 677 | if (vp->v_type == VNON) { |
2c5b44a2 KM |
678 | if (vtyp == VCHR && rdev == 0xffffffff) |
679 | vp->v_type = vtyp = VFIFO; | |
d4e5799e | 680 | else |
2c5b44a2 | 681 | vp->v_type = vtyp; |
28543a6e KM |
682 | if (vp->v_type == VFIFO) { |
683 | #ifdef FIFO | |
9342689a JH |
684 | extern int (**fifo_nfsv2nodeop_p)(); |
685 | vp->v_op = fifo_nfsv2nodeop_p; | |
28543a6e KM |
686 | #else |
687 | return (EOPNOTSUPP); | |
688 | #endif /* FIFO */ | |
689 | } | |
e16a8c9b | 690 | if (vp->v_type == VCHR || vp->v_type == VBLK) { |
9342689a | 691 | vp->v_op = spec_nfsv2nodeop_p; |
d4e5799e | 692 | if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { |
36ce47e7 KM |
693 | /* |
694 | * Discard unneeded vnode, but save its nfsnode. | |
695 | */ | |
696 | remque(np); | |
36ce47e7 KM |
697 | nvp->v_data = vp->v_data; |
698 | vp->v_data = NULL; | |
9342689a | 699 | vp->v_op = spec_vnodeop_p; |
36ce47e7 KM |
700 | vrele(vp); |
701 | vgone(vp); | |
e16a8c9b KM |
702 | /* |
703 | * Reinitialize aliased node. | |
704 | */ | |
e16a8c9b | 705 | np->n_vnode = nvp; |
e16a8c9b | 706 | insque(np, nfs_hash(&np->n_fh)); |
36ce47e7 | 707 | *vpp = vp = nvp; |
e16a8c9b KM |
708 | } |
709 | } | |
2c5b44a2 KM |
710 | if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0) |
711 | np->n_mtime = mtime.tv_sec; | |
e16a8c9b | 712 | } |
180c0ba3 | 713 | vap = &np->n_vattr; |
2c5b44a2 KM |
714 | vap->va_type = vtyp; |
715 | vap->va_mode = (vmode & 07777); | |
9238aa59 RM |
716 | vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); |
717 | vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); | |
718 | vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); | |
719 | vap->va_size = fxdr_unsigned(u_long, fp->fa_size); | |
8986c97c | 720 | if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) { |
9238aa59 | 721 | np->n_size = vap->va_size; |
400a1380 | 722 | vnode_pager_setsize(vp, (u_long)np->n_size); |
8986c97c | 723 | } |
9238aa59 | 724 | vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); |
d4e5799e KM |
725 | vap->va_rdev = (dev_t)rdev; |
726 | vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; | |
a12d9e5a | 727 | vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; |
9238aa59 | 728 | vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); |
e8540f59 KM |
729 | vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); |
730 | vap->va_atime.tv_usec = 0; | |
731 | vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); | |
e16a8c9b | 732 | vap->va_mtime = mtime; |
e8540f59 KM |
733 | vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); |
734 | vap->va_ctime.tv_usec = 0; | |
735 | vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); | |
37a7e5ab KM |
736 | #ifdef _NOQUAD |
737 | vap->va_size_rsv = 0; | |
738 | vap->va_bytes_rsv = 0; | |
739 | #endif | |
180c0ba3 KM |
740 | np->n_attrstamp = time.tv_sec; |
741 | *dposp = dpos; | |
742 | *mdp = md; | |
9238aa59 | 743 | if (vaper != NULL) { |
180c0ba3 | 744 | bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); |
9238aa59 RM |
745 | if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) |
746 | vaper->va_size = np->n_size; | |
747 | } | |
180c0ba3 KM |
748 | return (0); |
749 | } | |
750 | ||
751 | /* | |
752 | * Check the time stamp | |
753 | * If the cache is valid, copy contents to *vap and return 0 | |
754 | * otherwise return an error | |
755 | */ | |
756 | nfs_getattrcache(vp, vap) | |
757 | register struct vnode *vp; | |
758 | struct vattr *vap; | |
759 | { | |
760 | register struct nfsnode *np; | |
761 | ||
762 | np = VTONFS(vp); | |
2c5b44a2 KM |
763 | if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) { |
764 | if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { | |
765 | nfsstats.attrcache_misses++; | |
766 | return (ENOENT); | |
767 | } | |
768 | } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO) { | |
180c0ba3 KM |
769 | nfsstats.attrcache_misses++; |
770 | return (ENOENT); | |
771 | } | |
2c5b44a2 KM |
772 | nfsstats.attrcache_hits++; |
773 | bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); | |
774 | if ((np->n_flag & NMODIFIED) == 0) { | |
775 | np->n_size = vap->va_size; | |
400a1380 | 776 | vnode_pager_setsize(vp, (u_long)np->n_size); |
2c5b44a2 KM |
777 | } else if (np->n_size > vap->va_size) |
778 | vap->va_size = np->n_size; | |
779 | return (0); | |
180c0ba3 KM |
780 | } |
781 | ||
180c0ba3 | 782 | /* |
2c5b44a2 | 783 | * Set up nameidata for a lookup() call and do it |
180c0ba3 | 784 | */ |
2c5b44a2 | 785 | nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) |
180c0ba3 KM |
786 | register struct nameidata *ndp; |
787 | fhandle_t *fhp; | |
788 | int len; | |
2c5b44a2 KM |
789 | struct nfssvc_sock *slp; |
790 | struct mbuf *nam; | |
180c0ba3 KM |
791 | struct mbuf **mdp; |
792 | caddr_t *dposp; | |
bd0f8fef | 793 | struct proc *p; |
180c0ba3 KM |
794 | { |
795 | register int i, rem; | |
796 | register struct mbuf *md; | |
bd0f8fef | 797 | register char *fromcp, *tocp; |
10bae9ee | 798 | struct vnode *dp; |
7bd310ea JH |
799 | int error, rdonly; |
800 | struct componentname *cnp = &ndp->ni_cnd; | |
180c0ba3 | 801 | |
7bd310ea | 802 | MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); |
bd0f8fef KM |
803 | /* |
804 | * Copy the name from the mbuf list to ndp->ni_pnbuf | |
805 | * and set the various ndp fields appropriately. | |
806 | */ | |
807 | fromcp = *dposp; | |
7bd310ea | 808 | tocp = cnp->cn_pnbuf; |
bd0f8fef KM |
809 | md = *mdp; |
810 | rem = mtod(md, caddr_t) + md->m_len - fromcp; | |
7bd310ea | 811 | cnp->cn_hash = 0; |
bd0f8fef KM |
812 | for (i = 0; i < len; i++) { |
813 | while (rem == 0) { | |
814 | md = md->m_next; | |
815 | if (md == NULL) { | |
816 | error = EBADRPC; | |
817 | goto out; | |
d4e5799e | 818 | } |
bd0f8fef KM |
819 | fromcp = mtod(md, caddr_t); |
820 | rem = md->m_len; | |
d4e5799e | 821 | } |
bd0f8fef KM |
822 | if (*fromcp == '\0' || *fromcp == '/') { |
823 | error = EINVAL; | |
824 | goto out; | |
d4e5799e | 825 | } |
bd0f8fef | 826 | if (*fromcp & 0200) |
7bd310ea | 827 | if ((*fromcp&0377) == ('/'|0200) || cnp->cn_nameiop != DELETE) { |
bd0f8fef KM |
828 | error = EINVAL; |
829 | goto out; | |
830 | } | |
7bd310ea | 831 | cnp->cn_hash += (unsigned char)*fromcp; |
bd0f8fef KM |
832 | *tocp++ = *fromcp++; |
833 | rem--; | |
834 | } | |
835 | *tocp = '\0'; | |
836 | *mdp = md; | |
837 | *dposp = fromcp; | |
838 | len = nfsm_rndup(len)-len; | |
839 | if (len > 0) { | |
840 | if (rem >= len) | |
841 | *dposp += len; | |
842 | else if (error = nfs_adv(mdp, dposp, len, rem)) | |
843 | goto out; | |
844 | } | |
7bd310ea JH |
845 | ndp->ni_pathlen = tocp - cnp->cn_pnbuf; |
846 | cnp->cn_nameptr = cnp->cn_pnbuf; | |
10bae9ee KM |
847 | /* |
848 | * Extract and set starting directory. | |
849 | */ | |
7bd310ea JH |
850 | if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, |
851 | nam, &rdonly)) | |
bd0f8fef | 852 | goto out; |
36c3043b | 853 | if (dp->v_type != VDIR) { |
f0f1cbaa | 854 | vrele(dp); |
bd0f8fef KM |
855 | error = ENOTDIR; |
856 | goto out; | |
36c3043b | 857 | } |
10bae9ee | 858 | ndp->ni_startdir = dp; |
2c5b44a2 | 859 | if (rdonly) |
7bd310ea | 860 | cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); |
2c5b44a2 | 861 | else |
7bd310ea | 862 | cnp->cn_flags |= NOCROSSMOUNT; |
180c0ba3 | 863 | /* |
bd0f8fef | 864 | * And call lookup() to do the real work |
180c0ba3 | 865 | */ |
7bd310ea JH |
866 | cnp->cn_proc = p; |
867 | if (error = lookup(ndp)) | |
bd0f8fef KM |
868 | goto out; |
869 | /* | |
870 | * Check for encountering a symbolic link | |
871 | */ | |
7bd310ea JH |
872 | if (cnp->cn_flags & ISSYMLINK) { |
873 | if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) | |
bd0f8fef KM |
874 | vput(ndp->ni_dvp); |
875 | else | |
876 | vrele(ndp->ni_dvp); | |
877 | vput(ndp->ni_vp); | |
878 | ndp->ni_vp = NULL; | |
879 | error = EINVAL; | |
880 | goto out; | |
881 | } | |
882 | /* | |
883 | * Check for saved name request | |
884 | */ | |
7bd310ea JH |
885 | if (cnp->cn_flags & (SAVENAME | SAVESTART)) { |
886 | cnp->cn_flags |= HASBUF; | |
bd0f8fef KM |
887 | return (0); |
888 | } | |
889 | out: | |
7bd310ea | 890 | FREE(cnp->cn_pnbuf, M_NAMEI); |
180c0ba3 KM |
891 | return (error); |
892 | } | |
893 | ||
894 | /* | |
895 | * A fiddled version of m_adj() that ensures null fill to a long | |
896 | * boundary and only trims off the back end | |
897 | */ | |
2c5b44a2 | 898 | void |
180c0ba3 KM |
899 | nfsm_adj(mp, len, nul) |
900 | struct mbuf *mp; | |
901 | register int len; | |
902 | int nul; | |
903 | { | |
904 | register struct mbuf *m; | |
905 | register int count, i; | |
906 | register char *cp; | |
907 | ||
908 | /* | |
909 | * Trim from tail. Scan the mbuf chain, | |
910 | * calculating its length and finding the last mbuf. | |
911 | * If the adjustment only affects this mbuf, then just | |
912 | * adjust and return. Otherwise, rescan and truncate | |
913 | * after the remaining size. | |
914 | */ | |
915 | count = 0; | |
916 | m = mp; | |
917 | for (;;) { | |
918 | count += m->m_len; | |
919 | if (m->m_next == (struct mbuf *)0) | |
920 | break; | |
921 | m = m->m_next; | |
922 | } | |
1f9b0aa5 | 923 | if (m->m_len > len) { |
180c0ba3 KM |
924 | m->m_len -= len; |
925 | if (nul > 0) { | |
926 | cp = mtod(m, caddr_t)+m->m_len-nul; | |
927 | for (i = 0; i < nul; i++) | |
928 | *cp++ = '\0'; | |
929 | } | |
930 | return; | |
931 | } | |
932 | count -= len; | |
933 | if (count < 0) | |
934 | count = 0; | |
935 | /* | |
936 | * Correct length for chain is "count". | |
937 | * Find the mbuf with last data, adjust its length, | |
938 | * and toss data from remaining mbufs on chain. | |
939 | */ | |
940 | for (m = mp; m; m = m->m_next) { | |
941 | if (m->m_len >= count) { | |
942 | m->m_len = count; | |
943 | if (nul > 0) { | |
944 | cp = mtod(m, caddr_t)+m->m_len-nul; | |
945 | for (i = 0; i < nul; i++) | |
946 | *cp++ = '\0'; | |
947 | } | |
948 | break; | |
949 | } | |
950 | count -= m->m_len; | |
951 | } | |
952 | while (m = m->m_next) | |
953 | m->m_len = 0; | |
954 | } | |
955 | ||
956 | /* | |
957 | * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) | |
958 | * - look up fsid in mount list (if not found ret error) | |
959 | * - check that it is exported | |
960 | * - get vp by calling VFS_FHTOVP() macro | |
961 | * - if not lockflag unlock it with VOP_UNLOCK() | |
2c5b44a2 | 962 | * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to neth_anon |
180c0ba3 | 963 | */ |
2c5b44a2 | 964 | nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) |
180c0ba3 KM |
965 | fhandle_t *fhp; |
966 | int lockflag; | |
967 | struct vnode **vpp; | |
968 | struct ucred *cred; | |
2c5b44a2 KM |
969 | struct nfssvc_sock *slp; |
970 | struct mbuf *nam; | |
971 | int *rdonlyp; | |
180c0ba3 | 972 | { |
9342689a | 973 | USES_VOP_UNLOCK; |
180c0ba3 | 974 | register struct mount *mp; |
2c5b44a2 KM |
975 | register struct netaddrhash *np; |
976 | register struct ufsmount *ump; | |
977 | register struct nfsuid *uidp; | |
978 | struct sockaddr *saddr; | |
979 | int error; | |
180c0ba3 | 980 | |
2c5b44a2 | 981 | *vpp = (struct vnode *)0; |
180c0ba3 KM |
982 | if ((mp = getvfs(&fhp->fh_fsid)) == NULL) |
983 | return (ESTALE); | |
54fb9dc2 | 984 | if ((mp->mnt_flag & MNT_EXPORTED) == 0) |
180c0ba3 | 985 | return (EACCES); |
958df9fb | 986 | |
2c5b44a2 KM |
987 | /* |
988 | * Get the export permission structure for this <mp, client> tuple. | |
989 | */ | |
990 | ump = VFSTOUFS(mp); | |
991 | if (nam) { | |
958df9fb | 992 | |
2c5b44a2 KM |
993 | /* |
994 | * First search for a network match. | |
995 | */ | |
996 | np = ump->um_netaddr[NETMASK_HASH]; | |
997 | while (np) { | |
998 | if (nfs_netaddr_match(np->neth_family, &np->neth_haddr, | |
999 | &np->neth_hmask, nam)) | |
1000 | break; | |
1001 | np = np->neth_next; | |
958df9fb | 1002 | } |
958df9fb | 1003 | |
2c5b44a2 KM |
1004 | /* |
1005 | * If not found, try for an address match. | |
1006 | */ | |
1007 | if (np == (struct netaddrhash *)0) { | |
1008 | saddr = mtod(nam, struct sockaddr *); | |
1009 | np = ump->um_netaddr[NETADDRHASH(saddr)]; | |
1010 | while (np) { | |
1011 | if (nfs_netaddr_match(np->neth_family, &np->neth_haddr, | |
1012 | (struct netaddrhash *)0, nam)) | |
1013 | break; | |
1014 | np = np->neth_next; | |
1015 | } | |
958df9fb | 1016 | } |
2c5b44a2 KM |
1017 | } else |
1018 | np = (struct netaddrhash *)0; | |
1019 | if (np == (struct netaddrhash *)0) { | |
1020 | ||
1021 | /* | |
1022 | * If no address match, use the default if it exists. | |
1023 | */ | |
1024 | if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0) | |
1025 | return (EACCES); | |
1026 | np = &ump->um_defexported; | |
958df9fb | 1027 | } |
2c5b44a2 KM |
1028 | |
1029 | /* | |
1030 | * Check/setup credentials. | |
1031 | */ | |
1032 | if (np->neth_exflags & MNT_EXKERB) { | |
1033 | uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; | |
1034 | while (uidp) { | |
1035 | if (uidp->nu_uid == cred->cr_uid) | |
1036 | break; | |
1037 | uidp = uidp->nu_hnext; | |
958df9fb | 1038 | } |
2c5b44a2 KM |
1039 | if (uidp) { |
1040 | if (cred->cr_ref != 1) | |
1041 | panic("nsrv fhtovp"); | |
1042 | *cred = uidp->nu_cr; | |
1043 | } else | |
1044 | return (NQNFS_AUTHERR); | |
1045 | } else if (cred->cr_uid == 0 || (np->neth_exflags & MNT_EXPORTANON)) | |
1046 | *cred = np->neth_anon; | |
1047 | if (error = VFS_FHTOVP(mp, &fhp->fh_fid, 0, vpp)) | |
1048 | return (ESTALE); | |
1049 | if (np->neth_exflags & MNT_EXRDONLY) | |
1050 | *rdonlyp = 1; | |
1051 | else | |
1052 | *rdonlyp = 0; | |
1053 | if (!lockflag) | |
1054 | VOP_UNLOCK(*vpp); | |
1055 | return (0); | |
958df9fb | 1056 | } |