2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
38 * These functions support the macros and help fiddle mbuf chains for
39 * the nfs op functions. They do things like create the rpc header and
40 * copy data between mbuf chains and uio lists.
43 #include <fs/nfs/nfsport.h>
45 extern struct nfsstatsv1 nfsstatsv1;
46 extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
47 extern int ncl_mbuf_mlen;
48 extern enum vtype newnv2tov_type[8];
49 extern enum vtype nv34tov_type[8];
50 extern int nfs_bigreply[NFSV41_NPROCS];
52 #endif /* !APPLEKEXT */
54 static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
60 } nfsv4_opmap[NFSV41_NPROCS] = {
62 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
63 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
64 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
65 { NFSV4OP_ACCESS, 2, "Access", 6, },
66 { NFSV4OP_READLINK, 2, "Readlink", 8, },
67 { NFSV4OP_READ, 1, "Read", 4, },
68 { NFSV4OP_WRITE, 2, "Write", 5, },
69 { NFSV4OP_OPEN, 5, "Open", 4, },
70 { NFSV4OP_CREATE, 5, "Create", 6, },
71 { NFSV4OP_CREATE, 1, "Create", 6, },
72 { NFSV4OP_CREATE, 3, "Create", 6, },
73 { NFSV4OP_REMOVE, 1, "Remove", 6, },
74 { NFSV4OP_REMOVE, 1, "Remove", 6, },
75 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
76 { NFSV4OP_SAVEFH, 4, "Link", 4, },
77 { NFSV4OP_READDIR, 2, "Readdir", 7, },
78 { NFSV4OP_READDIR, 2, "Readdir", 7, },
79 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
80 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
81 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
82 { NFSV4OP_COMMIT, 2, "Commit", 6, },
83 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
84 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
85 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
86 { NFSV4OP_LOCK, 1, "Lock", 4, },
87 { NFSV4OP_LOCKU, 1, "LockU", 5, },
88 { NFSV4OP_OPEN, 2, "Open", 4, },
89 { NFSV4OP_CLOSE, 1, "Close", 5, },
90 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
91 { NFSV4OP_LOCKT, 1, "LockT", 5, },
92 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
93 { NFSV4OP_RENEW, 1, "Renew", 5, },
94 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
95 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
96 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
97 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
98 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
99 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
100 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
101 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
102 { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
103 { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
104 { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
105 { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
106 { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
107 { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
108 { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
109 { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
110 { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
111 { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
112 { NFSV4OP_WRITE, 1, "WriteDS", 7, },
113 { NFSV4OP_READ, 1, "ReadDS", 6, },
114 { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
118 * NFS RPCS that have large request message size.
120 static int nfs_bigrequest[NFSV41_NPROCS] = {
121 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 0, 0, 0, 0, 0, 0, 1, 0, 0
127 * Start building a request. Mostly just put the first file handle in
131 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
132 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep)
137 nfsattrbit_t attrbits;
140 * First, fill in some of the fields of nd.
142 nd->nd_slotseq = NULL;
143 if (NFSHASNFSV4(nmp)) {
144 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
145 if (NFSHASNFSV4N(nmp))
146 nd->nd_flag |= ND_NFSV41;
147 } else if (NFSHASNFSV3(nmp))
148 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
150 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
151 nd->nd_procnum = procnum;
155 * Get the first mbuf for the request.
157 if (nfs_bigrequest[procnum])
158 NFSMCLGET(mb, M_WAITOK);
162 nd->nd_mreq = nd->nd_mb = mb;
163 nd->nd_bpos = NFSMTOD(mb, caddr_t);
166 * And fill the first file handle into the request.
168 if (nd->nd_flag & ND_NFSV4) {
169 opcnt = nfsv4_opmap[procnum].opcnt +
170 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
171 if ((nd->nd_flag & ND_NFSV41) != 0) {
172 opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
173 if (procnum == NFSPROC_RENEW)
175 * For the special case of Renew, just do a
179 else if (procnum == NFSPROC_WRITEDS ||
180 procnum == NFSPROC_COMMITDS)
182 * For the special case of a Writeor Commit to
183 * a DS, the opcnt == 3, for Sequence, PutFH,
189 * What should the tag really be?
191 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
192 nfsv4_opmap[procnum].taglen);
193 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
194 if ((nd->nd_flag & ND_NFSV41) != 0)
195 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
197 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
200 *tl = txdr_unsigned(opcnt);
201 if ((nd->nd_flag & ND_NFSV41) != 0 &&
202 nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
203 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
204 *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
206 nfsv4_setsequence(nmp, nd,
207 NFSMNT_MDSSESSION(nmp),
208 nfs_bigreply[procnum]);
210 nfsv4_setsequence(nmp, nd, sep,
211 nfs_bigreply[procnum]);
213 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
215 *tl = txdr_unsigned(NFSV4OP_PUTFH);
216 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
217 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
218 == 2 && procnum != NFSPROC_WRITEDS &&
219 procnum != NFSPROC_COMMITDS) {
220 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
221 *tl = txdr_unsigned(NFSV4OP_GETATTR);
223 * For Lookup Ops, we want all the directory
224 * attributes, so we can load the name cache.
226 if (procnum == NFSPROC_LOOKUP ||
227 procnum == NFSPROC_LOOKUPP)
228 NFSGETATTR_ATTRBIT(&attrbits);
230 NFSWCCATTR_ATTRBIT(&attrbits);
231 nd->nd_flag |= ND_V4WCCATTR;
233 (void) nfsrv_putattrbit(nd, &attrbits);
236 if (procnum != NFSPROC_RENEW ||
237 (nd->nd_flag & ND_NFSV41) == 0) {
238 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
239 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
242 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
244 if (procnum < NFSV41_NPROCS)
245 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
250 * copies a uio scatter/gather list to an mbuf chain.
251 * NOTE: can ony handle iovcnt == 1
254 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
257 struct mbuf *mp, *mp2;
258 int xfer, left, mlen;
259 int uiosiz, clflg, rem;
262 KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
264 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
268 rem = NFSM_RNDUP(siz) - siz;
269 mp = mp2 = nd->nd_mb;
271 left = uiop->uio_iov->iov_len;
272 uiocp = uiop->uio_iov->iov_base;
277 mlen = M_TRAILINGSPACE(mp);
280 NFSMCLGET(mp, M_WAITOK);
284 mbuf_setnext(mp2, mp);
286 mlen = M_TRAILINGSPACE(mp);
288 xfer = (left > mlen) ? mlen : left;
291 if (uiop->uio_iov->iov_op != NULL)
292 (*(uiop->uio_iov->iov_op))
293 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
297 if (uiop->uio_segflg == UIO_SYSSPACE)
298 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
301 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
302 + mbuf_len(mp), xfer);
303 mbuf_setlen(mp, mbuf_len(mp) + xfer);
306 uiop->uio_offset += xfer;
307 uiop->uio_resid -= xfer;
309 tcp = (char *)uiop->uio_iov->iov_base;
311 uiop->uio_iov->iov_base = (void *)tcp;
312 uiop->uio_iov->iov_len -= uiosiz;
316 if (rem > M_TRAILINGSPACE(mp)) {
319 mbuf_setnext(mp2, mp);
321 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
322 for (left = 0; left < rem; left++)
324 mbuf_setlen(mp, mbuf_len(mp) + rem);
327 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
333 * Load vnode attributes from the xdr file attributes.
334 * Returns EBADRPC if they can't be parsed, 0 otherwise.
337 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
339 struct nfs_fattr *fp;
342 if (nd->nd_flag & ND_NFSV4) {
343 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
344 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
345 } else if (nd->nd_flag & ND_NFSV3) {
346 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
347 nap->na_type = nfsv34tov_type(fp->fa_type);
348 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
349 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
350 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
351 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
352 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
353 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
354 nap->na_size = fxdr_hyper(&fp->fa3_size);
355 nap->na_blocksize = NFS_FABLKSIZE;
356 nap->na_bytes = fxdr_hyper(&fp->fa3_used);
357 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
358 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
359 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
360 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
364 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
365 nap->na_type = nfsv2tov_type(fp->fa_type);
366 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
367 if (nap->na_type == VNON || nap->na_type == VREG)
368 nap->na_type = IFTOVT(nap->na_mode);
369 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
372 * Really ugly NFSv2 kludge.
374 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
375 nap->na_type = VFIFO;
376 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
377 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
378 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
379 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
380 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
382 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
384 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
385 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
386 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
388 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
389 fp->fa2_ctime.nfsv2_sec);
390 nap->na_ctime.tv_nsec = 0;
391 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
399 * This function finds the directory cookie that corresponds to the
400 * logical byte offset given.
402 APPLESTATIC nfsuint64 *
403 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
405 struct nfsdmap *dp, *dp2;
408 pos = off / NFS_DIRBLKSIZ;
410 KASSERT(!add, ("nfs getcookie add at 0"));
411 return (&nfs_nullcookie);
414 dp = LIST_FIRST(&np->n_cookies);
417 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
418 M_NFSDIROFF, M_WAITOK);
419 dp->ndm_eocookie = 0;
420 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
424 while (pos >= NFSNUMCOOKIES) {
425 pos -= NFSNUMCOOKIES;
426 if (LIST_NEXT(dp, ndm_list) != NULL) {
427 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
428 pos >= dp->ndm_eocookie)
430 dp = LIST_NEXT(dp, ndm_list);
432 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
433 M_NFSDIROFF, M_WAITOK);
434 dp2->ndm_eocookie = 0;
435 LIST_INSERT_AFTER(dp, dp2, ndm_list);
440 if (pos >= dp->ndm_eocookie) {
442 dp->ndm_eocookie = pos + 1;
446 return (&dp->ndm_cookies[pos]);
450 * Gets a file handle out of an nfs reply sent to the client and returns
451 * the file handle and the file's attributes.
452 * For V4, it assumes that Getfh and Getattr Op's results are here.
455 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
456 struct nfsvattr *nap, int *attrflagp)
459 int error = 0, flag = 1;
464 * First get the file handle and vnode.
466 if (nd->nd_flag & ND_NFSV3) {
467 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
468 flag = fxdr_unsigned(int, *tl);
469 } else if (nd->nd_flag & ND_NFSV4) {
470 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
473 error = nfsm_getfh(nd, nfhpp);
479 * Now, get the attributes.
481 if (nd->nd_flag & ND_NFSV4) {
482 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
483 } else if (nd->nd_flag & ND_NFSV3) {
484 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
486 flag = fxdr_unsigned(int, *tl);
487 } else if (fxdr_unsigned(int, *tl)) {
488 error = nfsm_advance(nd, NFSX_V3FATTR, -1);
494 error = nfsm_loadattr(nd, nap);
503 * Put a state Id in the mbuf list.
506 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
510 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
511 if (flag == NFSSTATEID_PUTALLZERO) {
516 } else if (flag == NFSSTATEID_PUTALLONE) {
517 st->seqid = 0xffffffff;
518 st->other[0] = 0xffffffff;
519 st->other[1] = 0xffffffff;
520 st->other[2] = 0xffffffff;
521 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
523 st->other[0] = stateidp->other[0];
524 st->other[1] = stateidp->other[1];
525 st->other[2] = stateidp->other[2];
527 st->seqid = stateidp->seqid;
528 st->other[0] = stateidp->other[0];
529 st->other[1] = stateidp->other[1];
530 st->other[2] = stateidp->other[2];
535 * Initialize the owner/delegation sleep lock.
538 nfscl_lockinit(struct nfsv4lock *lckp)
541 lckp->nfslock_usecnt = 0;
542 lckp->nfslock_lock = 0;
546 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
547 * thread for each posix process in the kernel.)
550 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
555 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
560 * Release an exclusive lock.
563 nfscl_lockunlock(struct nfsv4lock *lckp)
566 nfsv4_unlock(lckp, 0);
570 * Called to derefernce a lock on a stateid (delegation or open owner).
573 nfscl_lockderef(struct nfsv4lock *lckp)
577 lckp->nfslock_usecnt--;
578 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
579 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
580 wakeup((caddr_t)lckp);