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(nd, NFSMNT_MDSSESSION(nmp),
207 nfs_bigreply[procnum]);
209 nfsv4_setsequence(nd, sep,
210 nfs_bigreply[procnum]);
212 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
213 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
214 *tl = txdr_unsigned(NFSV4OP_PUTFH);
215 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
216 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
217 == 2 && procnum != NFSPROC_WRITEDS &&
218 procnum != NFSPROC_COMMITDS) {
219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
220 *tl = txdr_unsigned(NFSV4OP_GETATTR);
221 NFSWCCATTR_ATTRBIT(&attrbits);
222 (void) nfsrv_putattrbit(nd, &attrbits);
223 nd->nd_flag |= ND_V4WCCATTR;
226 if (procnum != NFSPROC_RENEW ||
227 (nd->nd_flag & ND_NFSV41) == 0) {
228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
229 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
232 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
234 if (procnum < NFSV4_NPROCS)
235 NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
240 * copies a uio scatter/gather list to an mbuf chain.
241 * NOTE: can ony handle iovcnt == 1
244 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
247 struct mbuf *mp, *mp2;
248 int xfer, left, mlen;
249 int uiosiz, clflg, rem;
252 KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
254 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
258 rem = NFSM_RNDUP(siz) - siz;
259 mp = mp2 = nd->nd_mb;
261 left = uiop->uio_iov->iov_len;
262 uiocp = uiop->uio_iov->iov_base;
267 mlen = M_TRAILINGSPACE(mp);
270 NFSMCLGET(mp, M_WAITOK);
274 mbuf_setnext(mp2, mp);
276 mlen = M_TRAILINGSPACE(mp);
278 xfer = (left > mlen) ? mlen : left;
281 if (uiop->uio_iov->iov_op != NULL)
282 (*(uiop->uio_iov->iov_op))
283 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
287 if (uiop->uio_segflg == UIO_SYSSPACE)
288 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
291 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
292 + mbuf_len(mp), xfer);
293 mbuf_setlen(mp, mbuf_len(mp) + xfer);
296 uiop->uio_offset += xfer;
297 uiop->uio_resid -= xfer;
299 tcp = (char *)uiop->uio_iov->iov_base;
301 uiop->uio_iov->iov_base = (void *)tcp;
302 uiop->uio_iov->iov_len -= uiosiz;
306 if (rem > M_TRAILINGSPACE(mp)) {
309 mbuf_setnext(mp2, mp);
311 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
312 for (left = 0; left < rem; left++)
314 mbuf_setlen(mp, mbuf_len(mp) + rem);
317 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
323 * Load vnode attributes from the xdr file attributes.
324 * Returns EBADRPC if they can't be parsed, 0 otherwise.
327 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
329 struct nfs_fattr *fp;
332 if (nd->nd_flag & ND_NFSV4) {
333 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
334 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
335 } else if (nd->nd_flag & ND_NFSV3) {
336 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
337 nap->na_type = nfsv34tov_type(fp->fa_type);
338 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
339 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
340 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
341 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
342 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
343 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
344 nap->na_size = fxdr_hyper(&fp->fa3_size);
345 nap->na_blocksize = NFS_FABLKSIZE;
346 nap->na_bytes = fxdr_hyper(&fp->fa3_used);
347 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
348 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
349 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
350 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
354 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
355 nap->na_type = nfsv2tov_type(fp->fa_type);
356 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
357 if (nap->na_type == VNON || nap->na_type == VREG)
358 nap->na_type = IFTOVT(nap->na_mode);
359 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
362 * Really ugly NFSv2 kludge.
364 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
365 nap->na_type = VFIFO;
366 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
367 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
368 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
369 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
370 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
372 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
374 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
375 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
376 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
378 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
379 fp->fa2_ctime.nfsv2_sec);
380 nap->na_ctime.tv_nsec = 0;
381 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
389 * This function finds the directory cookie that corresponds to the
390 * logical byte offset given.
392 APPLESTATIC nfsuint64 *
393 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
395 struct nfsdmap *dp, *dp2;
398 pos = off / NFS_DIRBLKSIZ;
400 KASSERT(!add, ("nfs getcookie add at 0"));
401 return (&nfs_nullcookie);
404 dp = LIST_FIRST(&np->n_cookies);
407 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
408 M_NFSDIROFF, M_WAITOK);
409 dp->ndm_eocookie = 0;
410 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
414 while (pos >= NFSNUMCOOKIES) {
415 pos -= NFSNUMCOOKIES;
416 if (LIST_NEXT(dp, ndm_list) != NULL) {
417 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
418 pos >= dp->ndm_eocookie)
420 dp = LIST_NEXT(dp, ndm_list);
422 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
423 M_NFSDIROFF, M_WAITOK);
424 dp2->ndm_eocookie = 0;
425 LIST_INSERT_AFTER(dp, dp2, ndm_list);
430 if (pos >= dp->ndm_eocookie) {
432 dp->ndm_eocookie = pos + 1;
436 return (&dp->ndm_cookies[pos]);
440 * Gets a file handle out of an nfs reply sent to the client and returns
441 * the file handle and the file's attributes.
442 * For V4, it assumes that Getfh and Getattr Op's results are here.
445 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
446 struct nfsvattr *nap, int *attrflagp)
449 int error = 0, flag = 1;
454 * First get the file handle and vnode.
456 if (nd->nd_flag & ND_NFSV3) {
457 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
458 flag = fxdr_unsigned(int, *tl);
459 } else if (nd->nd_flag & ND_NFSV4) {
460 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
463 error = nfsm_getfh(nd, nfhpp);
469 * Now, get the attributes.
471 if (nd->nd_flag & ND_NFSV4) {
472 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
473 } else if (nd->nd_flag & ND_NFSV3) {
474 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
476 flag = fxdr_unsigned(int, *tl);
477 } else if (fxdr_unsigned(int, *tl)) {
478 error = nfsm_advance(nd, NFSX_V3FATTR, -1);
484 error = nfsm_loadattr(nd, nap);
493 * Put a state Id in the mbuf list.
496 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
500 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
501 if (flag == NFSSTATEID_PUTALLZERO) {
506 } else if (flag == NFSSTATEID_PUTALLONE) {
507 st->seqid = 0xffffffff;
508 st->other[0] = 0xffffffff;
509 st->other[1] = 0xffffffff;
510 st->other[2] = 0xffffffff;
511 } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
513 st->other[0] = stateidp->other[0];
514 st->other[1] = stateidp->other[1];
515 st->other[2] = stateidp->other[2];
517 st->seqid = stateidp->seqid;
518 st->other[0] = stateidp->other[0];
519 st->other[1] = stateidp->other[1];
520 st->other[2] = stateidp->other[2];
525 * Initialize the owner/delegation sleep lock.
528 nfscl_lockinit(struct nfsv4lock *lckp)
531 lckp->nfslock_usecnt = 0;
532 lckp->nfslock_lock = 0;
536 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
537 * thread for each posix process in the kernel.)
540 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
545 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
550 * Release an exclusive lock.
553 nfscl_lockunlock(struct nfsv4lock *lckp)
556 nfsv4_unlock(lckp, 0);
560 * Called to derefernce a lock on a stateid (delegation or open owner).
563 nfscl_lockderef(struct nfsv4lock *lckp)
567 lckp->nfslock_usecnt--;
568 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
569 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
570 wakeup((caddr_t)lckp);