1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
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.
41 */
42 #ifndef APPLEKEXT
43 #include <fs/nfs/nfsport.h>
44
45 extern struct nfsstats newnfsstats;
46 extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
47 extern int ncl_mbuf_mlen;
48 extern enum vtype newnv2tov_type[8];
49 extern enum vtype nv34tov_type[8];
50 NFSCLSTATEMUTEX;
51 #endif /* !APPLEKEXT */
52
53 static nfsuint64 nfs_nullcookie = {{ 0, 0 }};
54 static struct {
55 int op;
56 int opcnt;
57 const u_char *tag;
58 int taglen;
59 } nfsv4_opmap[NFS_NPROCS] = {
60 { 0, 1, "Null", 4 },
61 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
62 { NFSV4OP_SETATTR, 2, "Setattr", 7, },
63 { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
64 { NFSV4OP_ACCESS, 2, "Access", 6, },
65 { NFSV4OP_READLINK, 2, "Readlink", 8, },
66 { NFSV4OP_READ, 1, "Read", 4, },
67 { NFSV4OP_WRITE, 2, "Write", 5, },
68 { NFSV4OP_OPEN, 5, "Open", 4, },
69 { NFSV4OP_CREATE, 5, "Create", 6, },
70 { NFSV4OP_CREATE, 1, "Create", 6, },
71 { NFSV4OP_CREATE, 3, "Create", 6, },
72 { NFSV4OP_REMOVE, 1, "Remove", 6, },
73 { NFSV4OP_REMOVE, 1, "Remove", 6, },
74 { NFSV4OP_SAVEFH, 5, "Rename", 6, },
75 { NFSV4OP_SAVEFH, 4, "Link", 4, },
76 { NFSV4OP_READDIR, 2, "Readdir", 7, },
77 { NFSV4OP_READDIR, 2, "Readdir", 7, },
78 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
79 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
80 { NFSV4OP_GETATTR, 1, "Getattr", 7, },
81 { NFSV4OP_COMMIT, 2, "Commit", 6, },
82 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
83 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
84 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
85 { NFSV4OP_LOCK, 1, "Lock", 4, },
86 { NFSV4OP_LOCKU, 1, "LockU", 5, },
87 { NFSV4OP_OPEN, 2, "Open", 4, },
88 { NFSV4OP_CLOSE, 1, "Close", 5, },
89 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
90 { NFSV4OP_LOCKT, 1, "LockT", 5, },
91 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
92 { NFSV4OP_RENEW, 1, "Renew", 5, },
93 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
94 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
95 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
96 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
97 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
98 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
99 { NFSV4OP_GETATTR, 1, "Getacl", 6, },
100 { NFSV4OP_SETATTR, 1, "Setacl", 6, },
101 };
102
103
104 /*
105 * NFS RPCS that have large request message size.
106 */
107 static int nfs_bigrequest[NFS_NPROCS] = {
108 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110 };
111
112 /*
113 * Start building a request. Mostly just put the first file handle in
114 * place.
115 */
116 APPLESTATIC void
117 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
118 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp)
119 {
120 struct mbuf *mb;
121 u_int32_t *tl;
122 int opcnt;
123 nfsattrbit_t attrbits;
124
125 /*
126 * First, fill in some of the fields of nd.
127 */
128 if (NFSHASNFSV4(nmp))
129 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
130 else if (NFSHASNFSV3(nmp))
131 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
132 else
133 nd->nd_flag = ND_NFSV2 | ND_NFSCL;
134 nd->nd_procnum = procnum;
135 nd->nd_repstat = 0;
136
137 /*
138 * Get the first mbuf for the request.
139 */
140 if (nfs_bigrequest[procnum])
141 NFSMCLGET(mb, M_WAIT);
142 else
143 NFSMGET(mb);
144 mbuf_setlen(mb, 0);
145 nd->nd_mreq = nd->nd_mb = mb;
146 nd->nd_bpos = NFSMTOD(mb, caddr_t);
147
148 /*
149 * And fill the first file handle into the request.
150 */
151 if (nd->nd_flag & ND_NFSV4) {
152 opcnt = nfsv4_opmap[procnum].opcnt +
153 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
154 /*
155 * What should the tag really be?
156 */
157 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
158 nfsv4_opmap[procnum].taglen);
159 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
160 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
161 if (opcntpp != NULL)
162 *opcntpp = tl;
163 *tl++ = txdr_unsigned(opcnt);
164 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
165 *tl = txdr_unsigned(NFSV4OP_PUTFH);
166 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
167 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh==2){
168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
169 *tl = txdr_unsigned(NFSV4OP_GETATTR);
170 /*
171 * For Lookup Ops, we want all the directory
172 * attributes, so we can load the name cache.
173 */
174 if (procnum == NFSPROC_LOOKUP ||
175 procnum == NFSPROC_LOOKUPP)
176 NFSGETATTR_ATTRBIT(&attrbits);
177 else {
178 NFSWCCATTR_ATTRBIT(&attrbits);
179 nd->nd_flag |= ND_V4WCCATTR;
180 }
181 (void) nfsrv_putattrbit(nd, &attrbits);
182 }
183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
184 }
185 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
186 } else {
187 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
188 }
189 NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
190 }
191
192 #ifndef APPLE
193 /*
194 * copies a uio scatter/gather list to an mbuf chain.
195 * NOTE: can ony handle iovcnt == 1
196 */
197 APPLESTATIC void
198 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
199 {
200 char *uiocp;
201 struct mbuf *mp, *mp2;
202 int xfer, left, mlen;
203 int uiosiz, clflg, rem;
204 char *cp, *tcp;
205
206 KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
207
208 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
209 clflg = 1;
210 else
211 clflg = 0;
212 rem = NFSM_RNDUP(siz) - siz;
213 mp = mp2 = nd->nd_mb;
214 while (siz > 0) {
215 left = uiop->uio_iov->iov_len;
216 uiocp = uiop->uio_iov->iov_base;
217 if (left > siz)
218 left = siz;
219 uiosiz = left;
220 while (left > 0) {
221 mlen = M_TRAILINGSPACE(mp);
222 if (mlen == 0) {
223 if (clflg)
224 NFSMCLGET(mp, M_WAIT);
225 else
226 NFSMGET(mp);
227 mbuf_setlen(mp, 0);
228 mbuf_setnext(mp2, mp);
229 mp2 = mp;
230 mlen = M_TRAILINGSPACE(mp);
231 }
232 xfer = (left > mlen) ? mlen : left;
233 #ifdef notdef
234 /* Not Yet.. */
235 if (uiop->uio_iov->iov_op != NULL)
236 (*(uiop->uio_iov->iov_op))
237 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
238 xfer);
239 else
240 #endif
241 if (uiop->uio_segflg == UIO_SYSSPACE)
242 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
243 xfer);
244 else
245 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
246 + mbuf_len(mp), xfer);
247 mbuf_setlen(mp, mbuf_len(mp) + xfer);
248 left -= xfer;
249 uiocp += xfer;
250 uiop->uio_offset += xfer;
251 uiop->uio_resid -= xfer;
252 }
253 tcp = (char *)uiop->uio_iov->iov_base;
254 tcp += uiosiz;
255 uiop->uio_iov->iov_base = (void *)tcp;
256 uiop->uio_iov->iov_len -= uiosiz;
257 siz -= uiosiz;
258 }
259 if (rem > 0) {
260 if (rem > M_TRAILINGSPACE(mp)) {
261 NFSMGET(mp);
262 mbuf_setlen(mp, 0);
263 mbuf_setnext(mp2, mp);
264 }
265 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
266 for (left = 0; left < rem; left++)
267 *cp++ = '\0';
268 mbuf_setlen(mp, mbuf_len(mp) + rem);
269 nd->nd_bpos = cp;
270 } else
271 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
272 nd->nd_mb = mp;
273 }
274 #endif /* !APPLE */
275
276 /*
277 * Load vnode attributes from the xdr file attributes.
278 * Returns EBADRPC if they can't be parsed, 0 otherwise.
279 */
280 APPLESTATIC int
281 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
282 {
283 struct nfs_fattr *fp;
284 int error = 0;
285
286 if (nd->nd_flag & ND_NFSV4) {
287 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
288 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
289 } else if (nd->nd_flag & ND_NFSV3) {
290 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
291 nap->na_type = nfsv34tov_type(fp->fa_type);
292 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
293 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
294 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
295 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
296 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
297 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
298 nap->na_size = fxdr_hyper(&fp->fa3_size);
299 nap->na_blocksize = NFS_FABLKSIZE;
300 nap->na_bytes = fxdr_hyper(&fp->fa3_used);
301 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid);
302 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
303 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
304 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
305 nap->na_flags = 0;
306 nap->na_filerev = 0;
307 } else {
308 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
309 nap->na_type = nfsv2tov_type(fp->fa_type);
310 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
311 if (nap->na_type == VNON || nap->na_type == VREG)
312 nap->na_type = IFTOVT(nap->na_mode);
313 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
314
315 /*
316 * Really ugly NFSv2 kludge.
317 */
318 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
319 nap->na_type = VFIFO;
320 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
321 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
322 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
323 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
324 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
325 nap->na_bytes =
326 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
327 NFS_FABLKSIZE;
328 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid);
329 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
330 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
331 nap->na_flags = 0;
332 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
333 fp->fa2_ctime.nfsv2_sec);
334 nap->na_ctime.tv_nsec = 0;
335 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
336 nap->na_filerev = 0;
337 }
338 nfsmout:
339 return (error);
340 }
341
342 /*
343 * This function finds the directory cookie that corresponds to the
344 * logical byte offset given.
345 */
346 APPLESTATIC nfsuint64 *
347 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
348 {
349 struct nfsdmap *dp, *dp2;
350 int pos;
351
352 pos = off / NFS_DIRBLKSIZ;
353 if (pos == 0) {
354 KASSERT(!add, ("nfs getcookie add at 0"));
355 return (&nfs_nullcookie);
356 }
357 pos--;
358 dp = LIST_FIRST(&np->n_cookies);
359 if (!dp) {
360 if (add) {
361 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
362 M_NFSDIROFF, M_WAITOK);
363 dp->ndm_eocookie = 0;
364 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
365 } else
366 return (NULL);
367 }
368 while (pos >= NFSNUMCOOKIES) {
369 pos -= NFSNUMCOOKIES;
370 if (LIST_NEXT(dp, ndm_list) != NULL) {
371 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
372 pos >= dp->ndm_eocookie)
373 return (NULL);
374 dp = LIST_NEXT(dp, ndm_list);
375 } else if (add) {
376 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
377 M_NFSDIROFF, M_WAITOK);
378 dp2->ndm_eocookie = 0;
379 LIST_INSERT_AFTER(dp, dp2, ndm_list);
380 dp = dp2;
381 } else
382 return (NULL);
383 }
384 if (pos >= dp->ndm_eocookie) {
385 if (add)
386 dp->ndm_eocookie = pos + 1;
387 else
388 return (NULL);
389 }
390 return (&dp->ndm_cookies[pos]);
391 }
392
393 /*
394 * Gets a file handle out of an nfs reply sent to the client and returns
395 * the file handle and the file's attributes.
396 * For V4, it assumes that Getfh and Getattr Op's results are here.
397 */
398 APPLESTATIC int
399 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
400 struct nfsvattr *nap, int *attrflagp)
401 {
402 u_int32_t *tl;
403 int error = 0, flag = 1;
404
405 *nfhpp = NULL;
406 *attrflagp = 0;
407 /*
408 * First get the file handle and vnode.
409 */
410 if (nd->nd_flag & ND_NFSV3) {
411 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
412 flag = fxdr_unsigned(int, *tl);
413 } else if (nd->nd_flag & ND_NFSV4) {
414 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
415 }
416 if (flag) {
417 error = nfsm_getfh(nd, nfhpp);
418 if (error)
419 return (error);
420 }
421
422 /*
423 * Now, get the attributes.
424 */
425 if (nd->nd_flag & ND_NFSV4) {
426 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
427 } else if (nd->nd_flag & ND_NFSV3) {
428 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
429 if (flag) {
430 flag = fxdr_unsigned(int, *tl);
431 } else if (fxdr_unsigned(int, *tl)) {
432 error = nfsm_advance(nd, NFSX_V3FATTR, -1);
433 if (error)
434 return (error);
435 }
436 }
437 if (flag) {
438 error = nfsm_loadattr(nd, nap);
439 if (!error)
440 *attrflagp = 1;
441 }
442 nfsmout:
443 return (error);
444 }
445
446 /*
447 * Put a state Id in the mbuf list.
448 */
449 APPLESTATIC void
450 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
451 {
452 nfsv4stateid_t *st;
453
454 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
455 if (flag == NFSSTATEID_PUTALLZERO) {
456 st->seqid = 0;
457 st->other[0] = 0;
458 st->other[1] = 0;
459 st->other[2] = 0;
460 } else if (flag == NFSSTATEID_PUTALLONE) {
461 st->seqid = 0xffffffff;
462 st->other[0] = 0xffffffff;
463 st->other[1] = 0xffffffff;
464 st->other[2] = 0xffffffff;
465 } else {
466 st->seqid = stateidp->seqid;
467 st->other[0] = stateidp->other[0];
468 st->other[1] = stateidp->other[1];
469 st->other[2] = stateidp->other[2];
470 }
471 }
472
473 /*
474 * Initialize the owner/delegation sleep lock.
475 */
476 APPLESTATIC void
477 nfscl_lockinit(struct nfsv4lock *lckp)
478 {
479
480 lckp->nfslock_usecnt = 0;
481 lckp->nfslock_lock = 0;
482 }
483
484 /*
485 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
486 * thread for each posix process in the kernel.)
487 */
488 APPLESTATIC void
489 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
490 {
491 int igotlock;
492
493 do {
494 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
495 } while (!igotlock);
496 }
497
498 /*
499 * Release an exclusive lock.
500 */
501 APPLESTATIC void
502 nfscl_lockunlock(struct nfsv4lock *lckp)
503 {
504
505 nfsv4_unlock(lckp, 0);
506 }
507
508 /*
509 * Called to derefernce a lock on a stateid (delegation or open owner).
510 */
511 APPLESTATIC void
512 nfscl_lockderef(struct nfsv4lock *lckp)
513 {
514
515 NFSLOCKCLSTATE();
516 lckp->nfslock_usecnt--;
517 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
518 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
519 wakeup((caddr_t)lckp);
520 }
521 NFSUNLOCKCLSTATE();
522 }
523
Cache object: d838e136b08101cbd0792deeaeb8c9c4
|