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 nfsstats newnfsstats;
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, 3, "Open", 4, },
70 { NFSV4OP_CREATE, 3, "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);
222 NFSWCCATTR_ATTRBIT(&attrbits);
223 (void) nfsrv_putattrbit(nd, &attrbits);
224 nd->nd_flag |= ND_V4WCCATTR;
227 if (procnum != NFSPROC_RENEW ||
228 (nd->nd_flag & ND_NFSV41) == 0) {
229 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
230 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
233 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
235 if (procnum < NFSV4_NPROCS)
236 NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
241 * copies a uio scatter/gather list to an mbuf chain.
242 * NOTE: can ony handle iovcnt == 1
245 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
248 struct mbuf *mp, *mp2;
249 int xfer, left, mlen;
250 int uiosiz, clflg, rem;
253 KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
255 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
259 rem = NFSM_RNDUP(siz) - siz;
260 mp = mp2 = nd->nd_mb;
262 left = uiop->uio_iov->iov_len;
263 uiocp = uiop->uio_iov->iov_base;
268 mlen = M_TRAILINGSPACE(mp);
271 NFSMCLGET(mp, M_WAITOK);
275 mbuf_setnext(mp2, mp);
277 mlen = M_TRAILINGSPACE(mp);
279 xfer = (left > mlen) ? mlen : left;
282 if (uiop->uio_iov->iov_op != NULL)
283 (*(uiop->uio_iov->iov_op))
284 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
288 if (uiop->uio_segflg == UIO_SYSSPACE)
289 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
292 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
293 + mbuf_len(mp), xfer);
294 mbuf_setlen(mp, mbuf_len(mp) + xfer);
297 uiop->uio_offset += xfer;
298 uiop->uio_resid -= xfer;
300 tcp = (char *)uiop->uio_iov->iov_base;
302 uiop->uio_iov->iov_base = (void *)tcp;
303 uiop->uio_iov->iov_len -= uiosiz;
307 if (rem > M_TRAILINGSPACE(mp)) {
310 mbuf_setnext(mp2, mp);
312 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
313 for (left = 0; left < rem; left++)
315 mbuf_setlen(mp, mbuf_len(mp) + rem);
318 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
324 * Load vnode attributes from the xdr file attributes.
325 * Returns EBADRPC if they can't be parsed, 0 otherwise.
328 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
330 struct nfs_fattr *fp;
333 if (nd->nd_flag & ND_NFSV4) {
334 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
335 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
336 } else if (nd->nd_flag & ND_NFSV3) {
337 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
338 nap->na_type = nfsv34tov_type(fp->fa_type);
339 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
340 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
341 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
342 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
343 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
344 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
345 nap->na_size = fxdr_hyper(&fp->fa3_size);
346 nap->na_blocksize = NFS_FABLKSIZE;
347 nap->na_bytes = fxdr_hyper(&fp->fa3_used);
348 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
349 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
350 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
351 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
355 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
356 nap->na_type = nfsv2tov_type(fp->fa_type);
357 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
358 if (nap->na_type == VNON || nap->na_type == VREG)
359 nap->na_type = IFTOVT(nap->na_mode);
360 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
363 * Really ugly NFSv2 kludge.
365 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
366 nap->na_type = VFIFO;
367 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
368 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
369 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
370 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
371 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
373 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
375 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
376 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
377 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
379 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
380 fp->fa2_ctime.nfsv2_sec);
381 nap->na_ctime.tv_nsec = 0;
382 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
390 * This function finds the directory cookie that corresponds to the
391 * logical byte offset given.
393 APPLESTATIC nfsuint64 *
394 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
396 struct nfsdmap *dp, *dp2;
399 pos = off / NFS_DIRBLKSIZ;
401 KASSERT(!add, ("nfs getcookie add at 0"));
402 return (&nfs_nullcookie);
405 dp = LIST_FIRST(&np->n_cookies);
408 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
409 M_NFSDIROFF, M_WAITOK);
410 dp->ndm_eocookie = 0;
411 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
415 while (pos >= NFSNUMCOOKIES) {
416 pos -= NFSNUMCOOKIES;
417 if (LIST_NEXT(dp, ndm_list) != NULL) {
418 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
419 pos >= dp->ndm_eocookie)
421 dp = LIST_NEXT(dp, ndm_list);
423 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
424 M_NFSDIROFF, M_WAITOK);
425 dp2->ndm_eocookie = 0;
426 LIST_INSERT_AFTER(dp, dp2, ndm_list);
431 if (pos >= dp->ndm_eocookie) {
433 dp->ndm_eocookie = pos + 1;
437 return (&dp->ndm_cookies[pos]);
441 * Gets a file handle out of an nfs reply sent to the client and returns
442 * the file handle and the file's attributes.
443 * For V4, it assumes that Getfh and Getattr Op's results are here.
446 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
447 struct nfsvattr *nap, int *attrflagp)
450 int error = 0, flag = 1;
455 * First get the file handle and vnode.
457 if (nd->nd_flag & ND_NFSV3) {
458 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
459 flag = fxdr_unsigned(int, *tl);
460 } else if (nd->nd_flag & ND_NFSV4) {
461 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
464 error = nfsm_getfh(nd, nfhpp);
470 * Now, get the attributes.
472 if (nd->nd_flag & ND_NFSV4) {
473 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
474 } else if (nd->nd_flag & ND_NFSV3) {
475 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
477 flag = fxdr_unsigned(int, *tl);
478 } else if (fxdr_unsigned(int, *tl)) {
479 error = nfsm_advance(nd, NFSX_V3FATTR, -1);
485 error = nfsm_loadattr(nd, nap);
494 * Put a state Id in the mbuf list.
497 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
501 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
502 if (flag == NFSSTATEID_PUTALLZERO) {
507 } else if (flag == NFSSTATEID_PUTALLONE) {
508 st->seqid = 0xffffffff;
509 st->other[0] = 0xffffffff;
510 st->other[1] = 0xffffffff;
511 st->other[2] = 0xffffffff;
512 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
514 st->other[0] = stateidp->other[0];
515 st->other[1] = stateidp->other[1];
516 st->other[2] = stateidp->other[2];
518 st->seqid = stateidp->seqid;
519 st->other[0] = stateidp->other[0];
520 st->other[1] = stateidp->other[1];
521 st->other[2] = stateidp->other[2];
526 * Initialize the owner/delegation sleep lock.
529 nfscl_lockinit(struct nfsv4lock *lckp)
532 lckp->nfslock_usecnt = 0;
533 lckp->nfslock_lock = 0;
537 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
538 * thread for each posix process in the kernel.)
541 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
546 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
551 * Release an exclusive lock.
554 nfscl_lockunlock(struct nfsv4lock *lckp)
557 nfsv4_unlock(lckp, 0);
561 * Called to derefernce a lock on a stateid (delegation or open owner).
564 nfscl_lockderef(struct nfsv4lock *lckp)
568 lckp->nfslock_usecnt--;
569 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
570 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
571 wakeup((caddr_t)lckp);