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: releng/8.0/sys/fs/nfsclient/nfs_clcomsubs.c 191783 2009-05-04 15:23:58Z rmacklem $");
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, 3, "Open", 4, },
69 { NFSV4OP_CREATE, 3, "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;
130 else if (NFSHASNFSV3(nmp))
131 nd->nd_flag = ND_NFSV3;
132 else
133 nd->nd_flag = ND_NFSV2;
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 NFSWCCATTR_ATTRBIT(&attrbits);
171 (void) nfsrv_putattrbit(nd, &attrbits);
172 nd->nd_flag |= ND_V4WCCATTR;
173 }
174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
175 }
176 *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
177 } else {
178 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
179 }
180 NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]);
181 }
182
183 #ifndef APPLE
184 /*
185 * copies a uio scatter/gather list to an mbuf chain.
186 * NOTE: can ony handle iovcnt == 1
187 */
188 APPLESTATIC void
189 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz)
190 {
191 char *uiocp;
192 struct mbuf *mp, *mp2;
193 int xfer, left, mlen;
194 int uiosiz, clflg, rem;
195 char *cp, *tcp;
196
197 #ifdef DIAGNOSTIC
198 if (uiop->uio_iovcnt != 1)
199 panic("nfsm_uiotombuf: iovcnt != 1");
200 #endif
201
202 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */
203 clflg = 1;
204 else
205 clflg = 0;
206 rem = NFSM_RNDUP(siz) - siz;
207 mp = mp2 = nd->nd_mb;
208 while (siz > 0) {
209 left = uiop->uio_iov->iov_len;
210 uiocp = uiop->uio_iov->iov_base;
211 if (left > siz)
212 left = siz;
213 uiosiz = left;
214 while (left > 0) {
215 mlen = M_TRAILINGSPACE(mp);
216 if (mlen == 0) {
217 if (clflg)
218 NFSMCLGET(mp, M_WAIT);
219 else
220 NFSMGET(mp);
221 mbuf_setlen(mp, 0);
222 mbuf_setnext(mp2, mp);
223 mp2 = mp;
224 mlen = M_TRAILINGSPACE(mp);
225 }
226 xfer = (left > mlen) ? mlen : left;
227 #ifdef notdef
228 /* Not Yet.. */
229 if (uiop->uio_iov->iov_op != NULL)
230 (*(uiop->uio_iov->iov_op))
231 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
232 xfer);
233 else
234 #endif
235 if (uiop->uio_segflg == UIO_SYSSPACE)
236 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp),
237 xfer);
238 else
239 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t)
240 + mbuf_len(mp), xfer);
241 mbuf_setlen(mp, mbuf_len(mp) + xfer);
242 left -= xfer;
243 uiocp += xfer;
244 uiop->uio_offset += xfer;
245 uiop->uio_resid -= xfer;
246 }
247 tcp = (char *)uiop->uio_iov->iov_base;
248 tcp += uiosiz;
249 uiop->uio_iov->iov_base = (void *)tcp;
250 uiop->uio_iov->iov_len -= uiosiz;
251 siz -= uiosiz;
252 }
253 if (rem > 0) {
254 if (rem > M_TRAILINGSPACE(mp)) {
255 NFSMGET(mp);
256 mbuf_setlen(mp, 0);
257 mbuf_setnext(mp2, mp);
258 }
259 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
260 for (left = 0; left < rem; left++)
261 *cp++ = '\0';
262 mbuf_setlen(mp, mbuf_len(mp) + rem);
263 nd->nd_bpos = cp;
264 } else
265 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp);
266 nd->nd_mb = mp;
267 }
268 #endif /* !APPLE */
269
270 /*
271 * Load vnode attributes from the xdr file attributes.
272 * Returns EBADRPC if they can't be parsed, 0 otherwise.
273 */
274 APPLESTATIC int
275 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap)
276 {
277 struct nfs_fattr *fp;
278 int error = 0;
279
280 if (nd->nd_flag & ND_NFSV4) {
281 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL,
282 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL);
283 } else if (nd->nd_flag & ND_NFSV3) {
284 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR);
285 nap->na_type = nfsv34tov_type(fp->fa_type);
286 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
287 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
288 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
289 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
290 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
291 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
292 nap->na_size = fxdr_hyper(&fp->fa3_size);
293 nap->na_blocksize = NFS_FABLKSIZE;
294 nap->na_bytes = fxdr_hyper(&fp->fa3_used);
295 nap->na_fileid = fxdr_unsigned(int32_t,
296 fp->fa3_fileid.nfsuquad[1]);
297 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime);
298 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime);
299 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime);
300 nap->na_flags = 0;
301 nap->na_filerev = 0;
302 } else {
303 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR);
304 nap->na_type = nfsv2tov_type(fp->fa_type);
305 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode);
306 if (nap->na_type == VNON || nap->na_type == VREG)
307 nap->na_type = IFTOVT(nap->na_mode);
308 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev);
309
310 /*
311 * Really ugly NFSv2 kludge.
312 */
313 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1))
314 nap->na_type = VFIFO;
315 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
316 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid);
317 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid);
318 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
319 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
320 nap->na_bytes =
321 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
322 NFS_FABLKSIZE;
323 nap->na_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
324 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime);
325 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime);
326 nap->na_flags = 0;
327 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t,
328 fp->fa2_ctime.nfsv2_sec);
329 nap->na_ctime.tv_nsec = 0;
330 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
331 nap->na_filerev = 0;
332 }
333 nfsmout:
334 return (error);
335 }
336
337 /*
338 * This function finds the directory cookie that corresponds to the
339 * logical byte offset given.
340 */
341 APPLESTATIC nfsuint64 *
342 nfscl_getcookie(struct nfsnode *np, off_t off, int add)
343 {
344 struct nfsdmap *dp, *dp2;
345 int pos;
346
347 pos = off / NFS_DIRBLKSIZ;
348 if (pos == 0) {
349 #ifdef DIAGNOSTIC
350 if (add)
351 panic("nfs getcookie add at 0");
352 #endif
353 return (&nfs_nullcookie);
354 }
355 pos--;
356 dp = LIST_FIRST(&np->n_cookies);
357 if (!dp) {
358 if (add) {
359 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
360 M_NFSDIROFF, M_WAITOK);
361 dp->ndm_eocookie = 0;
362 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
363 } else
364 return (NULL);
365 }
366 while (pos >= NFSNUMCOOKIES) {
367 pos -= NFSNUMCOOKIES;
368 if (LIST_NEXT(dp, ndm_list) != NULL) {
369 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
370 pos >= dp->ndm_eocookie)
371 return (NULL);
372 dp = LIST_NEXT(dp, ndm_list);
373 } else if (add) {
374 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
375 M_NFSDIROFF, M_WAITOK);
376 dp2->ndm_eocookie = 0;
377 LIST_INSERT_AFTER(dp, dp2, ndm_list);
378 dp = dp2;
379 } else
380 return (NULL);
381 }
382 if (pos >= dp->ndm_eocookie) {
383 if (add)
384 dp->ndm_eocookie = pos + 1;
385 else
386 return (NULL);
387 }
388 return (&dp->ndm_cookies[pos]);
389 }
390
391 /*
392 * Gets a file handle out of an nfs reply sent to the client and returns
393 * the file handle and the file's attributes.
394 * For V4, it assumes that Getfh and Getattr Op's results are here.
395 */
396 APPLESTATIC int
397 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp,
398 struct nfsvattr *nap, int *attrflagp)
399 {
400 u_int32_t *tl;
401 int error = 0, flag = 1;
402
403 *nfhpp = NULL;
404 *attrflagp = 0;
405 /*
406 * First get the file handle and vnode.
407 */
408 if (nd->nd_flag & ND_NFSV3) {
409 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
410 flag = fxdr_unsigned(int, *tl);
411 } else if (nd->nd_flag & ND_NFSV4) {
412 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
413 }
414 if (flag) {
415 error = nfsm_getfh(nd, nfhpp);
416 if (error)
417 return (error);
418 }
419
420 /*
421 * Now, get the attributes.
422 */
423 if (nd->nd_flag & ND_NFSV4) {
424 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
425 } else if (nd->nd_flag & ND_NFSV3) {
426 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
427 if (flag) {
428 flag = fxdr_unsigned(int, *tl);
429 } else if (fxdr_unsigned(int, *tl)) {
430 error = nfsm_advance(nd, NFSX_V3FATTR, -1);
431 if (error)
432 return (error);
433 }
434 }
435 if (flag) {
436 error = nfsm_loadattr(nd, nap);
437 if (!error)
438 *attrflagp = 1;
439 }
440 nfsmout:
441 return (error);
442 }
443
444 /*
445 * Put a state Id in the mbuf list.
446 */
447 APPLESTATIC void
448 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
449 {
450 nfsv4stateid_t *st;
451
452 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
453 if (flag == NFSSTATEID_PUTALLZERO) {
454 st->seqid = 0;
455 st->other[0] = 0;
456 st->other[1] = 0;
457 st->other[2] = 0;
458 } else if (flag == NFSSTATEID_PUTALLONE) {
459 st->seqid = 0xffffffff;
460 st->other[0] = 0xffffffff;
461 st->other[1] = 0xffffffff;
462 st->other[2] = 0xffffffff;
463 } else {
464 st->seqid = stateidp->seqid;
465 st->other[0] = stateidp->other[0];
466 st->other[1] = stateidp->other[1];
467 st->other[2] = stateidp->other[2];
468 }
469 }
470
471 /*
472 * Initialize the owner/delegation sleep lock.
473 */
474 APPLESTATIC void
475 nfscl_lockinit(struct nfsv4lock *lckp)
476 {
477
478 lckp->nfslock_usecnt = 0;
479 lckp->nfslock_lock = 0;
480 }
481
482 /*
483 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one
484 * thread for each posix process in the kernel.)
485 */
486 APPLESTATIC void
487 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
488 {
489 int igotlock;
490
491 do {
492 igotlock = nfsv4_lock(lckp, 1, NULL, mutex);
493 } while (!igotlock);
494 }
495
496 /*
497 * Release an exclusive lock.
498 */
499 APPLESTATIC void
500 nfscl_lockunlock(struct nfsv4lock *lckp)
501 {
502
503 nfsv4_unlock(lckp, 0);
504 }
505
506 /*
507 * Called to derefernce a lock on a stateid (delegation or open owner).
508 */
509 APPLESTATIC void
510 nfscl_lockderef(struct nfsv4lock *lckp)
511 {
512
513 NFSLOCKCLSTATE();
514 lckp->nfslock_usecnt--;
515 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) {
516 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED;
517 wakeup((caddr_t)lckp);
518 }
519 NFSUNLOCKCLSTATE();
520 }
521
Cache object: 16700adb458a15110371d18406628106
|