[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/nfsserver/nfs_srvsubs.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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  *      @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
 33  */
 34 
 35 #include <sys/cdefs.h>
 36 __FBSDID("$FreeBSD: src/sys/nfsserver/nfs_srvsubs.c,v 1.161 2008/11/12 09:36:35 dfr Exp $");
 37 
 38 /*
 39  * These functions support the macros and help fiddle mbuf chains for
 40  * the nfs op functions. They do things like create the rpc header and
 41  * copy data between mbuf chains and uio lists.
 42  */
 43 
 44 #include "opt_inet6.h"
 45 
 46 #include <sys/param.h>
 47 #include <sys/systm.h>
 48 #include <sys/kernel.h>
 49 #include <sys/bio.h>
 50 #include <sys/buf.h>
 51 #include <sys/proc.h>
 52 #include <sys/mount.h>
 53 #include <sys/vnode.h>
 54 #include <sys/namei.h>
 55 #include <sys/mbuf.h>
 56 #include <sys/refcount.h>
 57 #include <sys/socket.h>
 58 #include <sys/stat.h>
 59 #include <sys/malloc.h>
 60 #include <sys/module.h>
 61 #include <sys/sysent.h>
 62 #include <sys/syscall.h>
 63 #include <sys/sysproto.h>
 64 
 65 #include <vm/vm.h>
 66 #include <vm/vm_object.h>
 67 #include <vm/vm_extern.h>
 68 #include <vm/uma.h>
 69 
 70 #include <nfs/rpcv2.h>
 71 #include <nfs/nfsproto.h>
 72 #include <nfsserver/nfs.h>
 73 #include <nfs/xdr_subs.h>
 74 #include <nfsserver/nfsm_subs.h>
 75 
 76 #include <netinet/in.h>
 77 
 78 /*
 79  * Data items converted to xdr at startup, since they are constant
 80  * This is kinda hokey, but may save a little time doing byte swaps
 81  */
 82 u_int32_t nfsrv_nfs_xdrneg1;
 83 u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
 84         nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
 85         nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
 86 u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
 87 
 88 /* And other global data */
 89 static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR,
 90                                        NFLNK, NFNON, NFCHR, NFNON };
 91 #define vtonfsv2_type(a)        txdr_unsigned(nfsv2_type[((int32_t)(a))])
 92 #define vtonfsv3_mode(m)        txdr_unsigned((m) & ALLPERMS)
 93 
 94 int nfsrv_ticks;
 95 
 96 #ifdef NFS_LEGACYRPC
 97 struct nfssvc_sockhead nfssvc_sockhead;
 98 int nfssvc_sockhead_flag;
 99 struct nfsd_head nfsd_head;
100 int nfsd_head_flag;
101 #endif
102 
103 static int nfssvc_offset = SYS_nfssvc;
104 static struct sysent nfssvc_prev_sysent;
105 MAKE_SYSENT(nfssvc);
106 
107 struct mtx nfsd_mtx;
108 
109 /*
110  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
111  */
112 const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
113         NFSPROC_NULL,
114         NFSPROC_GETATTR,
115         NFSPROC_SETATTR,
116         NFSPROC_NOOP,
117         NFSPROC_LOOKUP,
118         NFSPROC_READLINK,
119         NFSPROC_READ,
120         NFSPROC_NOOP,
121         NFSPROC_WRITE,
122         NFSPROC_CREATE,
123         NFSPROC_REMOVE,
124         NFSPROC_RENAME,
125         NFSPROC_LINK,
126         NFSPROC_SYMLINK,
127         NFSPROC_MKDIR,
128         NFSPROC_RMDIR,
129         NFSPROC_READDIR,
130         NFSPROC_FSSTAT,
131         NFSPROC_NOOP,
132         NFSPROC_NOOP,
133         NFSPROC_NOOP,
134         NFSPROC_NOOP,
135         NFSPROC_NOOP,
136 };
137 
138 /*
139  * and the reverse mapping from generic to Version 2 procedure numbers
140  */
141 const int nfsrvv2_procid[NFS_NPROCS] = {
142         NFSV2PROC_NULL,
143         NFSV2PROC_GETATTR,
144         NFSV2PROC_SETATTR,
145         NFSV2PROC_LOOKUP,
146         NFSV2PROC_NOOP,
147         NFSV2PROC_READLINK,
148         NFSV2PROC_READ,
149         NFSV2PROC_WRITE,
150         NFSV2PROC_CREATE,
151         NFSV2PROC_MKDIR,
152         NFSV2PROC_SYMLINK,
153         NFSV2PROC_CREATE,
154         NFSV2PROC_REMOVE,
155         NFSV2PROC_RMDIR,
156         NFSV2PROC_RENAME,
157         NFSV2PROC_LINK,
158         NFSV2PROC_READDIR,
159         NFSV2PROC_NOOP,
160         NFSV2PROC_STATFS,
161         NFSV2PROC_NOOP,
162         NFSV2PROC_NOOP,
163         NFSV2PROC_NOOP,
164         NFSV2PROC_NOOP,
165 };
166 
167 /*
168  * Maps errno values to nfs error numbers.
169  * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
170  * specifically defined in RFC 1094.
171  */
172 static const u_char nfsrv_v2errmap[ELAST] = {
173   NFSERR_PERM,  NFSERR_NOENT,   0,              0,              0,      
174   NFSERR_NXIO,  0,              0,              0,              0,      
175   0,            0,              NFSERR_ACCES,   0,              0,      
176   0,            NFSERR_EXIST,   0,              NFSERR_NODEV,   NFSERR_NOTDIR,
177   NFSERR_ISDIR, 0,              0,              0,              0,      
178   0,            NFSERR_FBIG,    NFSERR_NOSPC,   0,              NFSERR_ROFS,
179   0,            0,              0,              0,              0,      
180   0,            0,              0,              0,              0,      
181   0,            0,              0,              0,              0,      
182   0,            0,              0,              0,              0,      
183   0,            0,              0,              0,              0,      
184   0,            0,              0,              0,              0,      
185   0,            0,              NFSERR_NAMETOL, 0,              0,      
186   NFSERR_NOTEMPTY, 0,           0,              NFSERR_DQUOT,   NFSERR_STALE,
187   0
188 };
189 
190 /*
191  * Maps errno values to nfs error numbers.
192  * Although it is not obvious whether or not NFS clients really care if
193  * a returned error value is in the specified list for the procedure, the
194  * safest thing to do is filter them appropriately. For Version 2, the
195  * X/Open XNFS document is the only specification that defines error values
196  * for each RPC (The RFC simply lists all possible error values for all RPCs),
197  * so I have decided to not do this for Version 2.
198  * The first entry is the default error return and the rest are the valid
199  * errors for that RPC in increasing numeric order.
200  */
201 static const short nfsv3err_null[] = {
202         0,
203         0,
204 };
205 
206 static const short nfsv3err_getattr[] = {
207         NFSERR_IO,
208         NFSERR_IO,
209         NFSERR_STALE,
210         NFSERR_BADHANDLE,
211         NFSERR_SERVERFAULT,
212         0,
213 };
214 
215 static const short nfsv3err_setattr[] = {
216         NFSERR_IO,
217         NFSERR_PERM,
218         NFSERR_IO,
219         NFSERR_ACCES,
220         NFSERR_INVAL,
221         NFSERR_NOSPC,
222         NFSERR_ROFS,
223         NFSERR_DQUOT,
224         NFSERR_STALE,
225         NFSERR_BADHANDLE,
226         NFSERR_NOT_SYNC,
227         NFSERR_SERVERFAULT,
228         0,
229 };
230 
231 static const short nfsv3err_lookup[] = {
232         NFSERR_IO,
233         NFSERR_NOENT,
234         NFSERR_IO,
235         NFSERR_ACCES,
236         NFSERR_NOTDIR,
237         NFSERR_NAMETOL,
238         NFSERR_STALE,
239         NFSERR_BADHANDLE,
240         NFSERR_SERVERFAULT,
241         0,
242 };
243 
244 static const short nfsv3err_access[] = {
245         NFSERR_IO,
246         NFSERR_IO,
247         NFSERR_STALE,
248         NFSERR_BADHANDLE,
249         NFSERR_SERVERFAULT,
250         0,
251 };
252 
253 static const short nfsv3err_readlink[] = {
254         NFSERR_IO,
255         NFSERR_IO,
256         NFSERR_ACCES,
257         NFSERR_INVAL,
258         NFSERR_STALE,
259         NFSERR_BADHANDLE,
260         NFSERR_NOTSUPP,
261         NFSERR_SERVERFAULT,
262         0,
263 };
264 
265 static const short nfsv3err_read[] = {
266         NFSERR_IO,
267         NFSERR_IO,
268         NFSERR_NXIO,
269         NFSERR_ACCES,
270         NFSERR_INVAL,
271         NFSERR_STALE,
272         NFSERR_BADHANDLE,
273         NFSERR_SERVERFAULT,
274         0,
275 };
276 
277 static const short nfsv3err_write[] = {
278         NFSERR_IO,
279         NFSERR_IO,
280         NFSERR_ACCES,
281         NFSERR_INVAL,
282         NFSERR_FBIG,
283         NFSERR_NOSPC,
284         NFSERR_ROFS,
285         NFSERR_DQUOT,
286         NFSERR_STALE,
287         NFSERR_BADHANDLE,
288         NFSERR_SERVERFAULT,
289         0,
290 };
291 
292 static const short nfsv3err_create[] = {
293         NFSERR_IO,
294         NFSERR_IO,
295         NFSERR_ACCES,
296         NFSERR_EXIST,
297         NFSERR_NOTDIR,
298         NFSERR_NOSPC,
299         NFSERR_ROFS,
300         NFSERR_NAMETOL,
301         NFSERR_DQUOT,
302         NFSERR_STALE,
303         NFSERR_BADHANDLE,
304         NFSERR_NOTSUPP,
305         NFSERR_SERVERFAULT,
306         0,
307 };
308 
309 static const short nfsv3err_mkdir[] = {
310         NFSERR_IO,
311         NFSERR_IO,
312         NFSERR_ACCES,
313         NFSERR_EXIST,
314         NFSERR_NOTDIR,
315         NFSERR_NOSPC,
316         NFSERR_ROFS,
317         NFSERR_NAMETOL,
318         NFSERR_DQUOT,
319         NFSERR_STALE,
320         NFSERR_BADHANDLE,
321         NFSERR_NOTSUPP,
322         NFSERR_SERVERFAULT,
323         0,
324 };
325 
326 static const short nfsv3err_symlink[] = {
327         NFSERR_IO,
328         NFSERR_IO,
329         NFSERR_ACCES,
330         NFSERR_EXIST,
331         NFSERR_NOTDIR,
332         NFSERR_NOSPC,
333         NFSERR_ROFS,
334         NFSERR_NAMETOL,
335         NFSERR_DQUOT,
336         NFSERR_STALE,
337         NFSERR_BADHANDLE,
338         NFSERR_NOTSUPP,
339         NFSERR_SERVERFAULT,
340         0,
341 };
342 
343 static const short nfsv3err_mknod[] = {
344         NFSERR_IO,
345         NFSERR_IO,
346         NFSERR_ACCES,
347         NFSERR_EXIST,
348         NFSERR_NOTDIR,
349         NFSERR_NOSPC,
350         NFSERR_ROFS,
351         NFSERR_NAMETOL,
352         NFSERR_DQUOT,
353         NFSERR_STALE,
354         NFSERR_BADHANDLE,
355         NFSERR_NOTSUPP,
356         NFSERR_SERVERFAULT,
357         NFSERR_BADTYPE,
358         0,
359 };
360 
361 static const short nfsv3err_remove[] = {
362         NFSERR_IO,
363         NFSERR_NOENT,
364         NFSERR_IO,
365         NFSERR_ACCES,
366         NFSERR_NOTDIR,
367         NFSERR_ROFS,
368         NFSERR_NAMETOL,
369         NFSERR_STALE,
370         NFSERR_BADHANDLE,
371         NFSERR_SERVERFAULT,
372         0,
373 };
374 
375 static const short nfsv3err_rmdir[] = {
376         NFSERR_IO,
377         NFSERR_NOENT,
378         NFSERR_IO,
379         NFSERR_ACCES,
380         NFSERR_EXIST,
381         NFSERR_NOTDIR,
382         NFSERR_INVAL,
383         NFSERR_ROFS,
384         NFSERR_NAMETOL,
385         NFSERR_NOTEMPTY,
386         NFSERR_STALE,
387         NFSERR_BADHANDLE,
388         NFSERR_NOTSUPP,
389         NFSERR_SERVERFAULT,
390         0,
391 };
392 
393 static const short nfsv3err_rename[] = {
394         NFSERR_IO,
395         NFSERR_NOENT,
396         NFSERR_IO,
397         NFSERR_ACCES,
398         NFSERR_EXIST,
399         NFSERR_XDEV,
400         NFSERR_NOTDIR,
401         NFSERR_ISDIR,
402         NFSERR_INVAL,
403         NFSERR_NOSPC,
404         NFSERR_ROFS,
405         NFSERR_MLINK,
406         NFSERR_NAMETOL,
407         NFSERR_NOTEMPTY,
408         NFSERR_DQUOT,
409         NFSERR_STALE,
410         NFSERR_BADHANDLE,
411         NFSERR_NOTSUPP,
412         NFSERR_SERVERFAULT,
413         0,
414 };
415 
416 static const short nfsv3err_link[] = {
417         NFSERR_IO,
418         NFSERR_IO,
419         NFSERR_ACCES,
420         NFSERR_EXIST,
421         NFSERR_XDEV,
422         NFSERR_NOTDIR,
423         NFSERR_INVAL,
424         NFSERR_NOSPC,
425         NFSERR_ROFS,
426         NFSERR_MLINK,
427         NFSERR_NAMETOL,
428         NFSERR_DQUOT,
429         NFSERR_STALE,
430         NFSERR_BADHANDLE,
431         NFSERR_NOTSUPP,
432         NFSERR_SERVERFAULT,
433         0,
434 };
435 
436 static const short nfsv3err_readdir[] = {
437         NFSERR_IO,
438         NFSERR_IO,
439         NFSERR_ACCES,
440         NFSERR_NOTDIR,
441         NFSERR_STALE,
442         NFSERR_BADHANDLE,
443         NFSERR_BAD_COOKIE,
444         NFSERR_TOOSMALL,
445         NFSERR_SERVERFAULT,
446         0,
447 };
448 
449 static const short nfsv3err_readdirplus[] = {
450         NFSERR_IO,
451         NFSERR_IO,
452         NFSERR_ACCES,
453         NFSERR_NOTDIR,
454         NFSERR_STALE,
455         NFSERR_BADHANDLE,
456         NFSERR_BAD_COOKIE,
457         NFSERR_NOTSUPP,
458         NFSERR_TOOSMALL,
459         NFSERR_SERVERFAULT,
460         0,
461 };
462 
463 static const short nfsv3err_fsstat[] = {
464         NFSERR_IO,
465         NFSERR_IO,
466         NFSERR_STALE,
467         NFSERR_BADHANDLE,
468         NFSERR_SERVERFAULT,
469         0,
470 };
471 
472 static const short nfsv3err_fsinfo[] = {
473         NFSERR_STALE,
474         NFSERR_STALE,
475         NFSERR_BADHANDLE,
476         NFSERR_SERVERFAULT,
477         0,
478 };
479 
480 static const short nfsv3err_pathconf[] = {
481         NFSERR_STALE,
482         NFSERR_STALE,
483         NFSERR_BADHANDLE,
484         NFSERR_SERVERFAULT,
485         0,
486 };
487 
488 static const short nfsv3err_commit[] = {
489         NFSERR_IO,
490         NFSERR_IO,
491         NFSERR_STALE,
492         NFSERR_BADHANDLE,
493         NFSERR_SERVERFAULT,
494         0,
495 };
496 
497 static const short *nfsrv_v3errmap[] = {
498         nfsv3err_null,
499         nfsv3err_getattr,
500         nfsv3err_setattr,
501         nfsv3err_lookup,
502         nfsv3err_access,
503         nfsv3err_readlink,
504         nfsv3err_read,
505         nfsv3err_write,
506         nfsv3err_create,
507         nfsv3err_mkdir,
508         nfsv3err_symlink,
509         nfsv3err_mknod,
510         nfsv3err_remove,
511         nfsv3err_rmdir,
512         nfsv3err_rename,
513         nfsv3err_link,
514         nfsv3err_readdir,
515         nfsv3err_readdirplus,
516         nfsv3err_fsstat,
517         nfsv3err_fsinfo,
518         nfsv3err_pathconf,
519         nfsv3err_commit,
520 };
521 
522 /*
523  * Called once to initialize data structures...
524  */
525 static int
526 nfsrv_modevent(module_t mod, int type, void *data)
527 {
528         static int registered;
529         int error = 0;
530 
531         switch (type) {
532         case MOD_LOAD:
533                 mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
534                 nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
535                 nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
536                 nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
537                 nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
538                 nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
539                 nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
540                 nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
541                 nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
542                 nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
543                 nfsrv_nfs_true = txdr_unsigned(TRUE);
544                 nfsrv_nfs_false = txdr_unsigned(FALSE);
545                 nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
546                 nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
547                 if (nfsrv_ticks < 1)
548                         nfsrv_ticks = 1;
549 
550 #ifdef NFS_LEGACYRPC
551                 nfsrv_initcache();      /* Init the server request cache */
552                 NFSD_LOCK();
553                 nfsrv_init(0);          /* Init server data structures */
554                 callout_init(&nfsrv_callout, CALLOUT_MPSAFE);
555                 NFSD_UNLOCK();
556                 nfsrv_timer(0);
557 #else
558                 NFSD_LOCK();
559                 nfsrv_init(0);          /* Init server data structures */
560                 NFSD_UNLOCK();
561 #endif
562 
563                 error = syscall_register(&nfssvc_offset, &nfssvc_sysent,
564                     &nfssvc_prev_sysent);
565                 if (error)
566                         break;
567                 registered = 1;
568                 break;
569 
570         case MOD_UNLOAD:
571                 if (nfsrv_numnfsd != 0) {
572                         error = EBUSY;
573                         break;
574                 }
575 
576                 if (registered)
577                         syscall_deregister(&nfssvc_offset, &nfssvc_prev_sysent);
578                 callout_drain(&nfsrv_callout);
579 #ifdef NFS_LEGACYRPC
580                 nfsrv_destroycache();   /* Free the server request cache */
581 #endif
582                 mtx_destroy(&nfsd_mtx);
583                 break;
584         default:
585                 error = EOPNOTSUPP;
586                 break;
587         }
588         return error;
589 }
590 static moduledata_t nfsserver_mod = {
591         "nfsserver",
592         nfsrv_modevent,
593         NULL,
594 };
595 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
596 
597 /* So that loader and kldload(2) can find us, wherever we are.. */
598 MODULE_VERSION(nfsserver, 1);
599 #ifndef NFS_LEGACYRPC
600 MODULE_DEPEND(nfsserver, krpc, 1, 1, 1);
601 #endif
602 
603 /*
604  * Set up nameidata for a lookup() call and do it.
605  *
606  * If pubflag is set, this call is done for a lookup operation on the
607  * public filehandle. In that case we allow crossing mountpoints and
608  * absolute pathnames. However, the caller is expected to check that
609  * the lookup result is within the public fs, and deny access if
610  * it is not.
611  *
612  * nfs_namei() clears out garbage fields that namei() might leave garbage.
613  * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
614  * error occurs but the parent was not requested.
615  *
616  * dirp may be set whether an error is returned or not, and must be
617  * released by the caller.
618  */
619 int
620 nfs_namei(struct nameidata *ndp, struct nfsrv_descript *nfsd,
621     fhandle_t *fhp, int len, struct nfssvc_sock *slp,
622     struct sockaddr *nam, struct mbuf **mdp,
623     caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
624     int *retdirattr_retp, int pubflag)
625 {
626         int i, rem;
627         struct mbuf *md;
628         char *fromcp, *tocp, *cp;
629         struct iovec aiov;
630         struct uio auio;
631         struct vnode *dp;
632         int error, rdonly, linklen;
633         struct componentname *cnp = &ndp->ni_cnd;
634         int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
635         int dvfslocked;
636         int vfslocked;
637 
638         vfslocked = 0;
639         dvfslocked = 0;
640         *retdirp = NULL;
641         cnp->cn_flags |= NOMACCHECK;
642         cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
643 
644         /*
645          * Copy the name from the mbuf list to ndp->ni_pnbuf
646          * and set the various ndp fields appropriately.
647          */
648         fromcp = *dposp;
649         tocp = cnp->cn_pnbuf;
650         md = *mdp;
651         rem = mtod(md, caddr_t) + md->m_len - fromcp;
652         for (i = 0; i < len; i++) {
653                 while (rem == 0) {
654                         md = md->m_next;
655                         if (md == NULL) {
656                                 error = EBADRPC;
657                                 goto out;
658                         }
659                         fromcp = mtod(md, caddr_t);
660                         rem = md->m_len;
661                 }
662                 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
663                         error = EACCES;
664                         goto out;
665                 }
666                 *tocp++ = *fromcp++;
667                 rem--;
668         }
669         *tocp = '\0';
670         *mdp = md;
671         *dposp = fromcp;
672         len = nfsm_rndup(len)-len;
673         if (len > 0) {
674                 if (rem >= len)
675                         *dposp += len;
676                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
677                         goto out;
678         }
679 
680         /*
681          * Extract and set starting directory.
682          */
683         error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
684             nfsd, slp, nam, &rdonly, pubflag);
685         if (error)
686                 goto out;
687         vfslocked = VFS_LOCK_GIANT(dp->v_mount);
688         if (dp->v_type != VDIR) {
689                 vrele(dp);
690                 error = ENOTDIR;
691                 goto out;
692         }
693 
694         if (rdonly)
695                 cnp->cn_flags |= RDONLY;
696 
697         /*
698          * Set return directory.  Reference to dp is implicitly transfered
699          * to the returned pointer
700          */
701         *retdirp = dp;
702         if (v3) {
703                 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
704                 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
705                         ndp->ni_cnd.cn_cred);
706                 VOP_UNLOCK(dp, 0);
707         }
708 
709         if (pubflag) {
710                 /*
711                  * Oh joy. For WebNFS, handle those pesky '%' escapes,
712                  * and the 'native path' indicator.
713                  */
714                 cp = uma_zalloc(namei_zone, M_WAITOK);
715                 fromcp = cnp->cn_pnbuf;
716                 tocp = cp;
717                 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
718                         switch ((unsigned char)*fromcp) {
719                         case WEBNFS_NATIVE_CHAR:
720                                 /*
721                                  * 'Native' path for us is the same
722                                  * as a path according to the NFS spec,
723                                  * just skip the escape char.
724                                  */
725                                 fromcp++;
726                                 break;
727                         /*
728                          * More may be added in the future, range 0x80-0xff
729                          */
730                         default:
731                                 error = EIO;
732                                 uma_zfree(namei_zone, cp);
733                                 goto out;
734                         }
735                 }
736                 /*
737                  * Translate the '%' escapes, URL-style.
738                  */
739                 while (*fromcp != '\0') {
740                         if (*fromcp == WEBNFS_ESC_CHAR) {
741                                 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
742                                         fromcp++;
743                                         *tocp++ = HEXSTRTOI(fromcp);
744                                         fromcp += 2;
745                                         continue;
746                                 } else {
747                                         error = ENOENT;
748                                         uma_zfree(namei_zone, cp);
749                                         goto out;
750                                 }
751                         } else
752                                 *tocp++ = *fromcp++;
753                 }
754                 *tocp = '\0';
755                 uma_zfree(namei_zone, cnp->cn_pnbuf);
756                 cnp->cn_pnbuf = cp;
757         }
758 
759         ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
760         ndp->ni_segflg = UIO_SYSSPACE;
761 
762         if (pubflag) {
763                 ndp->ni_rootdir = rootvnode;
764                 ndp->ni_loopcnt = 0;
765                 if (cnp->cn_pnbuf[0] == '/') {
766                         int tvfslocked;
767 
768                         tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
769                         VFS_UNLOCK_GIANT(vfslocked);
770                         dp = rootvnode;
771                         vfslocked = tvfslocked;
772                 }
773         } else {
774                 cnp->cn_flags |= NOCROSSMOUNT;
775         }
776 
777         /*
778          * Initialize for scan, set ni_startdir and bump ref on dp again
779          * because lookup() will dereference ni_startdir.
780          */
781 
782         cnp->cn_thread = curthread;
783         VREF(dp);
784         ndp->ni_startdir = dp;
785 
786         if (!lockleaf)
787                 cnp->cn_flags |= LOCKLEAF;
788         for (;;) {
789                 cnp->cn_nameptr = cnp->cn_pnbuf;
790                 /*
791                  * Call lookup() to do the real work.  If an error occurs,
792                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
793                  * we do not have to dereference anything before returning.
794                  * In either case ni_startdir will be dereferenced and NULLed
795                  * out.
796                  */
797                 if (vfslocked)
798                         ndp->ni_cnd.cn_flags |= GIANTHELD;
799                 error = lookup(ndp);
800                 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
801                 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
802                 if (error)
803                         break;
804 
805                 /*
806                  * Check for encountering a symbolic link.  Trivial
807                  * termination occurs if no symlink encountered.
808                  * Note: zfree is safe because error is 0, so we will
809                  * not zfree it again when we break.
810                  */
811                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
812                         if (cnp->cn_flags & (SAVENAME | SAVESTART))
813                                 cnp->cn_flags |= HASBUF;
814                         else
815                                 uma_zfree(namei_zone, cnp->cn_pnbuf);
816                         if (ndp->ni_vp && !lockleaf)
817                                 VOP_UNLOCK(ndp->ni_vp, 0);
818                         break;
819                 }
820 
821                 /*
822                  * Validate symlink
823                  */
824                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
825                         VOP_UNLOCK(ndp->ni_dvp, 0);
826                 if (!pubflag) {
827                         error = EINVAL;
828                         goto badlink2;
829                 }
830 
831                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
832                         error = ELOOP;
833                         goto badlink2;
834                 }
835                 if (ndp->ni_pathlen > 1)
836                         cp = uma_zalloc(namei_zone, M_WAITOK);
837                 else
838                         cp = cnp->cn_pnbuf;
839                 aiov.iov_base = cp;
840                 aiov.iov_len = MAXPATHLEN;
841                 auio.uio_iov = &aiov;
842                 auio.uio_iovcnt = 1;
843                 auio.uio_offset = 0;
844                 auio.uio_rw = UIO_READ;
845                 auio.uio_segflg = UIO_SYSSPACE;
846                 auio.uio_td = NULL;
847                 auio.uio_resid = MAXPATHLEN;
848                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
849                 if (error) {
850                 badlink1:
851                         if (ndp->ni_pathlen > 1)
852                                 uma_zfree(namei_zone, cp);
853                 badlink2:
854                         vput(ndp->ni_vp);
855                         vrele(ndp->ni_dvp);
856                         break;
857                 }
858                 linklen = MAXPATHLEN - auio.uio_resid;
859                 if (linklen == 0) {
860                         error = ENOENT;
861                         goto badlink1;
862                 }
863                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
864                         error = ENAMETOOLONG;
865                         goto badlink1;
866                 }
867 
868                 /*
869                  * Adjust or replace path
870                  */
871                 if (ndp->ni_pathlen > 1) {
872                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
873                         uma_zfree(namei_zone, cnp->cn_pnbuf);
874                         cnp->cn_pnbuf = cp;
875                 } else
876                         cnp->cn_pnbuf[linklen] = '\0';
877                 ndp->ni_pathlen += linklen;
878 
879                 /*
880                  * Cleanup refs for next loop and check if root directory
881                  * should replace current directory.  Normally ni_dvp
882                  * becomes the new base directory and is cleaned up when
883                  * we loop.  Explicitly null pointers after invalidation
884                  * to clarify operation.
885                  */
886                 vput(ndp->ni_vp);
887                 ndp->ni_vp = NULL;
888 
889                 if (cnp->cn_pnbuf[0] == '/') {
890                         vrele(ndp->ni_dvp);
891                         ndp->ni_dvp = ndp->ni_rootdir;
892                         VREF(ndp->ni_dvp);
893                 }
894                 ndp->ni_startdir = ndp->ni_dvp;
895                 ndp->ni_dvp = NULL;
896         }
897         if (!lockleaf)
898                 cnp->cn_flags &= ~LOCKLEAF;
899         if (cnp->cn_flags & GIANTHELD) {
900                 mtx_unlock(&Giant);
901                 cnp->cn_flags &= ~GIANTHELD;
902         }
903 
904         /*
905          * nfs_namei() guarentees that fields will not contain garbage
906          * whether an error occurs or not.  This allows the caller to track
907          * cleanup state trivially.
908          */
909 out:
910         if (error) {
911                 uma_zfree(namei_zone, cnp->cn_pnbuf);
912                 ndp->ni_vp = NULL;
913                 ndp->ni_dvp = NULL;
914                 ndp->ni_startdir = NULL;
915                 cnp->cn_flags &= ~HASBUF;
916                 VFS_UNLOCK_GIANT(vfslocked);
917                 vfslocked = 0;
918         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
919                 ndp->ni_dvp = NULL;
920         }
921         /*
922          * This differs from normal namei() in that even on failure we may
923          * return with Giant held due to the dirp return.  Make sure we only
924          * have not recursed however.  The calling code only expects to drop
925          * one acquire.
926          */
927         if (vfslocked || dvfslocked)
928                 ndp->ni_cnd.cn_flags |= GIANTHELD;
929         if (vfslocked && dvfslocked)
930                 VFS_UNLOCK_GIANT(vfslocked);
931         return (error);
932 }
933 
934 /*
935  * A fiddled version of m_adj() that ensures null fill to a long
936  * boundary and only trims off the back end
937  */
938 void
939 nfsm_adj(struct mbuf *mp, int len, int nul)
940 {
941         struct mbuf *m;
942         int count, i;
943         char *cp;
944 
945         /*
946          * Trim from tail.  Scan the mbuf chain,
947          * calculating its length and finding the last mbuf.
948          * If the adjustment only affects this mbuf, then just
949          * adjust and return.  Otherwise, rescan and truncate
950          * after the remaining size.
951          */
952         count = 0;
953         m = mp;
954         for (;;) {
955                 count += m->m_len;
956                 if (m->m_next == NULL)
957                         break;
958                 m = m->m_next;
959         }
960         if (m->m_len > len) {
961                 m->m_len -= len;
962                 if (nul > 0) {
963                         cp = mtod(m, caddr_t)+m->m_len-nul;
964                         for (i = 0; i < nul; i++)
965                                 *cp++ = '\0';
966                 }
967                 return;
968         }
969         count -= len;
970         if (count < 0)
971                 count = 0;
972         /*
973          * Correct length for chain is "count".
974          * Find the mbuf with last data, adjust its length,
975          * and toss data from remaining mbufs on chain.
976          */
977         for (m = mp; m; m = m->m_next) {
978                 if (m->m_len >= count) {
979                         m->m_len = count;
980                         if (nul > 0) {
981                                 cp = mtod(m, caddr_t)+m->m_len-nul;
982                                 for (i = 0; i < nul; i++)
983                                         *cp++ = '\0';
984                         }
985                         if (m->m_next != NULL) {
986                                 m_freem(m->m_next);
987                                 m->m_next = NULL;
988                         }
989                         break;
990                 }
991                 count -= m->m_len;
992         }
993 }
994 
995 /*
996  * Make these functions instead of macros, so that the kernel text size
997  * doesn't get too big...
998  */
999 void
1000 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
1001     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
1002     struct mbuf **mbp, char **bposp)
1003 {
1004         struct mbuf *mb = *mbp;
1005         char *bpos = *bposp;
1006         u_int32_t *tl;
1007 
1008