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