get rid of ifdef NVM
[unix-history] / usr / src / sys / nfs / nfs_subs.c
CommitLineData
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 *
f8029f62 10 * @(#)nfs_subs.c 7.40 (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 */
180c0ba3 18#include "param.h"
ffe6f482 19#include "proc.h"
33e820ca 20#include "filedesc.h"
e587d97d 21#include "systm.h"
180c0ba3 22#include "kernel.h"
e587d97d 23#include "mount.h"
180c0ba3
KM
24#include "file.h"
25#include "vnode.h"
25bf04c4 26#include "namei.h"
e587d97d 27#include "mbuf.h"
9238aa59 28#include "map.h"
058dee65 29
1c89915d
KM
30#include "../ufs/quota.h"
31#include "../ufs/inode.h"
058dee65 32
180c0ba3
KM
33#include "rpcv2.h"
34#include "nfsv2.h"
35#include "nfsnode.h"
36#include "nfs.h"
9238aa59 37#include "nfsiom.h"
180c0ba3
KM
38#include "xdr_subs.h"
39#include "nfsm_subs.h"
958df9fb 40#include "nfscompress.h"
180c0ba3
KM
41
42#define TRUE 1
43#define FALSE 0
44
45/*
46 * Data items converted to xdr at startup, since they are constant
47 * This is kinda hokey, but may save a little time doing byte swaps
48 */
49u_long nfs_procids[NFS_NPROCS];
50u_long nfs_xdrneg1;
51u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
52 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
53u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
54/* And other global data */
55static u_long *rpc_uidp = (u_long *)0;
56static u_long nfs_xid = 1;
57static char *rpc_unixauth;
58extern long hostid;
d4e5799e 59enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
f0f1cbaa 60extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
9238aa59 61extern struct map nfsmap[NFS_MSIZ];
f0f1cbaa 62extern struct nfsreq nfsreqh;
180c0ba3
KM
63
64/* Function ret types */
65static char *nfs_unixauth();
66
7a398e6f
KM
67/*
68 * Maximum number of groups passed through to NFS server.
f0f1cbaa 69 * According to RFC1057 it should be 16.
7a398e6f 70 * For release 3.X systems, the maximum value is 8.
af2d4e11 71 * For some other servers, the maximum value is 10.
7a398e6f
KM
72 */
73int numgrps = 8;
74
180c0ba3
KM
75/*
76 * Create the header for an rpc request packet
77 * The function nfs_unixauth() creates a unix style authorization string
78 * and returns a ptr to it.
79 * The hsiz is the size of the rest of the nfs request header.
80 * (just used to decide if a cluster is a good idea)
0bd503ad 81 * nb: Note that the prog, vers and procid args are already in xdr byte order
180c0ba3 82 */
0bd503ad 83struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid)
180c0ba3
KM
84 u_long prog;
85 u_long vers;
0bd503ad 86 u_long procid;
180c0ba3
KM
87 struct ucred *cred;
88 int hsiz;
89 caddr_t *bpos;
90 struct mbuf **mb;
91 u_long *retxid;
92{
93 register struct mbuf *mreq, *m;
25bf04c4 94 register u_long *tl;
180c0ba3
KM
95 struct mbuf *m1;
96 char *ap;
97 int asiz, siz;
98
99 NFSMGETHDR(mreq);
af2d4e11
KM
100 asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps :
101 (cred->cr_ngroups - 1)) << 2);
36c3043b 102#ifdef FILLINHOST
180c0ba3 103 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
36c3043b
KM
104#else
105 asiz += 9*NFSX_UNSIGNED;
106#endif
180c0ba3
KM
107
108 /* If we need a lot, alloc a cluster ?? */
109 if ((asiz+hsiz+RPC_SIZ) > MHLEN)
f0f1cbaa 110 MCLGET(mreq, M_WAIT);
180c0ba3
KM
111 mreq->m_len = NFSMSIZ(mreq);
112 siz = mreq->m_len;
113 m1 = mreq;
114 /*
115 * Alloc enough mbufs
116 * We do it now to avoid all sleeps after the call to nfs_unixauth()
117 */
118 while ((asiz+RPC_SIZ) > siz) {
119 MGET(m, M_WAIT, MT_DATA);
120 m1->m_next = m;
121 m->m_len = MLEN;
122 siz += MLEN;
123 m1 = m;
124 }
25bf04c4
KM
125 tl = mtod(mreq, u_long *);
126 *tl++ = *retxid = txdr_unsigned(++nfs_xid);
127 *tl++ = rpc_call;
128 *tl++ = rpc_vers;
129 *tl++ = prog;
130 *tl++ = vers;
131 *tl++ = procid;
180c0ba3
KM
132
133 /* Now we can call nfs_unixauth() and copy it in */
134 ap = nfs_unixauth(cred);
135 m = mreq;
136 siz = m->m_len-RPC_SIZ;
137 if (asiz <= siz) {
25bf04c4 138 bcopy(ap, (caddr_t)tl, asiz);
180c0ba3
KM
139 m->m_len = asiz+RPC_SIZ;
140 } else {
25bf04c4 141 bcopy(ap, (caddr_t)tl, siz);
180c0ba3
KM
142 ap += siz;
143 asiz -= siz;
144 while (asiz > 0) {
145 siz = (asiz > MLEN) ? MLEN : asiz;
146 m = m->m_next;
147 bcopy(ap, mtod(m, caddr_t), siz);
148 m->m_len = siz;
149 asiz -= siz;
150 ap += siz;
151 }
152 }
153
154 /* Finally, return values */
155 *mb = m;
156 *bpos = mtod(m, caddr_t)+m->m_len;
157 return (mreq);
158}
159
160/*
161 * copies mbuf chain to the uio scatter/gather list
162 */
163nfsm_mbuftouio(mrep, uiop, siz, dpos)
164 struct mbuf **mrep;
170bfd05 165 register struct uio *uiop;
180c0ba3
KM
166 int siz;
167 caddr_t *dpos;
168{
170bfd05 169 register char *mbufcp, *uiocp;
180c0ba3
KM
170 register int xfer, left, len;
171 register struct mbuf *mp;
180c0ba3 172 long uiosiz, rem;
f0f1cbaa 173 int error = 0;
180c0ba3
KM
174
175 mp = *mrep;
176 mbufcp = *dpos;
177 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
178 rem = nfsm_rndup(siz)-siz;
179 while (siz > 0) {
180 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
f0f1cbaa 181 return (EFBIG);
180c0ba3
KM
182 left = uiop->uio_iov->iov_len;
183 uiocp = uiop->uio_iov->iov_base;
184 if (left > siz)
185 left = siz;
186 uiosiz = left;
187 while (left > 0) {
188 while (len == 0) {
189 mp = mp->m_next;
190 if (mp == NULL)
191 return (EBADRPC);
192 mbufcp = mtod(mp, caddr_t);
193 len = mp->m_len;
194 }
195 xfer = (left > len) ? len : left;
196#ifdef notdef
197 /* Not Yet.. */
198 if (uiop->uio_iov->iov_op != NULL)
199 (*(uiop->uio_iov->iov_op))
200 (mbufcp, uiocp, xfer);
201 else
202#endif
203 if (uiop->uio_segflg == UIO_SYSSPACE)
204 bcopy(mbufcp, uiocp, xfer);
205 else
206 copyout(mbufcp, uiocp, xfer);
207 left -= xfer;
208 len -= xfer;
209 mbufcp += xfer;
210 uiocp += xfer;
24c658f0 211 uiop->uio_offset += xfer;
180c0ba3
KM
212 uiop->uio_resid -= xfer;
213 }
214 if (uiop->uio_iov->iov_len <= siz) {
215 uiop->uio_iovcnt--;
216 uiop->uio_iov++;
217 } else {
218 uiop->uio_iov->iov_base += uiosiz;
219 uiop->uio_iov->iov_len -= uiosiz;
220 }
221 siz -= uiosiz;
222 }
180c0ba3
KM
223 *dpos = mbufcp;
224 *mrep = mp;
f0f1cbaa
KM
225 if (rem > 0) {
226 if (len < rem)
227 error = nfs_adv(mrep, dpos, rem, len);
228 else
229 *dpos += rem;
230 }
231 return (error);
180c0ba3
KM
232}
233
234/*
235 * copies a uio scatter/gather list to an mbuf chain...
236 */
237nfsm_uiotombuf(uiop, mq, siz, bpos)
238 register struct uio *uiop;
239 struct mbuf **mq;
240 int siz;
241 caddr_t *bpos;
242{
170bfd05
KM
243 register char *uiocp;
244 register struct mbuf *mp, *mp2;
245 register int xfer, left, len;
246 int uiosiz, clflg, rem;
247 char *cp;
180c0ba3
KM
248
249 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
250 clflg = 1;
251 else
252 clflg = 0;
253 rem = nfsm_rndup(siz)-siz;
254 mp2 = *mq;
255 while (siz > 0) {
256 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
f0f1cbaa 257 return (EINVAL);
180c0ba3
KM
258 left = uiop->uio_iov->iov_len;
259 uiocp = uiop->uio_iov->iov_base;
260 if (left > siz)
261 left = siz;
262 uiosiz = left;
263 while (left > 0) {
264 MGET(mp, M_WAIT, MT_DATA);
265 if (clflg)
f0f1cbaa 266 MCLGET(mp, M_WAIT);
180c0ba3
KM
267 mp->m_len = NFSMSIZ(mp);
268 mp2->m_next = mp;
269 mp2 = mp;
270 xfer = (left > mp->m_len) ? mp->m_len : left;
271#ifdef notdef
272 /* Not Yet.. */
273 if (uiop->uio_iov->iov_op != NULL)
274 (*(uiop->uio_iov->iov_op))
275 (uiocp, mtod(mp, caddr_t), xfer);
276 else
277#endif
278 if (uiop->uio_segflg == UIO_SYSSPACE)
279 bcopy(uiocp, mtod(mp, caddr_t), xfer);
280 else
281 copyin(uiocp, mtod(mp, caddr_t), xfer);
282 len = mp->m_len;
283 mp->m_len = xfer;
284 left -= xfer;
285 uiocp += xfer;
24c658f0 286 uiop->uio_offset += xfer;
180c0ba3
KM
287 uiop->uio_resid -= xfer;
288 }
289 if (uiop->uio_iov->iov_len <= siz) {
290 uiop->uio_iovcnt--;
291 uiop->uio_iov++;
292 } else {
293 uiop->uio_iov->iov_base += uiosiz;
294 uiop->uio_iov->iov_len -= uiosiz;
295 }
296 siz -= uiosiz;
297 }
298 if (rem > 0) {
299 if (rem > (len-mp->m_len)) {
300 MGET(mp, M_WAIT, MT_DATA);
301 mp->m_len = 0;
302 mp2->m_next = mp;
303 }
304 cp = mtod(mp, caddr_t)+mp->m_len;
305 for (left = 0; left < rem; left++)
306 *cp++ = '\0';
307 mp->m_len += rem;
308 *bpos = cp;
309 } else
310 *bpos = mtod(mp, caddr_t)+mp->m_len;
311 *mq = mp;
f0f1cbaa 312 return (0);
180c0ba3
KM
313}
314
315/*
316 * Help break down an mbuf chain by setting the first siz bytes contiguous
317 * pointed to by returned val.
318 * If Updateflg == True we can overwrite the first part of the mbuf data
319 * This is used by the macros nfsm_disect and nfsm_disecton for tough
320 * cases. (The macros use the vars. dpos and dpos2)
321 */
322nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
323 struct mbuf **mdp;
324 caddr_t *dposp;
325 int siz;
326 int left;
327 int updateflg;
328 caddr_t *cp2;
329{
330 register struct mbuf *mp, *mp2;
331 register int siz2, xfer;
25bf04c4 332 register caddr_t tl;
180c0ba3
KM
333
334 mp = *mdp;
335 while (left == 0) {
336 *mdp = mp = mp->m_next;
337 if (mp == NULL)
f0f1cbaa 338 return (EBADRPC);
180c0ba3
KM
339 left = mp->m_len;
340 *dposp = mtod(mp, caddr_t);
341 }
342 if (left >= siz) {
343 *cp2 = *dposp;
344 *dposp += siz;
180c0ba3 345 } else if (mp->m_next == NULL) {
f0f1cbaa
KM
346 return (EBADRPC);
347 } else if (siz > MHLEN) {
180c0ba3
KM
348 panic("nfs S too big");
349 } else {
350 /* Iff update, you can overwrite, else must alloc new mbuf */
351 if (updateflg) {
352 NFSMINOFF(mp);
353 } else {
354 MGET(mp2, M_WAIT, MT_DATA);
355 mp2->m_next = mp->m_next;
356 mp->m_next = mp2;
357 mp->m_len -= left;
358 mp = mp2;
359 }
25bf04c4
KM
360 *cp2 = tl = mtod(mp, caddr_t);
361 bcopy(*dposp, tl, left); /* Copy what was left */
180c0ba3 362 siz2 = siz-left;
25bf04c4 363 tl += left;
180c0ba3 364 mp2 = mp->m_next;
f0f1cbaa 365 /* Loop around copying up the siz2 bytes */
180c0ba3
KM
366 while (siz2 > 0) {
367 if (mp2 == NULL)
368 return (EBADRPC);
369 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
f0f1cbaa 370 if (xfer > 0) {
25bf04c4 371 bcopy(mtod(mp2, caddr_t), tl, xfer);
f0f1cbaa
KM
372 NFSMADV(mp2, xfer);
373 mp2->m_len -= xfer;
25bf04c4 374 tl += xfer;
f0f1cbaa
KM
375 siz2 -= xfer;
376 }
180c0ba3
KM
377 if (siz2 > 0)
378 mp2 = mp2->m_next;
379 }
380 mp->m_len = siz;
381 *mdp = mp2;
382 *dposp = mtod(mp2, caddr_t);
180c0ba3 383 }
0bd503ad 384 return (0);
180c0ba3
KM
385}
386
387/*
f0f1cbaa 388 * Advance the position in the mbuf chain.
180c0ba3
KM
389 */
390nfs_adv(mdp, dposp, offs, left)
391 struct mbuf **mdp;
392 caddr_t *dposp;
393 int offs;
394 int left;
395{
396 register struct mbuf *m;
397 register int s;
398
399 m = *mdp;
400 s = left;
401 while (s < offs) {
402 offs -= s;
403 m = m->m_next;
404 if (m == NULL)
f0f1cbaa 405 return (EBADRPC);
180c0ba3
KM
406 s = m->m_len;
407 }
408 *mdp = m;
409 *dposp = mtod(m, caddr_t)+offs;
f0f1cbaa 410 return (0);
180c0ba3
KM
411}
412
413/*
414 * Copy a string into mbufs for the hard cases...
415 */
416nfsm_strtmbuf(mb, bpos, cp, siz)
417 struct mbuf **mb;
418 char **bpos;
419 char *cp;
420 long siz;
421{
422 register struct mbuf *m1, *m2;
423 long left, xfer, len, tlen;
25bf04c4 424 u_long *tl;
180c0ba3
KM
425 int putsize;
426
427 putsize = 1;
428 m2 = *mb;
429 left = NFSMSIZ(m2)-m2->m_len;
430 if (left > 0) {
25bf04c4
KM
431 tl = ((u_long *)(*bpos));
432 *tl++ = txdr_unsigned(siz);
180c0ba3
KM
433 putsize = 0;
434 left -= NFSX_UNSIGNED;
435 m2->m_len += NFSX_UNSIGNED;
436 if (left > 0) {
25bf04c4 437 bcopy(cp, (caddr_t) tl, left);
180c0ba3
KM
438 siz -= left;
439 cp += left;
440 m2->m_len += left;
441 left = 0;
442 }
443 }
444 /* Loop arround adding mbufs */
445 while (siz > 0) {
446 MGET(m1, M_WAIT, MT_DATA);
447 if (siz > MLEN)
f0f1cbaa 448 MCLGET(m1, M_WAIT);
180c0ba3
KM
449 m1->m_len = NFSMSIZ(m1);
450 m2->m_next = m1;
451 m2 = m1;
25bf04c4 452 tl = mtod(m1, u_long *);
180c0ba3
KM
453 tlen = 0;
454 if (putsize) {
25bf04c4 455 *tl++ = txdr_unsigned(siz);
180c0ba3
KM
456 m1->m_len -= NFSX_UNSIGNED;
457 tlen = NFSX_UNSIGNED;
458 putsize = 0;
459 }
460 if (siz < m1->m_len) {
461 len = nfsm_rndup(siz);
462 xfer = siz;
463 if (xfer < len)
25bf04c4 464 *(tl+(xfer>>2)) = 0;
180c0ba3
KM
465 } else {
466 xfer = len = m1->m_len;
467 }
25bf04c4 468 bcopy(cp, (caddr_t) tl, xfer);
180c0ba3
KM
469 m1->m_len = len+tlen;
470 siz -= xfer;
471 cp += xfer;
472 }
473 *mb = m1;
474 *bpos = mtod(m1, caddr_t)+m1->m_len;
f0f1cbaa 475 return (0);
180c0ba3
KM
476}
477
478/*
479 * Called once to initialize data structures...
480 */
e16a8c9b 481nfs_init()
180c0ba3
KM
482{
483 register int i;
484
485 rpc_vers = txdr_unsigned(RPC_VER2);
486 rpc_call = txdr_unsigned(RPC_CALL);
487 rpc_reply = txdr_unsigned(RPC_REPLY);
488 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
489 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
490 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
491 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
492 nfs_vers = txdr_unsigned(NFS_VER2);
493 nfs_prog = txdr_unsigned(NFS_PROG);
494 nfs_true = txdr_unsigned(TRUE);
495 nfs_false = txdr_unsigned(FALSE);
496 /* Loop thru nfs procids */
497 for (i = 0; i < NFS_NPROCS; i++)
498 nfs_procids[i] = txdr_unsigned(i);
ffe6f482 499 /* Ensure async daemons disabled */
f0f1cbaa 500 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
ffe6f482 501 nfs_iodwant[i] = (struct proc *)0;
180c0ba3
KM
502 nfs_xdrneg1 = txdr_unsigned(-1);
503 nfs_nhinit(); /* Init the nfsnode table */
e8540f59 504 nfsrv_initcache(); /* Init the server request cache */
9238aa59 505 rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ);
f0f1cbaa
KM
506
507 /*
508 * Initialize reply list and start timer
509 */
510 nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
180c0ba3
KM
511 nfs_timer();
512}
513
514/*
515 * Fill in the rest of the rpc_unixauth and return it
516 */
517static char *nfs_unixauth(cr)
518 register struct ucred *cr;
519{
25bf04c4 520 register u_long *tl;
180c0ba3
KM
521 register int i;
522 int ngr;
523
524 /* Maybe someday there should be a cache of AUTH_SHORT's */
25bf04c4 525 if ((tl = rpc_uidp) == NULL) {
36c3043b 526#ifdef FILLINHOST
af2d4e11 527 i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED);
36c3043b 528#else
af2d4e11 529 i = 25*NFSX_UNSIGNED;
36c3043b 530#endif
25bf04c4
KM
531 MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK);
532 bzero((caddr_t)tl, i);
533 rpc_unixauth = (caddr_t)tl;
534 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
535 tl++; /* Fill in size later */
536 *tl++ = hostid;
36c3043b 537#ifdef FILLINHOST
25bf04c4 538 *tl++ = txdr_unsigned(hostnamelen);
180c0ba3 539 i = nfsm_rndup(hostnamelen);
25bf04c4
KM
540 bcopy(hostname, (caddr_t)tl, hostnamelen);
541 tl += (i>>2);
36c3043b 542#else
25bf04c4 543 *tl++ = 0;
36c3043b 544#endif
25bf04c4 545 rpc_uidp = tl;
180c0ba3 546 }
25bf04c4
KM
547 *tl++ = txdr_unsigned(cr->cr_uid);
548 *tl++ = txdr_unsigned(cr->cr_groups[0]);
af2d4e11 549 ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1);
25bf04c4 550 *tl++ = txdr_unsigned(ngr);
af2d4e11 551 for (i = 1; i <= ngr; i++)
25bf04c4 552 *tl++ = txdr_unsigned(cr->cr_groups[i]);
180c0ba3 553 /* And add the AUTH_NULL */
25bf04c4
KM
554 *tl++ = 0;
555 *tl = 0;
556 i = (((caddr_t)tl)-rpc_unixauth)-12;
557 tl = (u_long *)(rpc_unixauth+4);
558 *tl = txdr_unsigned(i);
f0f1cbaa 559 return (rpc_unixauth);
180c0ba3
KM
560}
561
562/*
563 * Attribute cache routines.
564 * nfs_loadattrcache() - loads or updates the cache contents from attributes
565 * that are on the mbuf list
566 * nfs_getattrcache() - returns valid attributes if found in cache, returns
567 * error otherwise
568 */
569
570/*
e16a8c9b 571 * Load the attribute cache (that lives in the nfsnode entry) with
180c0ba3
KM
572 * the values on the mbuf list and
573 * Iff vap not NULL
574 * copy the attributes to *vaper
575 */
610357c6
KM
576nfs_loadattrcache(vpp, mdp, dposp, vaper)
577 struct vnode **vpp;
180c0ba3
KM
578 struct mbuf **mdp;
579 caddr_t *dposp;
580 struct vattr *vaper;
581{
610357c6 582 register struct vnode *vp = *vpp;
180c0ba3 583 register struct vattr *vap;
9238aa59 584 register struct nfsv2_fattr *fp;
e16a8c9b 585 extern struct vnodeops spec_nfsv2nodeops;
610357c6 586 register struct nfsnode *np;
0bd503ad
KM
587 register long t1;
588 caddr_t dpos, cp2;
589 int error = 0;
590 struct mbuf *md;
e16a8c9b 591 enum vtype type;
1c89915d 592 u_short mode;
d4e5799e 593 long rdev;
e16a8c9b
KM
594 struct timeval mtime;
595 struct vnode *nvp;
180c0ba3
KM
596
597 md = *mdp;
598 dpos = *dposp;
599 t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
600 if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
601 return (error);
9238aa59 602 fp = (struct nfsv2_fattr *)cp2;
e16a8c9b 603 type = nfstov_type(fp->fa_type);
1c89915d
KM
604 mode = fxdr_unsigned(u_short, fp->fa_mode);
605 if (type == VNON)
606 type = IFTOVT(mode);
d4e5799e 607 rdev = fxdr_unsigned(long, fp->fa_rdev);
e16a8c9b
KM
608 fxdr_time(&fp->fa_mtime, &mtime);
609 /*
610 * If v_type == VNON it is a new node, so fill in the v_type,
611 * n_mtime fields. Check to see if it represents a special
612 * device, and if so, check for a possible alias. Once the
613 * correct vnode has been obtained, fill in the rest of the
614 * information.
615 */
180c0ba3 616 np = VTONFS(vp);
e16a8c9b 617 if (vp->v_type == VNON) {
d4e5799e
KM
618 if (type == VCHR && rdev == 0xffffffff)
619 vp->v_type = type = VFIFO;
620 else
621 vp->v_type = type;
28543a6e
KM
622 if (vp->v_type == VFIFO) {
623#ifdef FIFO
624 extern struct vnodeops fifo_nfsv2nodeops;
625 vp->v_op = &fifo_nfsv2nodeops;
626#else
627 return (EOPNOTSUPP);
628#endif /* FIFO */
629 }
e16a8c9b 630 if (vp->v_type == VCHR || vp->v_type == VBLK) {
e16a8c9b 631 vp->v_op = &spec_nfsv2nodeops;
d4e5799e 632 if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
e16a8c9b
KM
633 /*
634 * Reinitialize aliased node.
635 */
636 np = VTONFS(nvp);
637 np->n_vnode = nvp;
a8ddf3cc
KM
638 np->n_flag = 0;
639 nfs_lock(nvp);
e16a8c9b
KM
640 bcopy((caddr_t)&VTONFS(vp)->n_fh,
641 (caddr_t)&np->n_fh, NFSX_FH);
642 insque(np, nfs_hash(&np->n_fh));
643 np->n_attrstamp = 0;
644 np->n_sillyrename = (struct sillyrename *)0;
645 /*
610357c6 646 * Discard unneeded vnode and update actual one
e16a8c9b
KM
647 */
648 vput(vp);
f0f1cbaa 649 *vpp = nvp;
e16a8c9b
KM
650 }
651 }
652 np->n_mtime = mtime.tv_sec;
653 }
180c0ba3 654 vap = &np->n_vattr;
e16a8c9b 655 vap->va_type = type;
1c89915d 656 vap->va_mode = (mode & 07777);
9238aa59
RM
657 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
658 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
659 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
660 vap->va_size = fxdr_unsigned(u_long, fp->fa_size);
8986c97c 661 if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) {
9238aa59 662 np->n_size = vap->va_size;
8986c97c
KM
663 vnode_pager_setsize(vp, np->n_size);
664 }
8fae943a 665 vap->va_size_rsv = 0;
9238aa59 666 vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize);
d4e5799e
KM
667 vap->va_rdev = (dev_t)rdev;
668 vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE;
8fae943a 669 vap->va_bytes_rsv = 0;
a12d9e5a 670 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
9238aa59 671 vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid);
e8540f59
KM
672 vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec);
673 vap->va_atime.tv_usec = 0;
674 vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec);
e16a8c9b 675 vap->va_mtime = mtime;
e8540f59
KM
676 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec);
677 vap->va_ctime.tv_usec = 0;
678 vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec);
180c0ba3
KM
679 np->n_attrstamp = time.tv_sec;
680 *dposp = dpos;
681 *mdp = md;
9238aa59 682 if (vaper != NULL) {
180c0ba3 683 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
9238aa59
RM
684 if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size))
685 vaper->va_size = np->n_size;
686 }
180c0ba3
KM
687 return (0);
688}
689
690/*
691 * Check the time stamp
692 * If the cache is valid, copy contents to *vap and return 0
693 * otherwise return an error
694 */
695nfs_getattrcache(vp, vap)
696 register struct vnode *vp;
697 struct vattr *vap;
698{
699 register struct nfsnode *np;
700
701 np = VTONFS(vp);
702 if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
703 nfsstats.attrcache_hits++;
704 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
8986c97c 705 if ((np->n_flag & NMODIFIED) == 0) {
00b72154 706 np->n_size = vap->va_size;
8986c97c
KM
707 vnode_pager_setsize(vp, np->n_size);
708 } else if (np->n_size > vap->va_size)
9238aa59 709 vap->va_size = np->n_size;
180c0ba3
KM
710 return (0);
711 } else {
712 nfsstats.attrcache_misses++;
713 return (ENOENT);
714 }
715}
716
180c0ba3 717/*
f0f1cbaa 718 * Set up nameidata for a namei() call and do it
180c0ba3
KM
719 */
720nfs_namei(ndp, fhp, len, mdp, dposp)
721 register struct nameidata *ndp;
722 fhandle_t *fhp;
723 int len;
724 struct mbuf **mdp;
725 caddr_t *dposp;
726{
727 register int i, rem;
728 register struct mbuf *md;
729 register char *cp;
10bae9ee 730 struct vnode *dp;
180c0ba3 731 int flag;
f0f1cbaa 732 int error;
180c0ba3 733
d4e5799e 734 if ((ndp->ni_nameiop & HASBUF) == 0) {
10bae9ee 735 flag = ndp->ni_nameiop & OPMASK;
d4e5799e
KM
736 /*
737 * Copy the name from the mbuf list to the d_name field of ndp
738 * and set the various ndp fields appropriately.
739 */
740 cp = *dposp;
741 md = *mdp;
742 rem = mtod(md, caddr_t)+md->m_len-cp;
743 ndp->ni_hash = 0;
744 for (i = 0; i < len;) {
745 while (rem == 0) {
746 md = md->m_next;
747 if (md == NULL)
748 return (EBADRPC);
749 cp = mtod(md, caddr_t);
750 rem = md->m_len;
751 }
752 if (*cp == '\0' || *cp == '/')
180c0ba3 753 return (EINVAL);
d4e5799e
KM
754 if (*cp & 0200)
755 if ((*cp&0377) == ('/'|0200) || flag != DELETE)
756 return (EINVAL);
757 ndp->ni_dent.d_name[i++] = *cp;
758 ndp->ni_hash += (unsigned char)*cp * i;
759 cp++;
760 rem--;
761 }
762 *mdp = md;
763 *dposp = cp;
764 len = nfsm_rndup(len)-len;
765 if (len > 0) {
766 if (rem < len) {
767 if (error = nfs_adv(mdp, dposp, len, rem))
768 return (error);
769 } else
770 *dposp += len;
771 }
772 } else
773 i = len;
180c0ba3
KM
774 ndp->ni_namelen = i;
775 ndp->ni_dent.d_namlen = i;
776 ndp->ni_dent.d_name[i] = '\0';
d4e5799e 777 ndp->ni_segflg = UIO_SYSSPACE;
36c3043b 778 ndp->ni_pathlen = 1;
f0f1cbaa 779 ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
180c0ba3 780 ndp->ni_next = &ndp->ni_dent.d_name[i];
10bae9ee
KM
781 ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF | STARTDIR);
782 /*
783 * Extract and set starting directory.
784 */
f0f1cbaa 785 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred))
180c0ba3 786 return (error);
36c3043b 787 if (dp->v_type != VDIR) {
f0f1cbaa 788 vrele(dp);
36c3043b
KM
789 return (ENOTDIR);
790 }
10bae9ee 791 ndp->ni_startdir = dp;
180c0ba3 792 /*
f0f1cbaa 793 * And call namei() to do the real work
180c0ba3 794 */
25bf04c4 795 error = namei(ndp, curproc); /* XXX XXX XXX */
10bae9ee
KM
796 if (error || (ndp->ni_nameiop & SAVESTARTDIR) == 0)
797 vrele(dp);
180c0ba3
KM
798 return (error);
799}
800
801/*
802 * A fiddled version of m_adj() that ensures null fill to a long
803 * boundary and only trims off the back end
804 */
805nfsm_adj(mp, len, nul)
806 struct mbuf *mp;
807 register int len;
808 int nul;
809{
810 register struct mbuf *m;
811 register int count, i;
812 register char *cp;
813
814 /*
815 * Trim from tail. Scan the mbuf chain,
816 * calculating its length and finding the last mbuf.
817 * If the adjustment only affects this mbuf, then just
818 * adjust and return. Otherwise, rescan and truncate
819 * after the remaining size.
820 */
821 count = 0;
822 m = mp;
823 for (;;) {
824 count += m->m_len;
825 if (m->m_next == (struct mbuf *)0)
826 break;
827 m = m->m_next;
828 }
1f9b0aa5 829 if (m->m_len > len) {
180c0ba3
KM
830 m->m_len -= len;
831 if (nul > 0) {
832 cp = mtod(m, caddr_t)+m->m_len-nul;
833 for (i = 0; i < nul; i++)
834 *cp++ = '\0';
835 }
836 return;
837 }
838 count -= len;
839 if (count < 0)
840 count = 0;
841 /*
842 * Correct length for chain is "count".
843 * Find the mbuf with last data, adjust its length,
844 * and toss data from remaining mbufs on chain.
845 */
846 for (m = mp; m; m = m->m_next) {
847 if (m->m_len >= count) {
848 m->m_len = count;
849 if (nul > 0) {
850 cp = mtod(m, caddr_t)+m->m_len-nul;
851 for (i = 0; i < nul; i++)
852 *cp++ = '\0';
853 }
854 break;
855 }
856 count -= m->m_len;
857 }
858 while (m = m->m_next)
859 m->m_len = 0;
860}
861
862/*
863 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
864 * - look up fsid in mount list (if not found ret error)
865 * - check that it is exported
866 * - get vp by calling VFS_FHTOVP() macro
867 * - if not lockflag unlock it with VOP_UNLOCK()
f0f1cbaa 868 * - if cred->cr_uid == 0 set it to m_exroot
180c0ba3
KM
869 */
870nfsrv_fhtovp(fhp, lockflag, vpp, cred)
871 fhandle_t *fhp;
872 int lockflag;
873 struct vnode **vpp;
874 struct ucred *cred;
875{
876 register struct mount *mp;
180c0ba3
KM
877
878 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
879 return (ESTALE);
54fb9dc2 880 if ((mp->mnt_flag & MNT_EXPORTED) == 0)
180c0ba3
KM
881 return (EACCES);
882 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
883 return (ESTALE);
884 if (cred->cr_uid == 0)
54fb9dc2 885 cred->cr_uid = mp->mnt_exroot;
180c0ba3
KM
886 if (!lockflag)
887 VOP_UNLOCK(*vpp);
888 return (0);
889}
958df9fb
KM
890
891/*
892 * These two functions implement nfs rpc compression.
893 * The algorithm is a trivial run length encoding of '\0' bytes. The high
894 * order nibble of hex "e" is or'd with the number of zeroes - 2 in four
895 * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e"
896 * is byte stuffed.
897 * The compressed data is padded with 0x0 bytes to an even multiple of
898 * 4 bytes in length to avoid any weird long pointer alignments.
899 * If compression/uncompression is unsuccessful, the original mbuf list
900 * is returned.
901 * The first four bytes (the XID) are left uncompressed and the fifth
902 * byte is set to 0x1 for request and 0x2 for reply.
903 * An uncompressed RPC will always have the fifth byte == 0x0.
904 */
905struct mbuf *
906nfs_compress(m0)
907 struct mbuf *m0;
908{
909 register u_char ch, nextch;
910 register int i, rlelast;
911 register u_char *ip, *op;
912 register int ileft, oleft, noteof;
913 register struct mbuf *m, *om;
914 struct mbuf **mp, *retm;
915 int olen, clget;
916
917 i = rlelast = 0;
918 noteof = 1;
919 m = m0;
920 if (m->m_len < 12)
921 return (m0);
922 if (m->m_pkthdr.len >= MINCLSIZE)
923 clget = 1;
924 else
925 clget = 0;
926 ileft = m->m_len - 9;
927 ip = mtod(m, u_char *);
0b1d833e 928 MGETHDR(om, M_WAIT, MT_DATA);
958df9fb
KM
929 if (clget)
930 MCLGET(om, M_WAIT);
931 retm = om;
932 mp = &om->m_next;
933 olen = om->m_len = 5;
934 oleft = M_TRAILINGSPACE(om);
935 op = mtod(om, u_char *);
2799c55e 936 *((u_long *)op) = *((u_long *)ip);
958df9fb
KM
937 ip += 7;
938 op += 4;
939 *op++ = *ip++ + 1;
940 nextch = *ip++;
941 while (noteof) {
942 ch = nextch;
943 if (ileft == 0) {
944 do {
945 m = m->m_next;
946 } while (m && m->m_len == 0);
947 if (m) {
948 ileft = m->m_len;
949 ip = mtod(m, u_char *);
950 } else {
951 noteof = 0;
952 nextch = 0x1;
953 goto doit;
954 }
955 }
956 nextch = *ip++;
957 ileft--;
958doit:
959 if (ch == '\0') {
960 if (++i == NFSC_MAX || nextch != '\0') {
961 if (i < 2) {
962 nfscput('\0');
963 } else {
964 if (rlelast == i) {
965 nfscput('\0');
966 i--;
967 }
968 if (NFSCRLE(i) == (nextch & 0xff)) {
969 i--;
970 if (i < 2) {
971 nfscput('\0');
972 } else {
973 nfscput(NFSCRLE(i));
974 }
975 nfscput('\0');
976 rlelast = 0;
977 } else {
978 nfscput(NFSCRLE(i));
979 rlelast = i;
980 }
981 }
982 i = 0;
983 }
984 } else {
985 if ((ch & NFSCRL) == NFSCRL) {
986 nfscput(ch);
987 }
988 nfscput(ch);
989 i = rlelast = 0;
990 }
991 }
992 if (olen < m0->m_pkthdr.len) {
993 m_freem(m0);
994 if (i = (olen & 0x3)) {
995 i = 4 - i;
2799c55e 996 while (i-- > 0) {
958df9fb 997 nfscput('\0');
2799c55e 998 }
958df9fb
KM
999 }
1000 retm->m_pkthdr.len = olen;
2799c55e 1001 retm->m_pkthdr.rcvif = (struct ifnet *)0;
958df9fb
KM
1002 return (retm);
1003 } else {
1004 m_freem(retm);
1005 return (m0);
1006 }
1007}
1008
1009struct mbuf *
1010nfs_uncompress(m0)
1011 struct mbuf *m0;
1012{
1013 register u_char cp, nextcp, *ip, *op;
1014 register struct mbuf *m, *om;
1015 struct mbuf *retm, **mp;
1016 int i, j, noteof, clget, ileft, oleft, olen;
1017
1018 m = m0;
2799c55e
KM
1019 i = 0;
1020 while (m && i < MINCLSIZE) {
1021 i += m->m_len;
1022 m = m->m_next;
1023 }
1024 if (i < 6)
958df9fb 1025 return (m0);
2799c55e 1026 if (i >= MINCLSIZE)
958df9fb
KM
1027 clget = 1;
1028 else
1029 clget = 0;
2799c55e
KM
1030 m = m0;
1031 MGET(om, M_WAIT, MT_DATA);
958df9fb
KM
1032 if (clget)
1033 MCLGET(om, M_WAIT);
1034 olen = om->m_len = 8;
1035 oleft = M_TRAILINGSPACE(om);
1036 op = mtod(om, u_char *);
1037 retm = om;
1038 mp = &om->m_next;
1039 if (m->m_len >= 6) {
1040 ileft = m->m_len - 6;
1041 ip = mtod(m, u_char *);
1042 *((u_long *)op) = *((u_long *)ip);
1043 bzero(op + 4, 3);
1044 ip += 4;
1045 op += 7;
1046 if (*ip == '\0') {
1047 m_freem(om);
1048 return (m0);
1049 }
1050 *op++ = *ip++ - 1;
1051 cp = *ip++;
1052 } else {
1053 ileft = m->m_len;
1054 ip = mtod(m, u_char *);
1055 nfscget(*op++);
1056 nfscget(*op++);
1057 nfscget(*op++);
1058 nfscget(*op++);
1059 bzero(op, 3);
1060 op += 3;
1061 nfscget(*op);
1062 if (*op == '\0') {
1063 m_freem(om);
1064 return (m0);
1065 }
1066 (*op)--;
1067 op++;
1068 nfscget(cp);
1069 }
1070 noteof = 1;
1071 while (noteof) {
1072 if ((cp & NFSCRL) == NFSCRL) {
1073 nfscget(nextcp);
1074 if (cp == nextcp) {
1075 nfscput(cp);
1076 goto readit;
1077 } else {
1078 i = (cp & 0xf) + 2;
1079 for (j = 0; j < i; j++) {
1080 nfscput('\0');
1081 }
1082 cp = nextcp;
1083 }
1084 } else {
1085 nfscput(cp);
1086readit:
1087 nfscget(cp);
1088 }
1089 }
1090 m_freem(m0);
2799c55e 1091 if (i = (olen & 0x3))
958df9fb 1092 om->m_len -= i;
958df9fb
KM
1093 return (retm);
1094}