2b5282bbe063235476d8269a004384db76f1ff23
[dragonfly.git] / sys / kern / vfs_syscalls.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      @(#)vfs_syscalls.c      8.13 (Berkeley) 4/15/94
39  * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $
40  * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.41 2004/10/02 03:18:26 dillon Exp $
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/buf.h>
46 #include <sys/conf.h>
47 #include <sys/sysent.h>
48 #include <sys/malloc.h>
49 #include <sys/mount.h>
50 #include <sys/sysproto.h>
51 #include <sys/filedesc.h>
52 #include <sys/kernel.h>
53 #include <sys/fcntl.h>
54 #include <sys/file.h>
55 #include <sys/linker.h>
56 #include <sys/stat.h>
57 #include <sys/unistd.h>
58 #include <sys/vnode.h>
59 #include <sys/proc.h>
60 #include <sys/namei.h>
61 #include <sys/nlookup.h>
62 #include <sys/dirent.h>
63 #include <sys/extattr.h>
64 #include <sys/kern_syscall.h>
65
66 #include <machine/limits.h>
67 #include <vfs/union/union.h>
68 #include <sys/sysctl.h>
69 #include <vm/vm.h>
70 #include <vm/vm_object.h>
71 #include <vm/vm_zone.h>
72 #include <vm/vm_page.h>
73
74 #include <sys/file2.h>
75
76 static int checkvp_chdir (struct vnode *vn, struct thread *td);
77 static void checkdirs (struct vnode *olddp, struct namecache *ncp);
78 static int chroot_refuse_vdir_fds (struct filedesc *fdp);
79 static int getutimes (const struct timeval *, struct timespec *);
80 static int setfown (struct vnode *, uid_t, gid_t);
81 static int setfmode (struct vnode *, int);
82 static int setfflags (struct vnode *, int);
83 static int setutimes (struct vnode *, const struct timespec *, int);
84 static int      usermount = 0;  /* if 1, non-root can mount fs. */
85
86 int (*union_dircheckp) (struct thread *, struct vnode **, struct file *);
87
88 SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
89
90 /*
91  * Virtual File System System Calls
92  */
93
94 /*
95  * Mount a file system.
96  */
97 /*
98  * mount_args(char *type, char *path, int flags, caddr_t data)
99  */
100 /* ARGSUSED */
101 int
102 mount(struct mount_args *uap)
103 {
104         struct thread *td = curthread;
105         struct proc *p = td->td_proc;
106         struct vnode *vp;
107         struct namecache *ncp;
108         struct mount *mp;
109         struct vfsconf *vfsp;
110         int error, flag = 0, flag2 = 0;
111         struct vattr va;
112         struct nlookupdata nd;
113         char fstypename[MFSNAMELEN];
114         lwkt_tokref vlock;
115         lwkt_tokref ilock;
116         struct nlcomponent nlc;
117
118         KKASSERT(p);
119         if (p->p_ucred->cr_prison != NULL)
120                 return (EPERM);
121         if (usermount == 0 && (error = suser(td)))
122                 return (error);
123         /*
124          * Do not allow NFS export by non-root users.
125          */
126         if (SCARG(uap, flags) & MNT_EXPORTED) {
127                 error = suser(td);
128                 if (error)
129                         return (error);
130         }
131         /*
132          * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users
133          */
134         if (suser(td)) 
135                 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
136
137         /*
138          * Lookup the requested path and extract the ncp and vnode.
139          */
140         error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
141         if (error == 0) {
142                 if ((error = nlookup(&nd)) == 0) {
143                         if (nd.nl_ncp->nc_vp == NULL)
144                                 error = ENOENT;
145                 }
146         }
147         if (error) {
148                 nlookup_done(&nd);
149                 return (error);
150         }
151
152         /*
153          * Extract the locked+refd ncp and cleanup the nd structure
154          */
155         ncp = nd.nl_ncp;
156         nd.nl_ncp = NULL;
157         nlookup_done(&nd);
158
159         /*
160          * now we have the locked ref'd ncp and unreferenced vnode.
161          */
162         vp = ncp->nc_vp;
163         if ((error = vget(vp, NULL, LK_EXCLUSIVE, td)) != 0) {
164                 cache_put(ncp);
165                 return (error);
166         }
167         cache_unlock(ncp);
168
169         /*
170          * Now we have an unlocked ref'd ncp and a locked ref'd vp
171          */
172         if (SCARG(uap, flags) & MNT_UPDATE) {
173                 if ((vp->v_flag & VROOT) == 0) {
174                         cache_drop(ncp);
175                         vput(vp);
176                         return (EINVAL);
177                 }
178                 mp = vp->v_mount;
179                 flag = mp->mnt_flag;
180                 flag2 = mp->mnt_kern_flag;
181                 /*
182                  * We only allow the filesystem to be reloaded if it
183                  * is currently mounted read-only.
184                  */
185                 if ((SCARG(uap, flags) & MNT_RELOAD) &&
186                     ((mp->mnt_flag & MNT_RDONLY) == 0)) {
187                         cache_drop(ncp);
188                         vput(vp);
189                         return (EOPNOTSUPP);    /* Needs translation */
190                 }
191                 /*
192                  * Only root, or the user that did the original mount is
193                  * permitted to update it.
194                  */
195                 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
196                     (error = suser(td))) {
197                         cache_drop(ncp);
198                         vput(vp);
199                         return (error);
200                 }
201                 if (vfs_busy(mp, LK_NOWAIT, NULL, td)) {
202                         cache_drop(ncp);
203                         vput(vp);
204                         return (EBUSY);
205                 }
206                 lwkt_gettoken(&vlock, vp->v_interlock);
207                 if ((vp->v_flag & VMOUNT) != 0 ||
208                     vp->v_mountedhere != NULL) {
209                         cache_drop(ncp);
210                         lwkt_reltoken(&vlock);
211                         vfs_unbusy(mp, td);
212                         vput(vp);
213                         return (EBUSY);
214                 }
215                 vp->v_flag |= VMOUNT;
216                 lwkt_reltoken(&vlock);
217                 mp->mnt_flag |=
218                     SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
219                 VOP_UNLOCK(vp, NULL, 0, td);
220                 goto update;
221         }
222         /*
223          * If the user is not root, ensure that they own the directory
224          * onto which we are attempting to mount.
225          */
226         if ((error = VOP_GETATTR(vp, &va, td)) ||
227             (va.va_uid != p->p_ucred->cr_uid &&
228              (error = suser(td)))) {
229                 cache_drop(ncp);
230                 vput(vp);
231                 return (error);
232         }
233         if ((error = vinvalbuf(vp, V_SAVE, td, 0, 0)) != 0) {
234                 cache_drop(ncp);
235                 vput(vp);
236                 return (error);
237         }
238         if (vp->v_type != VDIR) {
239                 cache_drop(ncp);
240                 vput(vp);
241                 return (ENOTDIR);
242         }
243         if ((error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) != 0) {
244                 cache_drop(ncp);
245                 vput(vp);
246                 return (error);
247         }
248         for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
249                 if (!strcmp(vfsp->vfc_name, fstypename))
250                         break;
251         }
252         if (vfsp == NULL) {
253                 linker_file_t lf;
254
255                 /* Only load modules for root (very important!) */
256                 if ((error = suser(td)) != 0) {
257                         cache_drop(ncp);
258                         vput(vp);
259                         return error;
260                 }
261                 error = linker_load_file(fstypename, &lf);
262                 if (error || lf == NULL) {
263                         cache_drop(ncp);
264                         vput(vp);
265                         if (lf == NULL)
266                                 error = ENODEV;
267                         return error;
268                 }
269                 lf->userrefs++;
270                 /* lookup again, see if the VFS was loaded */
271                 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
272                         if (!strcmp(vfsp->vfc_name, fstypename))
273                                 break;
274                 }
275                 if (vfsp == NULL) {
276                         lf->userrefs--;
277                         linker_file_unload(lf);
278                         cache_drop(ncp);
279                         vput(vp);
280                         return (ENODEV);
281                 }
282         }
283         lwkt_gettoken(&vlock, vp->v_interlock);
284         if ((vp->v_flag & VMOUNT) != 0 ||
285             vp->v_mountedhere != NULL) {
286                 lwkt_reltoken(&vlock);
287                 cache_drop(ncp);
288                 vput(vp);
289                 return (EBUSY);
290         }
291         vp->v_flag |= VMOUNT;
292         lwkt_reltoken(&vlock);
293
294         /*
295          * Allocate and initialize the filesystem.
296          */
297         mp = malloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK);
298         TAILQ_INIT(&mp->mnt_nvnodelist);
299         TAILQ_INIT(&mp->mnt_reservedvnlist);
300         mp->mnt_nvnodelistsize = 0;
301         lockinit(&mp->mnt_lock, 0, "vfslock", 0, LK_NOPAUSE);
302         vfs_busy(mp, LK_NOWAIT, NULL, td);
303         mp->mnt_op = vfsp->vfc_vfsops;
304         mp->mnt_vfc = vfsp;
305         vfsp->vfc_refcount++;
306         mp->mnt_stat.f_type = vfsp->vfc_typenum;
307         mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
308         strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
309         mp->mnt_vnodecovered = vp;
310         mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
311         mp->mnt_iosize_max = DFLTPHYS;
312         VOP_UNLOCK(vp, NULL, 0, td);
313 update:
314         /*
315          * Set the mount level flags.
316          */
317         if (SCARG(uap, flags) & MNT_RDONLY)
318                 mp->mnt_flag |= MNT_RDONLY;
319         else if (mp->mnt_flag & MNT_RDONLY)
320                 mp->mnt_kern_flag |= MNTK_WANTRDWR;
321         mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
322             MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME |
323             MNT_NOSYMFOLLOW | MNT_IGNORE |
324             MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
325         mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
326             MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
327             MNT_NOSYMFOLLOW | MNT_IGNORE |
328             MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
329         /*
330          * Mount the filesystem.
331          * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
332          * get.  No freeing of cn_pnbuf.
333          */
334         error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), td);
335         if (mp->mnt_flag & MNT_UPDATE) {
336                 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
337                         mp->mnt_flag &= ~MNT_RDONLY;
338                 mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
339                 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
340                 if (error) {
341                         mp->mnt_flag = flag;
342                         mp->mnt_kern_flag = flag2;
343                 }
344                 vfs_unbusy(mp, td);
345                 lwkt_gettoken(&vlock, vp->v_interlock);
346                 vp->v_flag &= ~VMOUNT;
347                 lwkt_reltoken(&vlock);
348                 vrele(vp);
349                 cache_drop(ncp);
350                 return (error);
351         }
352         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
353         /*
354          * Put the new filesystem on the mount list after root.  The mount
355          * point gets its own mnt_ncp which is a special ncp linking the
356          * vnode-under to the root of the new mount.  The lookup code
357          * detects the mount point going forward and detects the special
358          * mnt_ncp via NCP_MOUNTPT going backwards.
359          */
360         cache_purge(vp);
361         if (!error) {
362                 nlc.nlc_nameptr = "";
363                 nlc.nlc_namelen = 0;
364                 mp->mnt_ncp = cache_nlookup(ncp, &nlc);
365                 mp->mnt_ncp->nc_flag |= NCF_MOUNTPT;
366                 mp->mnt_ncp->nc_mount = mp;
367                 cache_drop(ncp);
368                 /* XXX get the root of the fs and cache_setvp(mnt_ncp...) */
369                 lwkt_gettoken(&vlock, vp->v_interlock);
370                 vp->v_flag &= ~VMOUNT;
371                 vp->v_mountedhere = mp;
372                 lwkt_reltoken(&vlock);
373                 lwkt_gettoken(&ilock, &mountlist_token);
374                 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
375                 lwkt_reltoken(&ilock);
376                 checkdirs(vp, mp->mnt_ncp);
377                 cache_unlock(mp->mnt_ncp);      /* leave ref intact */
378                 VOP_UNLOCK(vp, NULL, 0, td);
379                 error = vfs_allocate_syncvnode(mp);
380                 vfs_unbusy(mp, td);
381                 if ((error = VFS_START(mp, 0, td)) != 0)
382                         vrele(vp);
383         } else {
384                 vfs_rm_vnodeops(&mp->mnt_vn_ops);
385                 vfs_rm_vnodeops(&mp->mnt_vn_spec_ops);
386                 vfs_rm_vnodeops(&mp->mnt_vn_fifo_ops);
387                 lwkt_gettoken(&vlock, vp->v_interlock);
388                 vp->v_flag &= ~VMOUNT;
389                 lwkt_reltoken(&vlock);
390                 mp->mnt_vfc->vfc_refcount--;
391                 vfs_unbusy(mp, td);
392                 free(mp, M_MOUNT);
393                 cache_drop(ncp);
394                 vput(vp);
395         }
396         return (error);
397 }
398
399 /*
400  * Scan all active processes to see if any of them have a current
401  * or root directory onto which the new filesystem has just been
402  * mounted. If so, replace them with the new mount point.
403  *
404  * The passed ncp is ref'd and locked (from the mount code) and
405  * must be associated with the vnode representing the root of the
406  * mount point.
407  */
408 static void
409 checkdirs(struct vnode *olddp, struct namecache *ncp)
410 {
411         struct filedesc *fdp;
412         struct vnode *newdp;
413         struct mount *mp;
414         struct proc *p;
415
416         if (olddp->v_usecount == 1)
417                 return;
418         mp = olddp->v_mountedhere;
419         if (VFS_ROOT(mp, &newdp))
420                 panic("mount: lost mount");
421         cache_setvp(ncp, newdp);
422
423         if (rootvnode == olddp) {
424                 vref(newdp);
425                 vfs_cache_setroot(newdp, cache_hold(ncp));
426         }
427
428         FOREACH_PROC_IN_SYSTEM(p) {
429                 fdp = p->p_fd;
430                 if (fdp->fd_cdir == olddp) {
431                         vrele(fdp->fd_cdir);
432                         vref(newdp);
433                         fdp->fd_cdir = newdp;
434                         cache_drop(fdp->fd_ncdir);
435                         fdp->fd_ncdir = cache_hold(ncp);
436                 }
437                 if (fdp->fd_rdir == olddp) {
438                         vrele(fdp->fd_rdir);
439                         vref(newdp);
440                         fdp->fd_rdir = newdp;
441                         cache_drop(fdp->fd_nrdir);
442                         fdp->fd_nrdir = cache_hold(ncp);
443                 }
444         }
445         vput(newdp);
446 }
447
448 /*
449  * Unmount a file system.
450  *
451  * Note: unmount takes a path to the vnode mounted on as argument,
452  * not special file (as before).
453  */
454 /*
455  * umount_args(char *path, int flags)
456  */
457 /* ARGSUSED */
458 int
459 unmount(struct unmount_args *uap)
460 {
461         struct thread *td = curthread;
462         struct proc *p = td->td_proc;
463         struct vnode *vp;
464         struct mount *mp;
465         int error;
466         struct nameidata nd;
467
468         KKASSERT(p);
469         if (p->p_ucred->cr_prison != NULL)
470                 return (EPERM);
471         if (usermount == 0 && (error = suser(td)))
472                 return (error);
473
474         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE,
475             SCARG(uap, path), td);
476         if ((error = namei(&nd)) != 0)
477                 return (error);
478         vp = nd.ni_vp;
479         NDFREE(&nd, NDF_ONLY_PNBUF);
480         mp = vp->v_mount;
481
482         /*
483          * Only root, or the user that did the original mount is
484          * permitted to unmount this filesystem.
485          */
486         if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
487             (error = suser(td))) {
488                 vput(vp);
489                 return (error);
490         }
491
492         /*
493          * Don't allow unmounting the root file system.
494          */
495         if (mp->mnt_flag & MNT_ROOTFS) {
496                 vput(vp);
497                 return (EINVAL);
498         }
499
500         /*
501          * Must be the root of the filesystem
502          */
503         if ((vp->v_flag & VROOT) == 0) {
504                 vput(vp);
505                 return (EINVAL);
506         }
507         vput(vp);
508         return (dounmount(mp, SCARG(uap, flags), td));
509 }
510
511 /*
512  * Do the actual file system unmount.
513  */
514 int
515 dounmount(struct mount *mp, int flags, struct thread *td)
516 {
517         struct vnode *coveredvp;
518         int error;
519         int async_flag;
520         lwkt_tokref ilock;
521
522         lwkt_gettoken(&ilock, &mountlist_token);
523         if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
524                 lwkt_reltoken(&ilock);
525                 return (EBUSY);
526         }
527         mp->mnt_kern_flag |= MNTK_UNMOUNT;
528         /* Allow filesystems to detect that a forced unmount is in progress. */
529         if (flags & MNT_FORCE)
530                 mp->mnt_kern_flag |= MNTK_UNMOUNTF;
531         error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK |
532             ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &ilock, td);
533         if (error) {
534                 mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
535                 if (mp->mnt_kern_flag & MNTK_MWAIT)
536                         wakeup(mp);
537                 return (error);
538         }
539
540         if (mp->mnt_flag & MNT_EXPUBLIC)
541                 vfs_setpublicfs(NULL, NULL, NULL);
542
543         vfs_msync(mp, MNT_WAIT);
544         async_flag = mp->mnt_flag & MNT_ASYNC;
545         mp->mnt_flag &=~ MNT_ASYNC;
546         cache_purgevfs(mp);     /* remove cache entries for this file sys */
547         if (mp->mnt_syncer != NULL)
548                 vrele(mp->mnt_syncer);
549         if (((mp->mnt_flag & MNT_RDONLY) ||
550              (error = VFS_SYNC(mp, MNT_WAIT, td)) == 0) ||
551             (flags & MNT_FORCE))
552                 error = VFS_UNMOUNT(mp, flags, td);
553         lwkt_gettokref(&ilock);
554         if (error) {
555                 if (mp->mnt_syncer == NULL)
556                         vfs_allocate_syncvnode(mp);
557                 mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
558                 mp->mnt_flag |= async_flag;
559                 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
560                     &ilock, td);
561                 if (mp->mnt_kern_flag & MNTK_MWAIT)
562                         wakeup(mp);
563                 return (error);
564         }
565         TAILQ_REMOVE(&mountlist, mp, mnt_list);
566
567         /*
568          * Remove any installed vnode ops here so the individual VFSs don't
569          * have to.
570          */
571         vfs_rm_vnodeops(&mp->mnt_vn_ops);
572         vfs_rm_vnodeops(&mp->mnt_vn_spec_ops);
573         vfs_rm_vnodeops(&mp->mnt_vn_fifo_ops);
574
575         if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
576                 coveredvp->v_mountedhere = NULL;
577                 vrele(coveredvp);
578                 cache_drop(mp->mnt_ncp);
579                 mp->mnt_ncp = NULL;
580         }
581         mp->mnt_vfc->vfc_refcount--;
582         if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
583                 panic("unmount: dangling vnode");
584         lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &ilock, td);
585         if (mp->mnt_kern_flag & MNTK_MWAIT)
586                 wakeup(mp);
587         free(mp, M_MOUNT);
588         return (0);
589 }
590
591 /*
592  * Sync each mounted filesystem.
593  */
594
595 #ifdef DEBUG
596 static int syncprt = 0;
597 SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
598 #endif /* DEBUG */
599
600 /* ARGSUSED */
601 int
602 sync(struct sync_args *uap)
603 {
604         struct thread *td = curthread;
605         struct mount *mp, *nmp;
606         lwkt_tokref ilock;
607         int asyncflag;
608
609         lwkt_gettoken(&ilock, &mountlist_token);
610         for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
611                 if (vfs_busy(mp, LK_NOWAIT, &ilock, td)) {
612                         nmp = TAILQ_NEXT(mp, mnt_list);
613                         continue;
614                 }
615                 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
616                         asyncflag = mp->mnt_flag & MNT_ASYNC;
617                         mp->mnt_flag &= ~MNT_ASYNC;
618                         vfs_msync(mp, MNT_NOWAIT);
619                         VFS_SYNC(mp, MNT_NOWAIT, td);
620                         mp->mnt_flag |= asyncflag;
621                 }
622                 lwkt_gettokref(&ilock);
623                 nmp = TAILQ_NEXT(mp, mnt_list);
624                 vfs_unbusy(mp, td);
625         }
626         lwkt_reltoken(&ilock);
627 /*
628  * print out buffer pool stat information on each sync() call.
629  */
630 #ifdef DEBUG
631         if (syncprt)
632                 vfs_bufstats();
633 #endif /* DEBUG */
634         return (0);
635 }
636
637 /* XXX PRISON: could be per prison flag */
638 static int prison_quotas;
639 #if 0
640 SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
641 #endif
642
643 /*
644  *  quotactl_args(char *path, int fcmd, int uid, caddr_t arg)
645  *
646  * Change filesystem quotas.
647  */
648 /* ARGSUSED */
649 int
650 quotactl(struct quotactl_args *uap)
651 {
652         struct thread *td = curthread;
653         struct proc *p = td->td_proc;
654         struct mount *mp;
655         int error;
656         struct nameidata nd;
657
658         KKASSERT(p);
659         if (p->p_ucred->cr_prison && !prison_quotas)
660                 return (EPERM);
661         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE,
662             SCARG(uap, path), td);
663         if ((error = namei(&nd)) != 0)
664                 return (error);
665         mp = nd.ni_vp->v_mount;
666         NDFREE(&nd, NDF_ONLY_PNBUF);
667         vrele(nd.ni_vp);
668         return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
669             SCARG(uap, arg), td));
670 }
671
672 int
673 kern_statfs(struct nameidata *nd, struct statfs *buf)
674 {
675         struct thread *td = curthread;
676         struct mount *mp;
677         struct statfs *sp;
678         int error;
679
680         error = namei(nd);
681         if (error)
682                 return (error);
683         mp = nd->ni_vp->v_mount;
684         sp = &mp->mnt_stat;
685         NDFREE(nd, NDF_ONLY_PNBUF);
686         vrele(nd->ni_vp);
687         error = VFS_STATFS(mp, sp, td);
688         if (error)
689                 return (error);
690         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
691         bcopy(sp, buf, sizeof(*buf));
692         /* Only root should have access to the fsid's. */
693         if (suser(td))
694                 buf->f_fsid.val[0] = buf->f_fsid.val[1] = 0;
695         return (0);
696 }
697
698 /*
699  * statfs_args(char *path, struct statfs *buf)
700  *
701  * Get filesystem statistics.
702  */
703 int
704 statfs(struct statfs_args *uap)
705 {
706         struct thread *td = curthread;
707         struct nameidata nd;
708         struct statfs buf;
709         int error;
710
711         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
712
713         error = kern_statfs(&nd, &buf);
714
715         if (error == 0)
716                 error = copyout(&buf, uap->buf, sizeof(*uap->buf));
717         return (error);
718 }
719
720 int
721 kern_fstatfs(int fd, struct statfs *buf)
722 {
723         struct thread *td = curthread;
724         struct proc *p = td->td_proc;
725         struct file *fp;
726         struct mount *mp;
727         struct statfs *sp;
728         int error;
729
730         KKASSERT(p);
731         error = getvnode(p->p_fd, fd, &fp);
732         if (error)
733                 return (error);
734         mp = ((struct vnode *)fp->f_data)->v_mount;
735         if (mp == NULL)
736                 return (EBADF);
737         sp = &mp->mnt_stat;
738         error = VFS_STATFS(mp, sp, td);
739         if (error)
740                 return (error);
741         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
742         bcopy(sp, buf, sizeof(*buf));
743         /* Only root should have access to the fsid's. */
744         if (suser(td))
745                 buf->f_fsid.val[0] = buf->f_fsid.val[1] = 0;
746         return (0);
747 }
748
749 /*
750  * fstatfs_args(int fd, struct statfs *buf)
751  *
752  * Get filesystem statistics.
753  */
754 int
755 fstatfs(struct fstatfs_args *uap)
756 {
757         struct statfs buf;
758         int error;
759
760         error = kern_fstatfs(uap->fd, &buf);
761
762         if (error == 0)
763                 error = copyout(&buf, uap->buf, sizeof(*uap->buf));
764         return (error);
765 }
766
767 /*
768  * getfsstat_args(struct statfs *buf, long bufsize, int flags)
769  *
770  * Get statistics on all filesystems.
771  */
772 /* ARGSUSED */
773 int
774 getfsstat(struct getfsstat_args *uap)
775 {
776         struct thread *td = curthread;
777         struct mount *mp, *nmp;
778         struct statfs *sp;
779         caddr_t sfsp;
780         lwkt_tokref ilock;
781         long count, maxcount, error;
782
783         maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
784         sfsp = (caddr_t)SCARG(uap, buf);
785         count = 0;
786         lwkt_gettoken(&ilock, &mountlist_token);
787         for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
788                 if (vfs_busy(mp, LK_NOWAIT, &ilock, td)) {
789                         nmp = TAILQ_NEXT(mp, mnt_list);
790                         continue;
791                 }
792                 if (sfsp && count < maxcount) {
793                         sp = &mp->mnt_stat;
794                         /*
795                          * If MNT_NOWAIT or MNT_LAZY is specified, do not
796                          * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
797                          * overrides MNT_WAIT.
798                          */
799                         if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
800                             (SCARG(uap, flags) & MNT_WAIT)) &&
801                             (error = VFS_STATFS(mp, sp, td))) {
802                                 lwkt_gettokref(&ilock);
803                                 nmp = TAILQ_NEXT(mp, mnt_list);
804                                 vfs_unbusy(mp, td);
805                                 continue;
806                         }
807                         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
808                         error = copyout(sp, sfsp, sizeof(*sp));
809                         if (error) {
810                                 vfs_unbusy(mp, td);
811                                 return (error);
812                         }
813                         sfsp += sizeof(*sp);
814                 }
815                 count++;
816                 lwkt_gettokref(&ilock);
817                 nmp = TAILQ_NEXT(mp, mnt_list);
818                 vfs_unbusy(mp, td);
819         }
820         lwkt_reltoken(&ilock);
821         if (sfsp && count > maxcount)
822                 uap->sysmsg_result = maxcount;
823         else
824                 uap->sysmsg_result = count;
825         return (0);
826 }
827
828 /*
829  * fchdir_args(int fd)
830  *
831  * Change current working directory to a given file descriptor.
832  */
833 /* ARGSUSED */
834 int
835 fchdir(struct fchdir_args *uap)
836 {
837         struct thread *td = curthread;
838         struct proc *p = td->td_proc;
839         struct filedesc *fdp = p->p_fd;
840         struct vnode *vp, *ovp;
841         struct mount *mp;
842         struct file *fp;
843         struct namecache *ncp, *oncp;
844         struct namecache *nct;
845         int error;
846
847         if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
848                 return (error);
849         vp = (struct vnode *)fp->f_data;
850         vref(vp);
851         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
852         if (vp->v_type != VDIR || fp->f_ncp == NULL)
853                 error = ENOTDIR;
854         else
855                 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, td);
856         if (error) {
857                 vput(vp);
858                 return (error);
859         }
860         ncp = cache_hold(fp->f_ncp);
861         while (!error && (mp = vp->v_mountedhere) != NULL) {
862                 error = nlookup_mp(mp, &nct);
863                 if (error == 0) {
864                         cache_unlock(nct);      /* leave ref intact */
865                         vput(vp);
866                         vp = nct->nc_vp;
867                         error = vget(vp, NULL, LK_SHARED, td);
868                         KKASSERT(error == 0);
869                         cache_drop(ncp);
870                         ncp = nct;
871                 }
872         }
873         if (error == 0) {
874                 ovp = fdp->fd_cdir;
875                 oncp = fdp->fd_ncdir;
876                 VOP_UNLOCK(vp, NULL, 0, td);    /* leave ref intact */
877                 fdp->fd_cdir = vp;
878                 fdp->fd_ncdir = ncp;
879                 cache_drop(oncp);
880                 vrele(ovp);
881         } else {
882                 cache_drop(ncp);
883                 vput(vp);
884         }
885         return (error);
886 }
887
888 int
889 kern_chdir(struct nlookupdata *nd)
890 {
891         struct thread *td = curthread;
892         struct proc *p = td->td_proc;
893         struct filedesc *fdp = p->p_fd;
894         struct vnode *vp, *ovp;
895         struct namecache *oncp;
896         int error;
897
898         if ((error = nlookup(nd)) != 0)
899                 return (error);
900         if ((vp = nd->nl_ncp->nc_vp) == NULL)
901                 return (ENOENT);
902         if ((error = vget(vp, NULL, LK_SHARED, td)) != 0)
903                 return (error);
904
905         error = checkvp_chdir(vp, td);
906         VOP_UNLOCK(vp, NULL, 0, td);
907         if (error == 0) {
908                 ovp = fdp->fd_cdir;
909                 oncp = fdp->fd_ncdir;
910                 cache_unlock(nd->nl_ncp);       /* leave reference intact */
911                 fdp->fd_ncdir = nd->nl_ncp;
912                 fdp->fd_cdir = vp;
913                 cache_drop(oncp);
914                 vrele(ovp);
915                 nd->nl_ncp = NULL;
916         } else {
917                 vrele(vp);
918         }
919         return (error);
920 }
921
922 /*
923  * chdir_args(char *path)
924  *
925  * Change current working directory (``.'').
926  */
927 int
928 chdir(struct chdir_args *uap)
929 {
930         struct nlookupdata nd;
931         int error;
932
933         error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
934         if (error == 0) {
935                 error = kern_chdir(&nd);
936                 nlookup_done(&nd);
937         }
938         return (error);
939 }
940
941 /*
942  * Helper function for raised chroot(2) security function:  Refuse if
943  * any filedescriptors are open directories.
944  */
945 static int
946 chroot_refuse_vdir_fds(fdp)
947         struct filedesc *fdp;
948 {
949         struct vnode *vp;
950         struct file *fp;
951         int error;
952         int fd;
953
954         for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
955                 error = getvnode(fdp, fd, &fp);
956                 if (error)
957                         continue;
958                 vp = (struct vnode *)fp->f_data;
959                 if (vp->v_type != VDIR)
960                         continue;
961                 return(EPERM);
962         }
963         return (0);
964 }
965
966 /*
967  * This sysctl determines if we will allow a process to chroot(2) if it
968  * has a directory open:
969  *      0: disallowed for all processes.
970  *      1: allowed for processes that were not already chroot(2)'ed.
971  *      2: allowed for all processes.
972  */
973
974 static int chroot_allow_open_directories = 1;
975
976 SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
977      &chroot_allow_open_directories, 0, "");
978
979 /*
980  * chroot to the specified namecache entry.  We obtain the vp from the
981  * namecache data.  The passed ncp must be locked and referenced and will
982  * remain locked and referenced on return.
983  */
984 static int
985 kern_chroot(struct namecache *ncp)
986 {
987         struct thread *td = curthread;
988         struct proc *p = td->td_proc;
989         struct filedesc *fdp = p->p_fd;
990         struct vnode *vp;
991         int error;
992
993         /*
994          * Only root can chroot
995          */
996         if ((error = suser_cred(p->p_ucred, PRISON_ROOT)) != 0)
997                 return (error);
998
999         /*
1000          * Disallow open directory descriptors (fchdir() breakouts).
1001          */
1002         if (chroot_allow_open_directories == 0 ||
1003            (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
1004                 if ((error = chroot_refuse_vdir_fds(fdp)) != 0)
1005                         return (error);
1006         }
1007         if ((vp = ncp->nc_vp) == NULL)
1008                 return (ENOENT);
1009
1010         if ((error = vget(vp, NULL, LK_SHARED, td)) != 0)
1011                 return (error);
1012
1013         /*
1014          * Check the validity of vp as a directory to change to and 
1015          * associate it with rdir/jdir.
1016          */
1017         error = checkvp_chdir(vp, td);
1018         VOP_UNLOCK(vp, NULL, 0, td);    /* leave reference intact */
1019         if (error == 0) {
1020                 vrele(fdp->fd_rdir);
1021                 fdp->fd_rdir = vp;      /* reference inherited by fd_rdir */
1022                 cache_drop(fdp->fd_nrdir);
1023                 fdp->fd_nrdir = cache_hold(ncp);
1024                 if (fdp->fd_jdir == NULL) {
1025                         fdp->fd_jdir = vp;
1026                         vref(fdp->fd_jdir);
1027                         fdp->fd_njdir = cache_hold(ncp);
1028                 }
1029         } else {
1030                 vrele(vp);
1031         }
1032         return (error);
1033 }
1034
1035 /*
1036  * chroot_args(char *path)
1037  *
1038  * Change notion of root (``/'') directory.
1039  */
1040 /* ARGSUSED */
1041 int
1042 chroot(struct chroot_args *uap)
1043 {
1044         struct thread *td = curthread;
1045         struct nlookupdata nd;
1046         int error;
1047
1048         KKASSERT(td->td_proc);
1049         error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
1050         if (error == 0) {
1051                 error = kern_chroot(nd.nl_ncp);
1052                 nlookup_done(&nd);
1053         }
1054         return (error);
1055 }
1056
1057 /*
1058  * Common routine for chroot and chdir.  Given a locked, referenced vnode,
1059  * determine whether it is legal to chdir to the vnode.  The vnode's state
1060  * is not changed by this call.
1061  */
1062 int
1063 checkvp_chdir(struct vnode *vp, struct thread *td)
1064 {
1065         int error;
1066
1067         if (vp->v_type != VDIR)
1068                 error = ENOTDIR;
1069         else
1070                 error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td);
1071         return (error);
1072 }
1073
1074 int
1075 kern_open(struct nameidata *nd, int oflags, int mode, int *res)
1076 {
1077         struct thread *td = curthread;
1078         struct proc *p = td->td_proc;
1079         struct filedesc *fdp = p->p_fd;
1080         struct file *fp;
1081         struct vnode *vp;
1082         int cmode, flags;
1083         struct file *nfp;
1084         int type, indx, error;
1085         int ndxerror;
1086         struct flock lf;
1087         struct nlookupdata ndx;
1088
1089         if ((oflags & O_ACCMODE) == O_ACCMODE)
1090                 return (EINVAL);
1091         flags = FFLAGS(oflags);
1092         error = falloc(p, &nfp, &indx);
1093         if (error)
1094                 return (error);
1095         fp = nfp;
1096         cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
1097         p->p_dupfd = -indx - 1;                 /* XXX check for fdopen */
1098         /*
1099          * Bump the ref count to prevent another process from closing
1100          * the descriptor while we are blocked in vn_open()
1101          */
1102         fhold(fp);
1103
1104         /*
1105          * XXX temporary hack so we can record the namecache pointer 
1106          * associated with an open descriptor.
1107          */
1108         ndxerror = nlookup_init(&ndx, nd->ni_dirp, nd->ni_segflg,
1109             ((nd->ni_cnd.cn_flags & CNP_FOLLOW) ? NLC_FOLLOW : 0));
1110
1111         error = vn_open(nd, flags, cmode);
1112         if (error) {
1113                 /*
1114                  * release our own reference
1115                  */
1116                 fdrop(fp, td);
1117
1118                 /*
1119                  * handle special fdopen() case.  bleh.  dupfdopen() is
1120                  * responsible for dropping the old contents of ofiles[indx]
1121                  * if it succeeds.
1122                  */
1123                 if ((error == ENODEV || error == ENXIO) &&
1124                     p->p_dupfd >= 0 &&                  /* XXX from fdopen */
1125                     (error =
1126                         dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
1127                         *res = indx;
1128                         nlookup_done(&ndx);
1129                         return (0);
1130                 }
1131                 /*
1132                  * Clean up the descriptor, but only if another thread hadn't
1133                  * replaced or closed it.
1134                  */
1135                 if (fdp->fd_ofiles[indx] == fp) {
1136                         fdp->fd_ofiles[indx] = NULL;
1137                         fdrop(fp, td);
1138                 }
1139
1140                 if (error == ERESTART)
1141                         error = EINTR;
1142                 nlookup_done(&ndx);
1143                 return (error);
1144         }
1145         p->p_dupfd = 0;
1146         NDFREE(nd, NDF_ONLY_PNBUF);
1147         vp = nd->ni_vp;
1148
1149         /*
1150          * There should be 2 references on the file, one from the descriptor
1151          * table, and one for us.
1152          *
1153          * Handle the case where someone closed the file (via its file
1154          * descriptor) while we were blocked.  The end result should look
1155          * like opening the file succeeded but it was immediately closed.
1156          */
1157         if (fp->f_count == 1) {
1158                 KASSERT(fdp->fd_ofiles[indx] != fp,
1159                     ("Open file descriptor lost all refs"));
1160                 VOP_UNLOCK(vp, NULL, 0, td);
1161                 vn_close(vp, flags & FMASK, td);
1162                 fdrop(fp, td);
1163                 *res = indx;
1164                 nlookup_done(&ndx);
1165                 return 0;
1166         }
1167
1168         fp->f_data = (caddr_t)vp;
1169         fp->f_flag = flags & FMASK;
1170         fp->f_ops = &vnops;
1171         fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
1172         if (flags & (O_EXLOCK | O_SHLOCK)) {
1173                 lf.l_whence = SEEK_SET;
1174                 lf.l_start = 0;
1175                 lf.l_len = 0;
1176                 if (flags & O_EXLOCK)
1177                         lf.l_type = F_WRLCK;
1178                 else
1179                         lf.l_type = F_RDLCK;
1180                 type = F_FLOCK;
1181                 if ((flags & FNONBLOCK) == 0)
1182                         type |= F_WAIT;
1183                 VOP_UNLOCK(vp, NULL, 0, td);
1184                 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
1185                         /*
1186                          * lock request failed.  Normally close the descriptor
1187                          * but handle the case where someone might have dup()d
1188                          * it when we weren't looking.  One reference is
1189                          * owned by the descriptor array, the other by us.
1190                          */
1191                         if (fdp->fd_ofiles[indx] == fp) {
1192                                 fdp->fd_ofiles[indx] = NULL;
1193                                 fdrop(fp, td);
1194                         }
1195                         fdrop(fp, td);
1196                         nlookup_done(&ndx);
1197                         return (error);
1198                 }
1199                 vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
1200                 fp->f_flag |= FHASLOCK;
1201         }
1202         /* assert that vn_open created a backing object if one is needed */
1203         KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
1204                 ("open: vmio vnode has no backing object after vn_open"));
1205         VOP_UNLOCK(vp, NULL, 0, td);
1206
1207         /*
1208          * If the vp is a directory locate the ncp to store with the file
1209          * descriptor.  XXX temporary.  We may eventually wish to do this
1210          * permanently as it would provide an invaluable diagnostic tool,
1211          * but first the entire open path needs to be converted from
1212          * namei to nlookup so we can avoid having to do a double-lookup.
1213          *
1214          * The primary purpose of storing the ncp with the file pointer is
1215          * so it can be used in fchdir() and fchroot() syscalls, allowing
1216          * us to retain an unbroken namecache topology.
1217          */
1218         if (ndxerror == 0 && vp->v_type == VDIR) {
1219                 if ((ndxerror = nlookup(&ndx)) == 0) {
1220                         fp->f_ncp = ndx.nl_ncp;
1221                         ndx.nl_ncp = NULL;
1222                         cache_unlock(fp->f_ncp);
1223                 }
1224         }
1225         nlookup_done(&ndx);
1226
1227         /*
1228          * release our private reference, leaving the one associated with the
1229          * descriptor table intact.
1230          */
1231         fdrop(fp, td);
1232         *res = indx;
1233         return (0);
1234 }
1235
1236 /*
1237  * open_args(char *path, int flags, int mode)
1238  *
1239  * Check permissions, allocate an open file structure,
1240  * and call the device open routine if any.
1241  */
1242 int
1243 open(struct open_args *uap)
1244 {
1245         struct thread *td = curthread;
1246         struct nameidata nd;
1247         int error;
1248
1249         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
1250
1251         error = kern_open(&nd, uap->flags, uap->mode, &uap->sysmsg_result);
1252
1253         return (error);
1254 }
1255
1256 int
1257 kern_mknod(struct nameidata *nd, int mode, int dev)
1258 {
1259         struct thread *td = curthread;
1260         struct proc *p = td->td_proc;
1261         struct vnode *vp;
1262         struct vattr vattr;
1263         int error;
1264         int whiteout = 0;
1265
1266         KKASSERT(p);
1267
1268         switch (mode & S_IFMT) {
1269         case S_IFCHR:
1270         case S_IFBLK:
1271                 error = suser(td);
1272                 break;
1273         default:
1274                 error = suser_cred(p->p_ucred, PRISON_ROOT);
1275                 break;
1276         }
1277         if (error)
1278                 return (error);
1279         bwillwrite();
1280         error = namei(nd);
1281         if (error)
1282                 return (error);
1283         vp = nd->ni_vp;
1284         if (vp != NULL)
1285                 error = EEXIST;
1286         else {
1287                 VATTR_NULL(&vattr);
1288                 vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1289                 vattr.va_rdev = dev;
1290                 whiteout = 0;
1291
1292                 switch (mode & S_IFMT) {
1293                 case S_IFMT:    /* used by badsect to flag bad sectors */
1294                         vattr.va_type = VBAD;
1295                         break;
1296                 case S_IFCHR:
1297                         vattr.va_type = VCHR;
1298                         break;
1299                 case S_IFBLK:
1300                         vattr.va_type = VBLK;
1301                         break;
1302                 case S_IFWHT:
1303                         whiteout = 1;
1304                         break;
1305                 default:
1306                         error = EINVAL;
1307                         break;
1308                 }
1309         }
1310         if (error == 0) {
1311                 VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
1312                 if (whiteout)
1313                         error = VOP_WHITEOUT(nd->ni_dvp, NCPNULL,
1314                             &nd->ni_cnd, NAMEI_CREATE);
1315                 else {
1316                         error = VOP_MKNOD(nd->ni_dvp, NCPNULL, &nd->ni_vp,
1317                             &nd->ni_cnd, &vattr);
1318                         if (error == 0)
1319                                 vput(nd->ni_vp);
1320                 }
1321                 NDFREE(nd, NDF_ONLY_PNBUF);
1322                 vput(nd->ni_dvp);
1323         } else {
1324                 NDFREE(nd, NDF_ONLY_PNBUF);
1325                 if (nd->ni_dvp == vp)
1326                         vrele(nd->ni_dvp);
1327                 else
1328                         vput(nd->ni_dvp);
1329                 if (vp)
1330                         vrele(vp);
1331         }
1332         ASSERT_VOP_UNLOCKED(nd->ni_dvp, "mknod");
1333         ASSERT_VOP_UNLOCKED(nd->ni_vp, "mknod");
1334         return (error);
1335 }
1336
1337 /*
1338  * mknod_args(char *path, int mode, int dev)
1339  *
1340  * Create a special file.
1341  */
1342 int
1343 mknod(struct mknod_args *uap)
1344 {
1345         struct thread *td = curthread;
1346         struct nameidata nd;
1347         int error;
1348
1349         NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path,
1350             td);
1351
1352         error = kern_mknod(&nd, uap->mode, uap->dev);
1353
1354         return (error);
1355 }
1356
1357 int
1358 kern_mkfifo(struct nameidata *nd, int mode)
1359 {
1360         struct thread *td = curthread;
1361         struct proc *p = td->td_proc;
1362         struct vattr vattr;
1363         int error;
1364
1365         bwillwrite();
1366         error = namei(nd);
1367         if (error)
1368                 return (error);
1369         if (nd->ni_vp != NULL) {
1370                 NDFREE(nd, NDF_ONLY_PNBUF);
1371                 if (nd->ni_dvp == nd->ni_vp)
1372                         vrele(nd->ni_dvp);
1373                 else
1374                         vput(nd->ni_dvp);
1375                 vrele(nd->ni_vp);
1376                 return (EEXIST);
1377         }
1378         VATTR_NULL(&vattr);
1379         vattr.va_type = VFIFO;
1380         vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1381         VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
1382         error = VOP_MKNOD(nd->ni_dvp, NCPNULL, &nd->ni_vp, &nd->ni_cnd, &vattr);
1383         if (error == 0)
1384                 vput(nd->ni_vp);
1385         NDFREE(nd, NDF_ONLY_PNBUF);
1386         vput(nd->ni_dvp);
1387         return (error);
1388 }
1389
1390 /*
1391  * mkfifo_args(char *path, int mode)
1392  *
1393  * Create a named pipe.
1394  */
1395 int
1396 mkfifo(struct mkfifo_args *uap)
1397 {
1398         struct thread *td = curthread;
1399         struct nameidata nd;
1400         int error;
1401
1402         NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path,
1403             td);
1404
1405         error = kern_mkfifo(&nd, uap->mode);
1406
1407         return (error);
1408 }
1409
1410 int
1411 kern_link(struct nameidata *nd, struct nameidata *linknd)
1412 {
1413         struct thread *td = curthread;
1414         struct proc *p = td->td_proc;
1415         struct vnode *vp;
1416         int error;
1417
1418         bwillwrite();
1419         error = namei(nd);
1420         if (error)
1421                 return (error);
1422         NDFREE(nd, NDF_ONLY_PNBUF);
1423         vp = nd->ni_vp;
1424         if (vp->v_type == VDIR)
1425                 error = EPERM;          /* POSIX */
1426         else {
1427                 error = namei(linknd);
1428                 if (error == 0) {
1429                         if (linknd->ni_vp != NULL) {
1430                                 if (linknd->ni_vp)
1431                                         vrele(linknd->ni_vp);
1432                                 error = EEXIST;
1433                         } else {
1434                                 VOP_LEASE(linknd->ni_dvp, td, p->p_ucred,
1435                                     LEASE_WRITE);
1436                                 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1437                                 error = VOP_LINK(linknd->ni_dvp, NCPNULL, vp,
1438                                     &linknd->ni_cnd);
1439                         }
1440                         NDFREE(linknd, NDF_ONLY_PNBUF);
1441                         if (linknd->ni_dvp == linknd->ni_vp)
1442                                 vrele(linknd->ni_dvp);
1443                         else
1444                                 vput(linknd->ni_dvp);
1445                         ASSERT_VOP_UNLOCKED(linknd->ni_dvp, "link");
1446                         ASSERT_VOP_UNLOCKED(linknd->ni_vp, "link");
1447                 }
1448         }
1449         vrele(vp);
1450         return (error);
1451 }
1452
1453 /*
1454  * link_args(char *path, char *link)
1455  *
1456  * Make a hard file link.
1457  */
1458 int
1459 link(struct link_args *uap)
1460 {
1461         struct thread *td = curthread;
1462         struct nameidata nd, linknd;
1463         int error;
1464
1465         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_NOOBJ, UIO_USERSPACE,
1466             uap->path, td);
1467         NDINIT(&linknd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ,
1468             UIO_USERSPACE, uap->link, td);
1469
1470         error = kern_link(&nd, &linknd);
1471
1472         return (error);
1473 }
1474
1475 int
1476 kern_symlink(char *path, struct nameidata *nd)
1477 {
1478         struct thread *td = curthread;
1479         struct proc *p = td->td_proc;
1480         struct vattr vattr;
1481         int error;
1482
1483         bwillwrite();
1484         error = namei(nd);
1485         if (error)
1486                 return (error);
1487         if (nd->ni_vp) {
1488                 NDFREE(nd, NDF_ONLY_PNBUF);
1489                 if (nd->ni_dvp == nd->ni_vp)
1490                         vrele(nd->ni_dvp);
1491                 else
1492                         vput(nd->ni_dvp);
1493                 vrele(nd->ni_vp);
1494                 return (EEXIST);
1495         }
1496         VATTR_NULL(&vattr);
1497         vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1498         VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
1499         error = VOP_SYMLINK(nd->ni_dvp, NCPNULL, &nd->ni_vp, &nd->ni_cnd,
1500             &vattr, path);
1501         NDFREE(nd, NDF_ONLY_PNBUF);
1502         if (error == 0)
1503                 vput(nd->ni_vp);
1504         vput(nd->ni_dvp);
1505         ASSERT_VOP_UNLOCKED(nd->ni_dvp, "symlink");
1506         ASSERT_VOP_UNLOCKED(nd->ni_vp, "symlink");
1507
1508         return (error);
1509 }
1510
1511 /*
1512  * symlink(char *path, char *link)
1513  *
1514  * Make a symbolic link.
1515  */
1516 int
1517 symlink(struct symlink_args *uap)
1518 {
1519         struct thread *td = curthread;
1520         struct nameidata nd;
1521         char *path;
1522         int error;
1523
1524         path = zalloc(namei_zone);
1525         error = copyinstr(uap->path, path, MAXPATHLEN, NULL);
1526         if (error == 0) {
1527                 NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ, 
1528                         UIO_USERSPACE, uap->link, td);
1529                 error = kern_symlink(path, &nd);
1530         }
1531         zfree(namei_zone, path);
1532         return (error);
1533 }
1534
1535 /*
1536  * undelete_args(char *path)
1537  *
1538  * Delete a whiteout from the filesystem.
1539  */
1540 /* ARGSUSED */
1541 int
1542 undelete(struct undelete_args *uap)
1543 {
1544         struct thread *td = curthread;
1545         struct proc *p = td->td_proc;
1546         int error;
1547         struct nameidata nd;
1548
1549         bwillwrite();
1550         NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_DOWHITEOUT, UIO_USERSPACE,
1551             SCARG(uap, path), td);
1552         error = namei(&nd);
1553         if (error)
1554                 return (error);
1555
1556         if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & CNP_ISWHITEOUT)) {
1557                 NDFREE(&nd, NDF_ONLY_PNBUF);
1558                 if (nd.ni_dvp == nd.ni_vp)
1559                         vrele(nd.ni_dvp);
1560                 else
1561                         vput(nd.ni_dvp);
1562                 if (nd.ni_vp)
1563                         vrele(nd.ni_vp);
1564                 return (EEXIST);
1565         }
1566
1567         VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
1568         error = VOP_WHITEOUT(nd.ni_dvp, NCPNULL, &nd.ni_cnd, NAMEI_DELETE);
1569         NDFREE(&nd, NDF_ONLY_PNBUF);
1570         vput(nd.ni_dvp);
1571         ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1572         ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1573         return (error);
1574 }
1575
1576 int
1577 kern_unlink(struct nameidata *nd)
1578 {
1579         struct thread *td = curthread;
1580         struct proc *p = td->td_proc;
1581         struct vnode *vp;
1582         int error;
1583
1584         bwillwrite();
1585         error = namei(nd);
1586         if (error)
1587                 return (error);
1588         vp = nd->ni_vp;
1589         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1590         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
1591
1592         if (vp->v_type == VDIR)
1593                 error = EPERM;          /* POSIX */
1594         else {
1595                 /*
1596                  * The root of a mounted filesystem cannot be deleted.
1597                  *
1598                  * XXX: can this only be a VDIR case?
1599                  */
1600                 if (vp->v_flag & VROOT)
1601                         error = EBUSY;
1602         }
1603
1604         if (error == 0) {
1605                 VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
1606                 error = VOP_REMOVE(nd->ni_dvp, NCPNULL, vp, &nd->ni_cnd);
1607         }
1608         NDFREE(nd, NDF_ONLY_PNBUF);
1609         if (nd->ni_dvp == vp)
1610                 vrele(nd->ni_dvp);
1611         else
1612                 vput(nd->ni_dvp);
1613         if (vp != NULLVP)
1614                 vput(vp);
1615         ASSERT_VOP_UNLOCKED(nd->ni_dvp, "unlink");
1616         ASSERT_VOP_UNLOCKED(nd->ni_vp, "unlink");
1617         return (error);
1618 }
1619
1620 /*
1621  * unlink_args(char *path)
1622  *
1623  * Delete a name from the filesystem.
1624  */
1625 int
1626 unlink(struct unlink_args *uap)
1627 {
1628         struct thread *td = curthread;
1629         struct nameidata nd;
1630         int error;
1631
1632         NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path,
1633             td);
1634
1635         error = kern_unlink(&nd);
1636
1637         return (error);
1638 }
1639
1640 int
1641 kern_lseek(int fd, off_t offset, int whence, off_t *res)
1642 {
1643         struct thread *td = curthread;
1644         struct proc *p = td->td_proc;
1645         struct filedesc *fdp = p->p_fd;
1646         struct file *fp;
1647         struct vattr vattr;
1648         int error;
1649
1650         if (fd >= fdp->fd_nfiles ||
1651             (fp = fdp->fd_ofiles[fd]) == NULL)
1652                 return (EBADF);
1653         if (fp->f_type != DTYPE_VNODE)
1654                 return (ESPIPE);
1655         switch (whence) {
1656         case L_INCR:
1657                 fp->f_offset += offset;
1658                 break;
1659         case L_XTND:
1660                 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, td);
1661                 if (error)
1662                         return (error);
1663                 fp->f_offset = offset + vattr.va_size;
1664                 break;
1665         case L_SET:
1666                 fp->f_offset = offset;
1667                 break;
1668         default:
1669                 return (EINVAL);
1670         }
1671         *res = fp->f_offset;
1672         return (0);
1673 }
1674
1675 /*
1676  * lseek_args(int fd, int pad, off_t offset, int whence)
1677  *
1678  * Reposition read/write file offset.
1679  */
1680 int
1681 lseek(struct lseek_args *uap)
1682 {
1683         int error;
1684
1685         error = kern_lseek(uap->fd, uap->offset, uap->whence,
1686             &uap->sysmsg_offset);
1687
1688         return (error);
1689 }
1690
1691 int
1692 kern_access(struct nameidata *nd, int aflags)
1693 {
1694         struct thread *td = curthread;
1695         struct proc *p = td->td_proc;
1696         struct ucred *cred, *tmpcred;
1697         struct vnode *vp;
1698         int error, flags;
1699
1700         cred = p->p_ucred;
1701         /*
1702          * Create and modify a temporary credential instead of one that
1703          * is potentially shared.  This could also mess up socket
1704          * buffer accounting which can run in an interrupt context.
1705          */
1706         tmpcred = crdup(cred);
1707         tmpcred->cr_uid = p->p_ucred->cr_ruid;
1708         tmpcred->cr_groups[0] = p->p_ucred->cr_rgid;
1709         p->p_ucred = tmpcred;
1710         nd->ni_cnd.cn_cred = tmpcred;
1711         error = namei(nd);
1712         if (error)
1713                 goto out1;
1714         vp = nd->ni_vp;
1715
1716         /* Flags == 0 means only check for existence. */
1717         if (aflags) {
1718                 flags = 0;
1719                 if (aflags & R_OK)
1720                         flags |= VREAD;
1721                 if (aflags & W_OK)
1722                         flags |= VWRITE;
1723                 if (aflags & X_OK)
1724                         flags |= VEXEC;
1725                 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1726                         error = VOP_ACCESS(vp, flags, tmpcred, td);
1727         }
1728         NDFREE(nd, NDF_ONLY_PNBUF);
1729         vput(vp);
1730 out1:
1731         p->p_ucred = cred;
1732         crfree(tmpcred);
1733         return (error);
1734 }
1735
1736 /*
1737  * access_args(char *path, int flags)
1738  *
1739  * Check access permissions.
1740  */
1741 int
1742 access(struct access_args *uap)
1743 {
1744         struct thread *td = curthread;
1745         struct nameidata nd;
1746         int error;
1747
1748         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ,
1749             UIO_USERSPACE, uap->path, td);
1750
1751         error = kern_access(&nd, uap->flags);
1752
1753         return (error);
1754 }
1755
1756 int
1757 kern_stat(struct nlookupdata *nd, struct stat *st)
1758 {
1759         int error;
1760         struct vnode *vp;
1761         thread_t td;
1762
1763         if ((error = nlookup(nd)) != 0)
1764                 return (error);
1765         if ((vp = nd->nl_ncp->nc_vp) == NULL)
1766                 return (ENOENT);
1767
1768         td = curthread;
1769         if ((error = vget(vp, NULL, LK_SHARED, td)) != 0)
1770                 return (error);
1771         error = vn_stat(vp, st, td);
1772         vput(vp);
1773         return (error);
1774 }
1775
1776 /*
1777  * stat_args(char *path, struct stat *ub)
1778  *
1779  * Get file status; this version follows links.
1780  */
1781 int
1782 stat(struct stat_args *uap)
1783 {
1784         struct nlookupdata nd;
1785         struct stat st;
1786         int error;
1787
1788         error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
1789         if (error == 0) {
1790                 error = kern_stat(&nd, &st);
1791                 if (error == 0)
1792                         error = copyout(&st, uap->ub, sizeof(*uap->ub));
1793                 nlookup_done(&nd);
1794         }
1795         return (error);
1796 }
1797
1798 /*
1799  * lstat_args(char *path, struct stat *ub)
1800  *
1801  * Get file status; this version does not follow links.
1802  */
1803 int
1804 lstat(struct lstat_args *uap)
1805 {
1806         struct nlookupdata nd;
1807         struct stat st;
1808         int error;
1809
1810         error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0);
1811         if (error == 0) {
1812                 error = kern_stat(&nd, &st);
1813                 if (error == 0)
1814                         error = copyout(&st, uap->ub, sizeof(*uap->ub));
1815                 nlookup_done(&nd);
1816         }
1817         return (error);
1818 }
1819
1820 void
1821 cvtnstat(sb, nsb)
1822         struct stat *sb;
1823         struct nstat *nsb;
1824 {
1825         nsb->st_dev = sb->st_dev;
1826         nsb->st_ino = sb->st_ino;
1827         nsb->st_mode = sb->st_mode;
1828         nsb->st_nlink = sb->st_nlink;
1829         nsb->st_uid = sb->st_uid;
1830         nsb->st_gid = sb->st_gid;
1831         nsb->st_rdev = sb->st_rdev;
1832         nsb->st_atimespec = sb->st_atimespec;
1833         nsb->st_mtimespec = sb->st_mtimespec;
1834         nsb->st_ctimespec = sb->st_ctimespec;
1835         nsb->st_size = sb->st_size;
1836         nsb->st_blocks = sb->st_blocks;
1837         nsb->st_blksize = sb->st_blksize;
1838         nsb->st_flags = sb->st_flags;
1839         nsb->st_gen = sb->st_gen;
1840         nsb->st_qspare[0] = sb->st_qspare[0];
1841         nsb->st_qspare[1] = sb->st_qspare[1];
1842 }
1843
1844 /*
1845  * nstat_args(char *path, struct nstat *ub)
1846  */
1847 /* ARGSUSED */
1848 int
1849 nstat(struct nstat_args *uap)
1850 {
1851         struct thread *td = curthread;
1852         struct stat sb;
1853         struct nstat nsb;
1854         int error;
1855         struct nameidata nd;
1856
1857         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ,
1858             UIO_USERSPACE, SCARG(uap, path), td);
1859         if ((error = namei(&nd)) != 0)
1860                 return (error);
1861         NDFREE(&nd, NDF_ONLY_PNBUF);
1862         error = vn_stat(nd.ni_vp, &sb, td);
1863         vput(nd.ni_vp);
1864         if (error)
1865                 return (error);
1866         cvtnstat(&sb, &nsb);
1867         error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb));
1868         return (error);
1869 }
1870
1871 /*
1872  * lstat_args(char *path, struct stat *ub)
1873  *
1874  * Get file status; this version does not follow links.
1875  */
1876 /* ARGSUSED */
1877 int
1878 nlstat(struct nlstat_args *uap)
1879 {
1880         struct thread *td = curthread;
1881         int error;
1882         struct vnode *vp;
1883         struct stat sb;
1884         struct nstat nsb;
1885         struct nameidata nd;
1886
1887         NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ,
1888             UIO_USERSPACE, SCARG(uap, path), td);
1889         if ((error = namei(&nd)) != 0)
1890                 return (error);
1891         vp = nd.ni_vp;
1892         NDFREE(&nd, NDF_ONLY_PNBUF);
1893         error = vn_stat(vp, &sb, td);
1894         vput(vp);
1895         if (error)
1896                 return (error);
1897         cvtnstat(&sb, &nsb);
1898         error = copyout(&nsb, SCARG(uap, ub), sizeof (nsb));
1899         return (error);
1900 }
1901
1902 /*
1903  * pathconf_Args(char *path, int name)
1904  *
1905  * Get configurable pathname variables.
1906  */
1907 /* ARGSUSED */
1908 int
1909 pathconf(struct pathconf_args *uap)
1910 {
1911         struct thread *td = curthread;
1912         int error;
1913         struct nameidata nd;
1914
1915         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF | CNP_NOOBJ,
1916             UIO_USERSPACE, SCARG(uap, path), td);
1917         if ((error = namei(&nd)) != 0)
1918                 return (error);
1919         NDFREE(&nd, NDF_ONLY_PNBUF);
1920         error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), uap->sysmsg_fds);
1921         vput(nd.ni_vp);
1922         return (error);
1923 }
1924
1925 /*
1926  * XXX: daver
1927  * kern_readlink isn't properly split yet.  There is a copyin burried
1928  * in VOP_READLINK().
1929  */
1930 int
1931 kern_readlink(struct nameidata *nd, char *buf, int count, int *res)
1932 {
1933         struct thread *td = curthread;
1934         struct proc *p = td->td_proc;
1935         struct vnode *vp;
1936         struct iovec aiov;
1937         struct uio auio;
1938         int error;
1939
1940         error = namei(nd);
1941         if (error)
1942                 return (error);
1943         NDFREE(nd, NDF_ONLY_PNBUF);
1944         vp = nd->ni_vp;
1945         if (vp->v_type != VLNK)
1946                 error = EINVAL;
1947         else {
1948                 aiov.iov_base = buf;
1949                 aiov.iov_len = count;
1950                 auio.uio_iov = &aiov;
1951                 auio.uio_iovcnt = 1;
1952                 auio.uio_offset = 0;
1953                 auio.uio_rw = UIO_READ;
1954                 auio.uio_segflg = UIO_USERSPACE;
1955                 auio.uio_td = td;
1956                 auio.uio_resid = count;
1957                 error = VOP_READLINK(vp, &auio, p->p_ucred);
1958         }
1959         vput(vp);
1960         *res = count - auio.uio_resid;
1961         return (error);
1962 }
1963
1964 /*
1965  * readlink_args(char *path, char *buf, int count)
1966  *
1967  * Return target name of a symbolic link.
1968  */
1969 int
1970 readlink(struct readlink_args *uap)
1971 {
1972         struct thread *td = curthread;
1973         struct nameidata nd;
1974         int error;
1975
1976         NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_NOOBJ, UIO_USERSPACE,
1977             uap->path, td);
1978
1979         error = kern_readlink(&nd, uap->buf, uap->count,
1980             &uap->sysmsg_result);
1981
1982         return (error);
1983 }
1984
1985 static int
1986 setfflags(struct vnode *vp, int flags)
1987 {
1988         struct thread *td = curthread;
1989         struct proc *p = td->td_proc;
1990         int error;
1991         struct vattr vattr;
1992
1993         /*
1994          * Prevent non-root users from setting flags on devices.  When
1995          * a device is reused, users can retain ownership of the device
1996          * if they are allowed to set flags and programs assume that
1997          * chown can't fail when done as root.
1998          */
1999         if ((vp->v_type == VCHR || vp->v_type == VBLK) && 
2000             ((error = suser_cred(p->p_ucred, PRISON_ROOT)) != 0))
2001                 return (error);
2002
2003         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2004         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2005         VATTR_NULL(&vattr);
2006         vattr.va_flags = flags;
2007         error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
2008         VOP_UNLOCK(vp, NULL, 0, td);
2009         return (error);
2010 }
2011
2012 /*
2013  * chflags(char *path, int flags)
2014  *
2015  * Change flags of a file given a path name.
2016  */
2017 /* ARGSUSED */
2018 int
2019 chflags(struct chflags_args *uap)
2020 {
2021         struct thread *td = curthread;
2022         int error;
2023         struct nameidata nd;
2024
2025         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE,
2026             SCARG(uap, path), td);
2027         if ((error = namei(&nd)) != 0)
2028                 return (error);
2029         NDFREE(&nd, NDF_ONLY_PNBUF);
2030         error = setfflags(nd.ni_vp, SCARG(uap, flags));
2031         vrele(nd.ni_vp);
2032         return error;
2033 }
2034
2035 /*
2036  * fchflags_args(int fd, int flags)
2037  *
2038  * Change flags of a file given a file descriptor.
2039  */
2040 /* ARGSUSED */
2041 int
2042 fchflags(struct fchflags_args *uap)
2043 {
2044         struct thread *td = curthread;
2045         struct proc *p = td->td_proc;
2046         struct file *fp;
2047         int error;
2048
2049         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2050                 return (error);
2051         return setfflags((struct vnode *) fp->f_data, SCARG(uap, flags));
2052 }
2053
2054 static int
2055 setfmode(struct vnode *vp, int mode)
2056 {
2057         struct thread *td = curthread;
2058         struct proc *p = td->td_proc;
2059         int error;
2060         struct vattr vattr;
2061
2062         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2063         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2064         VATTR_NULL(&vattr);
2065         vattr.va_mode = mode & ALLPERMS;
2066         error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
2067         VOP_UNLOCK(vp, NULL, 0, td);
2068         return error;
2069 }
2070
2071 int
2072 kern_chmod(struct nameidata *nd, int mode)
2073 {
2074         int error;
2075
2076         error = namei(nd);
2077         if (error)
2078                 return (error);
2079         NDFREE(nd, NDF_ONLY_PNBUF);
2080         error = setfmode(nd->ni_vp, mode);
2081         vrele(nd->ni_vp);
2082         return error;
2083 }
2084
2085 /*
2086  * chmod_args(char *path, int mode)
2087  *
2088  * Change mode of a file given path name.
2089  */
2090 /* ARGSUSED */
2091 int
2092 chmod(struct chmod_args *uap)
2093 {
2094         struct thread *td = curthread;
2095         struct nameidata nd;
2096         int error;
2097
2098         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
2099
2100         error = kern_chmod(&nd, uap->mode);
2101
2102         return (error);
2103 }
2104
2105 /*
2106  * lchmod_args(char *path, int mode)
2107  *
2108  * Change mode of a file given path name (don't follow links.)
2109  */
2110 /* ARGSUSED */
2111 int
2112 lchmod(struct lchmod_args *uap)
2113 {
2114         struct thread *td = curthread;
2115         int error;
2116         struct nameidata nd;
2117
2118         NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, SCARG(uap, path), td);
2119         if ((error = namei(&nd)) != 0)
2120                 return (error);
2121         NDFREE(&nd, NDF_ONLY_PNBUF);
2122         error = setfmode(nd.ni_vp, SCARG(uap, mode));
2123         vrele(nd.ni_vp);
2124         return error;
2125 }
2126
2127 /*
2128  * fchmod_args(int fd, int mode)
2129  *
2130  * Change mode of a file given a file descriptor.
2131  */
2132 /* ARGSUSED */
2133 int
2134 fchmod(struct fchmod_args *uap)
2135 {
2136         struct thread *td = curthread;
2137         struct proc *p = td->td_proc;
2138         struct file *fp;
2139         int error;
2140
2141         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2142                 return (error);
2143         return setfmode((struct vnode *)fp->f_data, SCARG(uap, mode));
2144 }
2145
2146 static int
2147 setfown(struct vnode *vp, uid_t uid, gid_t gid)
2148 {
2149         struct thread *td = curthread;
2150         struct proc *p = td->td_proc;
2151         int error;
2152         struct vattr vattr;
2153
2154         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2155         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2156         VATTR_NULL(&vattr);
2157         vattr.va_uid = uid;
2158         vattr.va_gid = gid;
2159         error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
2160         VOP_UNLOCK(vp, NULL, 0, td);
2161         return error;
2162 }
2163
2164 int
2165 kern_chown(struct nameidata *nd, int uid, int gid)
2166 {
2167         int error;
2168
2169         error = namei(nd);
2170         if (error)
2171                 return (error);
2172         NDFREE(nd, NDF_ONLY_PNBUF);
2173         error = setfown(nd->ni_vp, uid, gid);
2174         vrele(nd->ni_vp);
2175         return (error);
2176 }
2177
2178 /*
2179  * chown(char *path, int uid, int gid)
2180  *
2181  * Set ownership given a path name.
2182  */
2183 int
2184 chown(struct chown_args *uap)
2185 {
2186         struct thread *td = curthread;
2187         struct nameidata nd;
2188         int error;
2189
2190         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
2191
2192         error = kern_chown(&nd, uap->uid, uap->gid);
2193
2194         return (error);
2195 }
2196
2197 /*
2198  * lchown_args(char *path, int uid, int gid)
2199  *
2200  * Set ownership given a path name, do not cross symlinks.
2201  */
2202 int
2203 lchown(struct lchown_args *uap)
2204 {
2205         struct thread *td = curthread;
2206         int error;
2207         struct nameidata nd;
2208
2209         NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->path, td);
2210
2211         error = kern_chown(&nd, uap->uid, uap->gid);
2212
2213         return (error);
2214 }
2215
2216 /*
2217  * fchown_args(int fd, int uid, int gid)
2218  *
2219  * Set ownership given a file descriptor.
2220  */
2221 /* ARGSUSED */
2222 int
2223 fchown(struct fchown_args *uap)
2224 {
2225         struct thread *td = curthread;
2226         struct proc *p = td->td_proc;
2227         struct file *fp;
2228         int error;
2229
2230         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2231                 return (error);
2232         return setfown((struct vnode *)fp->f_data,
2233                 SCARG(uap, uid), SCARG(uap, gid));
2234 }
2235
2236 static int
2237 getutimes(const struct timeval *tvp, struct timespec *tsp)
2238 {
2239         struct timeval tv[2];
2240
2241         if (tvp == NULL) {
2242                 microtime(&tv[0]);
2243                 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2244                 tsp[1] = tsp[0];
2245         } else {
2246                 TIMEVAL_TO_TIMESPEC(&tvp[0], &tsp[0]);
2247                 TIMEVAL_TO_TIMESPEC(&tvp[1], &tsp[1]);
2248         }
2249         return 0;
2250 }
2251
2252 static int
2253 setutimes(struct vnode *vp, const struct timespec *ts, int nullflag)
2254 {
2255         struct thread *td = curthread;
2256         struct proc *p = td->td_proc;
2257         int error;
2258         struct vattr vattr;
2259
2260         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2261         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2262         VATTR_NULL(&vattr);
2263         vattr.va_atime = ts[0];
2264         vattr.va_mtime = ts[1];
2265         if (nullflag)
2266                 vattr.va_vaflags |= VA_UTIMES_NULL;
2267         error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
2268         VOP_UNLOCK(vp, NULL, 0, td);
2269         return error;
2270 }
2271
2272 int
2273 kern_utimes(struct nameidata *nd, struct timeval *tptr)
2274 {
2275         struct timespec ts[2];
2276         int error;
2277
2278         error = getutimes(tptr, ts);
2279         if (error)
2280                 return (error);
2281         error = namei(nd);
2282         if (error)
2283                 return (error);
2284         NDFREE(nd, NDF_ONLY_PNBUF);
2285         error = setutimes(nd->ni_vp, ts, tptr == NULL);
2286         vrele(nd->ni_vp);
2287         return (error);
2288 }
2289
2290 /*
2291  * utimes_args(char *path, struct timeval *tptr)
2292  *
2293  * Set the access and modification times of a file.
2294  */
2295 int
2296 utimes(struct utimes_args *uap)
2297 {
2298         struct thread *td = curthread;
2299         struct timeval tv[2];
2300         struct nameidata nd;
2301         int error;
2302
2303         if (uap->tptr) {
2304                 error = copyin(uap->tptr, tv, sizeof(tv));
2305                 if (error)
2306                         return (error);
2307         }
2308         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
2309
2310         error = kern_utimes(&nd, uap->tptr ? tv : NULL);
2311
2312         return (error);
2313 }
2314
2315 /*
2316  * lutimes_args(char *path, struct timeval *tptr)
2317  *
2318  * Set the access and modification times of a file.
2319  */
2320 int
2321 lutimes(struct lutimes_args *uap)
2322 {
2323         struct thread *td = curthread;
2324         struct timeval tv[2];
2325         struct nameidata nd;
2326         int error;
2327
2328         if (uap->tptr) {
2329                 error = copyin(uap->tptr, tv, sizeof(tv));
2330                 if (error)
2331                         return (error);
2332         }
2333         NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_USERSPACE, uap->path, td);
2334
2335         error = kern_utimes(&nd, uap->tptr ? tv : NULL);
2336
2337         return (error);
2338 }
2339
2340 int
2341 kern_futimes(int fd, struct timeval *tptr)
2342 {
2343         struct thread *td = curthread;
2344         struct proc *p = td->td_proc;
2345         struct timespec ts[2];
2346         struct file *fp;
2347         int error;
2348
2349         error = getutimes(tptr, ts);
2350         if (error)
2351                 return (error);
2352         error = getvnode(p->p_fd, fd, &fp);
2353         if (error)
2354                 return (error);
2355         error =  setutimes((struct vnode *)fp->f_data, ts, tptr == NULL);
2356         return (error);
2357 }
2358
2359 /*
2360  * futimes_args(int fd, struct timeval *tptr)
2361  *
2362  * Set the access and modification times of a file.
2363  */
2364 int
2365 futimes(struct futimes_args *uap)
2366 {
2367         struct timeval tv[2];
2368         int error;
2369
2370         if (uap->tptr) {
2371                 error = copyin(uap->tptr, tv, sizeof(tv));
2372                 if (error)
2373                         return (error);
2374         }
2375
2376         error = kern_futimes(uap->fd, uap->tptr ? tv : NULL);
2377
2378         return (error);
2379 }
2380
2381 int
2382 kern_truncate(struct nameidata* nd, off_t length)
2383 {
2384         struct thread *td = curthread;
2385         struct proc *p = td->td_proc;
2386         struct vnode *vp;
2387         struct vattr vattr;
2388         int error;
2389
2390         if (length < 0)
2391                 return(EINVAL);
2392         if ((error = namei(nd)) != 0)
2393                 return (error);
2394         vp = nd->ni_vp;
2395         NDFREE(nd, NDF_ONLY_PNBUF);
2396         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2397         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2398         if (vp->v_type == VDIR)
2399                 error = EISDIR;
2400         else if ((error = vn_writechk(vp)) == 0 &&
2401             (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, td)) == 0) {
2402                 VATTR_NULL(&vattr);
2403                 vattr.va_size = length;
2404                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
2405         }
2406         vput(vp);
2407         return (error);
2408 }
2409
2410 /*
2411  * truncate(char *path, int pad, off_t length)
2412  *
2413  * Truncate a file given its path name.
2414  */
2415 int
2416 truncate(struct truncate_args *uap)
2417 {
2418         struct thread *td = curthread;
2419         struct nameidata nd;
2420         int error;
2421
2422         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, uap->path, td);
2423
2424         error = kern_truncate(&nd, uap->length);
2425
2426         return error;
2427 }
2428
2429 int
2430 kern_ftruncate(int fd, off_t length)
2431 {
2432         struct thread *td = curthread;
2433         struct proc *p = td->td_proc;
2434         struct vattr vattr;
2435         struct vnode *vp;
2436         struct file *fp;
2437         int error;
2438
2439         if (length < 0)
2440                 return(EINVAL);
2441         if ((error = getvnode(p->p_fd, fd, &fp)) != 0)
2442                 return (error);
2443         if ((fp->f_flag & FWRITE) == 0)
2444                 return (EINVAL);
2445         vp = (struct vnode *)fp->f_data;
2446         VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2447         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2448         if (vp->v_type == VDIR)
2449                 error = EISDIR;
2450         else if ((error = vn_writechk(vp)) == 0) {
2451                 VATTR_NULL(&vattr);
2452                 vattr.va_size = length;
2453                 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2454         }
2455         VOP_UNLOCK(vp, NULL, 0, td);
2456         return (error);
2457 }
2458
2459 /*
2460  * ftruncate_args(int fd, int pad, off_t length)
2461  *
2462  * Truncate a file given a file descriptor.
2463  */
2464 int
2465 ftruncate(struct ftruncate_args *uap)
2466 {
2467         int error;
2468
2469         error = kern_ftruncate(uap->fd, uap->length);
2470
2471         return (error);
2472 }
2473
2474 /*
2475  * fsync(int fd)
2476  *
2477  * Sync an open file.
2478  */
2479 /* ARGSUSED */
2480 int
2481 fsync(struct fsync_args *uap)
2482 {
2483         struct thread *td = curthread;
2484         struct proc *p = td->td_proc;
2485         struct vnode *vp;
2486         struct file *fp;
2487         vm_object_t obj;
2488         int error;
2489
2490         if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2491                 return (error);
2492         vp = (struct vnode *)fp->f_data;
2493         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2494         if (VOP_GETVOBJECT(vp, &obj) == 0)
2495                 vm_object_page_clean(obj, 0, 0, 0);
2496         if ((error = VOP_FSYNC(vp, MNT_WAIT, td)) == 0 &&
2497             vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP) &&
2498             bioops.io_fsync)
2499                 error = (*bioops.io_fsync)(vp);
2500         VOP_UNLOCK(vp, NULL, 0, td);
2501         return (error);
2502 }
2503
2504 int
2505 kern_rename(struct nameidata *fromnd, struct nameidata *tond)
2506 {
2507         struct thread *td = curthread;
2508         struct proc *p = td->td_proc;
2509         struct vnode *tvp, *fvp, *tdvp;
2510         int error;
2511
2512         bwillwrite();
2513         error = namei(fromnd);
2514         if (error)
2515                 return (error);
2516         fvp = fromnd->ni_vp;
2517         if (fromnd->ni_vp->v_type == VDIR)
2518                 tond->ni_cnd.cn_flags |= CNP_WILLBEDIR;
2519         error = namei(tond);
2520         if (error) {
2521                 /* Translate error code for rename("dir1", "dir2/."). */
2522                 if (error == EISDIR && fvp->v_type == VDIR)
2523                         error = EINVAL;
2524                 NDFREE(fromnd, NDF_ONLY_PNBUF);
2525                 vrele(fromnd->ni_dvp);
2526                 vrele(fvp);
2527                 goto out1;
2528         }
2529         tdvp = tond->ni_dvp;
2530         tvp = tond->ni_vp;
2531         if (tvp != NULL) {
2532                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2533                         error = ENOTDIR;
2534                         goto out;
2535                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2536                         error = EISDIR;
2537                         goto out;
2538                 }
2539         }
2540         if (fvp == tdvp)
2541                 error = EINVAL;
2542         /*
2543          * If the source is the same as the destination (that is, if they
2544          * are links to the same vnode), then there is nothing to do.
2545          */
2546         if (fvp == tvp)
2547                 error = -1;
2548 out:
2549         if (!error) {
2550                 VOP_LEASE(tdvp, td, p->p_ucred, LEASE_WRITE);
2551                 if (fromnd->ni_dvp != tdvp) {
2552                         VOP_LEASE(fromnd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
2553                 }
2554                 if (tvp) {
2555                         VOP_LEASE(tvp, td, p->p_ucred, LEASE_WRITE);
2556                 }
2557                 error = VOP_RENAME(fromnd->ni_dvp, NCPNULL, fromnd->ni_vp,
2558                     &fromnd->ni_cnd, tond->ni_dvp, NCPNULL, tond->ni_vp,
2559                     &tond->ni_cnd);
2560                 NDFREE(fromnd, NDF_ONLY_PNBUF);
2561                 NDFREE(tond, NDF_ONLY_PNBUF);
2562         } else {
2563                 NDFREE(fromnd, NDF_ONLY_PNBUF);
2564                 NDFREE(tond, NDF_ONLY_PNBUF);
2565                 if (tdvp == tvp)
2566                         vrele(tdvp);
2567                 else
2568                         vput(tdvp);
2569                 if (tvp)
2570                         vput(tvp);
2571                 vrele(fromnd->ni_dvp);
2572                 vrele(fvp);
2573         }
2574         vrele(tond->ni_startdir);
2575         ASSERT_VOP_UNLOCKED(fromnd->ni_dvp, "rename");
2576         ASSERT_VOP_UNLOCKED(fromnd->ni_vp, "rename");
2577         ASSERT_VOP_UNLOCKED(tond->ni_dvp, "rename");
2578         ASSERT_VOP_UNLOCKED(tond->ni_vp, "rename");
2579 out1:
2580         if (fromnd->ni_startdir)
2581                 vrele(fromnd->ni_startdir);
2582         if (error == -1)
2583                 return (0);
2584         return (error);
2585 }
2586
2587 /*
2588  * rename_args(char *from, char *to)
2589  *
2590  * Rename files.  Source and destination must either both be directories,
2591  * or both not be directories.  If target is a directory, it must be empty.
2592  */
2593 int
2594 rename(struct rename_args *uap)
2595 {
2596         struct thread *td = curthread;
2597         struct nameidata fromnd, tond;
2598         int error;
2599
2600         NDINIT(&fromnd, NAMEI_DELETE, CNP_WANTPARENT | CNP_SAVESTART,
2601                 UIO_USERSPACE, uap->from, td);
2602         NDINIT(&tond, NAMEI_RENAME, 
2603             CNP_LOCKPARENT | CNP_LOCKLEAF | CNP_NOCACHE |
2604              CNP_SAVESTART | CNP_NOOBJ,
2605             UIO_USERSPACE, uap->to, td);
2606
2607         error = kern_rename(&fromnd, &tond);
2608
2609         return (error);
2610 }
2611
2612 int
2613 kern_mkdir(struct nameidata *nd, int mode)
2614 {
2615         struct thread *td = curthread;
2616         struct proc *p = td->td_proc;
2617         struct vnode *vp;
2618         struct vattr vattr;
2619         int error;
2620
2621         bwillwrite();
2622         nd->ni_cnd.cn_flags |= CNP_WILLBEDIR;
2623         error = namei(nd);
2624         if (error)
2625                 return (error);
2626         vp = nd->ni_vp;
2627         if (vp) {
2628                 NDFREE(nd, NDF_ONLY_PNBUF);
2629                 if (nd->ni_dvp == vp)
2630                         vrele(nd->ni_dvp);
2631                 else
2632                         vput(nd->ni_dvp);
2633                 vrele(vp);
2634                 return (EEXIST);
2635         }
2636         VATTR_NULL(&vattr);
2637         vattr.va_type = VDIR;
2638         vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2639         VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
2640         error = VOP_MKDIR(nd->ni_dvp, NCPNULL, &nd->ni_vp, &nd->ni_cnd,
2641             &vattr);
2642         NDFREE(nd, NDF_ONLY_PNBUF);
2643         vput(nd->ni_dvp);
2644         if (error == 0)
2645                 vput(nd->ni_vp);
2646         ASSERT_VOP_UNLOCKED(nd->ni_dvp, "mkdir");
2647         ASSERT_VOP_UNLOCKED(nd->ni_vp, "mkdir");
2648         return (error);
2649 }
2650
2651 /*
2652  * mkdir_args(char *path, int mode)
2653  *
2654  * Make a directory file.
2655  */
2656 /* ARGSUSED */
2657 int
2658 mkdir(struct mkdir_args *uap)
2659 {
2660         struct thread *td = curthread;
2661         struct nameidata nd;
2662         int error;
2663
2664         NDINIT(&nd, NAMEI_CREATE, CNP_LOCKPARENT, UIO_USERSPACE, uap->path,
2665             td);
2666
2667         error = kern_mkdir(&nd, uap->mode);
2668
2669         return (error);
2670 }
2671
2672 int
2673 kern_rmdir(struct nameidata *nd)
2674 {
2675         struct thread *td = curthread;
2676         struct proc *p = td->td_proc;
2677         struct vnode *vp;
2678         int error;
2679
2680         bwillwrite();
2681         error = namei(nd);
2682         if (error)
2683                 return (error);
2684         vp = nd->ni_vp;
2685         if (vp->v_type != VDIR) {
2686                 error = ENOTDIR;
2687                 goto out;
2688         }
2689         /*
2690          * No rmdir "." please.
2691          */
2692         if (nd->ni_dvp == vp) {
2693                 error = EINVAL;
2694                 goto out;
2695         }
2696         /*
2697          * The root of a mounted filesystem cannot be deleted.
2698          */
2699         if (vp->v_flag & VROOT)
2700                 error = EBUSY;
2701         else {
2702                 VOP_LEASE(nd->ni_dvp, td, p->p_ucred, LEASE_WRITE);
2703                 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2704                 error = VOP_RMDIR(nd->ni_dvp, NCPNULL, nd->ni_vp,
2705                     &nd->ni_cnd);
2706         }
2707 out:
2708         NDFREE(nd, NDF_ONLY_PNBUF);
2709         if (nd->ni_dvp == vp)
2710                 vrele(nd->ni_dvp);
2711         else
2712                 vput(nd->ni_dvp);
2713         if (vp != NULLVP)
2714                 vput(vp);
2715         ASSERT_VOP_UNLOCKED(nd->ni_dvp, "rmdir");
2716         ASSERT_VOP_UNLOCKED(nd->ni_vp, "rmdir");
2717         return (error);
2718 }
2719
2720 /*
2721  * rmdir_args(char *path)
2722  *
2723  * Remove a directory file.
2724  */
2725 /* ARGSUSED */
2726 int
2727 rmdir(struct rmdir_args *uap)
2728 {
2729         struct thread *td = curthread;
2730         struct nameidata nd;
2731         int error;
2732
2733         NDINIT(&nd, NAMEI_DELETE, CNP_LOCKPARENT | CNP_LOCKLEAF,
2734             UIO_USERSPACE, uap->path, td);
2735
2736         error = kern_rmdir(&nd);
2737
2738         return (error);
2739 }
2740
2741 int
2742 kern_getdirentries(int fd, char *buf, u_int count, long *basep, int *res)
2743 {
2744         struct thread *td = curthread;
2745         struct proc *p = td->td_proc;
2746         struct vnode *vp;
2747         struct file *fp;
2748         struct uio auio;
2749         struct iovec aiov;
2750         long loff;
2751         int error, eofflag;
2752
2753         if ((error = getvnode(p->p_fd, fd, &fp)) != 0)
2754                 return (error);
2755         if ((fp->f_flag & FREAD) == 0)
2756                 return (EBADF);
2757         vp = (struct vnode *)fp->f_data;
2758 unionread:
2759         if (vp->v_type != VDIR)
2760                 return (EINVAL);
2761         aiov.iov_base = buf;
2762         aiov.iov_len = count;
2763         auio.uio_iov = &aiov;
2764         auio.uio_iovcnt = 1;
2765         auio.uio_rw = UIO_READ;
2766         auio.uio_segflg = UIO_USERSPACE;
2767         auio.uio_td = td;
2768         auio.uio_resid = count;
2769         /* vn_lock(vp, NULL, LK_SHARED | LK_RETRY, td); */
2770         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
2771         loff = auio.uio_offset = fp->f_offset;
2772         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
2773         fp->f_offset = auio.uio_offset;
2774         VOP_UNLOCK(vp, NULL, 0, td);
2775         if (error)
2776                 return (error);
2777         if (count == auio.uio_resid) {
2778                 if (union_dircheckp) {
2779                         error = union_dircheckp(td, &vp, fp);
2780                         if (error == -1)
2781                                 goto unionread;
2782                         if (error)
2783                                 return (error);
2784                 }
2785                 if ((vp->v_flag & VROOT) &&
2786                     (vp->v_mount->mnt_flag & MNT_UNION)) {
2787                         struct vnode *tvp = vp;
2788                         vp = vp->v_mount->mnt_vnodecovered;
2789                         vref(vp);
2790                         fp->f_data = (caddr_t)vp;
2791                         fp->f_offset = 0;
2792                         vrele(tvp);
2793                         goto unionread;
2794                 }
2795         }
2796         if (basep) {
2797                 *basep = loff;
2798         }
2799         *res = count - auio.uio_resid;
2800         return (error);
2801 }
2802
2803 /*
2804  * getdirentries_args(int fd, char *buf, u_int conut, long *basep)
2805  *
2806  * Read a block of directory entries in a file system independent format.
2807  */
2808 int
2809 getdirentries(struct getdirentries_args *uap)
2810 {
2811         long base;
2812         int error;
2813
2814         error = kern_getdirentries(uap->fd, uap->buf, uap->count, &base,
2815             &uap->sysmsg_result);
2816
2817         if (error == 0)
2818                 error = copyout(&base, uap->basep, sizeof(*uap->basep));
2819         return (error);
2820 }
2821
2822 /*
2823  * getdents_args(int fd, char *buf, size_t count)
2824  */
2825 int
2826 getdents(struct getdents_args *uap)
2827 {
2828         int error;
2829
2830         error = kern_getdirentries(uap->fd, uap->buf, uap->count, NULL,
2831             &uap->sysmsg_result);
2832
2833         return (error);
2834 }
2835
2836 /*
2837  * umask(int newmask)
2838  *
2839  * Set the mode mask for creation of filesystem nodes.
2840  *
2841  * MP SAFE
2842  */
2843 int
2844 umask(struct umask_args *uap)
2845 {
2846         struct thread *td = curthread;
2847         struct proc *p = td->td_proc;
2848         struct filedesc *fdp;
2849
2850         fdp = p->p_fd;
2851         uap->sysmsg_result = fdp->fd_cmask;
2852         fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2853         return (0);
2854 }
2855
2856 /*
2857  * revoke(char *path)
2858  *
2859  * Void all references to file by ripping underlying filesystem
2860  * away from vnode.
2861  */
2862 /* ARGSUSED */
2863 int
2864 revoke(struct revoke_args *uap)
2865 {
2866         struct thread *td = curthread;
2867         struct proc *p = td->td_proc;
2868         struct vnode *vp;
2869         struct vattr vattr;
2870         int error;
2871         struct nameidata nd;
2872
2873         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2874         if ((error = namei(&nd)) != 0)
2875                 return (error);
2876         vp = nd.ni_vp;
2877         NDFREE(&nd, NDF_ONLY_PNBUF);
2878         if (vp->v_type != VCHR && vp->v_type != VBLK) {
2879                 error = EINVAL;
2880                 goto out;
2881         }
2882         if ((error = VOP_GETATTR(vp, &vattr, td)) != 0)
2883                 goto out;
2884         if (p->p_ucred->cr_uid != vattr.va_uid &&
2885             (error = suser_cred(p->p_ucred, PRISON_ROOT)))
2886                 goto out;
2887         if (count_udev(vp->v_udev) > 0)
2888                 VOP_REVOKE(vp, REVOKEALL);
2889 out:
2890         vrele(vp);
2891         return (error);
2892 }
2893
2894 /*
2895  * Convert a user file descriptor to a kernel file entry.
2896  */
2897 int
2898 getvnode(struct filedesc *fdp, int fd, struct file **fpp)
2899 {
2900         struct file *fp;
2901
2902         if ((u_int)fd >= fdp->fd_nfiles ||
2903             (fp = fdp->fd_ofiles[fd]) == NULL)
2904                 return (EBADF);
2905         if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
2906                 return (EINVAL);
2907         *fpp = fp;
2908         return (0);
2909 }
2910 /*
2911  * getfh_args(char *fname, fhandle_t *fhp)
2912  *
2913  * Get (NFS) file handle
2914  */
2915 int
2916 getfh(struct getfh_args *uap)
2917 {
2918         struct thread *td = curthread;
2919         struct nameidata nd;
2920         fhandle_t fh;
2921         struct vnode *vp;
2922         int error;
2923
2924         /*
2925          * Must be super user
2926          */
2927         error = suser(td);
2928         if (error)
2929                 return (error);
2930         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE, uap->fname, td);
2931         error = namei(&nd);
2932         if (error)
2933                 return (error);
2934         NDFREE(&nd, NDF_ONLY_PNBUF);
2935         vp = nd.ni_vp;
2936         bzero(&fh, sizeof(fh));
2937         fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2938         error = VFS_VPTOFH(vp, &fh.fh_fid);
2939         vput(vp);
2940         if (error)
2941                 return (error);
2942         error = copyout(&fh, uap->fhp, sizeof (fh));
2943         return (error);
2944 }
2945
2946 /*
2947  * fhopen_args(const struct fhandle *u_fhp, int flags)
2948  *
2949  * syscall for the rpc.lockd to use to translate a NFS file handle into
2950  * an open descriptor.
2951  *
2952  * warning: do not remove the suser() call or this becomes one giant
2953  * security hole.
2954  */
2955 int
2956 fhopen(struct fhopen_args *uap)
2957 {
2958         struct thread *td = curthread;
2959         struct proc *p = td->td_proc;
2960         struct mount *mp;
2961         struct vnode *vp;
2962         struct fhandle fhp;
2963         struct vattr vat;
2964         struct vattr *vap = &vat;
2965         struct flock lf;
2966         struct file *fp;
2967         struct filedesc *fdp = p->p_fd;
2968         int fmode, mode, error, type;
2969         struct file *nfp; 
2970         int indx;
2971
2972         /*
2973          * Must be super user
2974          */
2975         error = suser(td);
2976         if (error)
2977                 return (error);
2978
2979         fmode = FFLAGS(SCARG(uap, flags));
2980         /* why not allow a non-read/write open for our lockd? */
2981         if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
2982                 return (EINVAL);
2983         error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
2984         if (error)
2985                 return(error);
2986         /* find the mount point */
2987         mp = vfs_getvfs(&fhp.fh_fsid);
2988         if (mp == NULL)
2989                 return (ESTALE);
2990         /* now give me my vnode, it gets returned to me locked */
2991         error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
2992         if (error)
2993                 return (error);
2994         /*
2995          * from now on we have to make sure not
2996          * to forget about the vnode
2997          * any error that causes an abort must vput(vp) 
2998          * just set error = err and 'goto bad;'.
2999          */
3000
3001         /* 
3002          * from vn_open 
3003          */
3004         if (vp->v_type == VLNK) {
3005                 error = EMLINK;
3006                 goto bad;
3007         }
3008         if (vp->v_type == VSOCK) {
3009                 error = EOPNOTSUPP;
3010                 goto bad;
3011         }
3012         mode = 0;
3013         if (fmode & (FWRITE | O_TRUNC)) {
3014                 if (vp->v_type == VDIR) {
3015                         error = EISDIR;
3016                         goto bad;
3017                 }
3018                 error = vn_writechk(vp);
3019                 if (error)
3020                         goto bad;
3021                 mode |= VWRITE;
3022         }
3023         if (fmode & FREAD)
3024                 mode |= VREAD;
3025         if (mode) {
3026                 error = VOP_ACCESS(vp, mode, p->p_ucred, td);
3027                 if (error)
3028                         goto bad;
3029         }
3030         if (fmode & O_TRUNC) {
3031                 VOP_UNLOCK(vp, NULL, 0, td);                    /* XXX */
3032                 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
3033                 vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
3034                 VATTR_NULL(vap);
3035                 vap->va_size = 0;
3036                 error = VOP_SETATTR(vp, vap, p->p_ucred, td);
3037                 if (error)
3038                         goto bad;
3039         }
3040         error = VOP_OPEN(vp, fmode, p->p_ucred, td);
3041         if (error)
3042                 goto bad;
3043         /*
3044          * Make sure that a VM object is created for VMIO support.
3045          */
3046         if (vn_canvmio(vp) == TRUE) {
3047                 if ((error = vfs_object_create(vp, td)) != 0)
3048                         goto bad;
3049         }
3050         if (fmode & FWRITE)
3051                 vp->v_writecount++;
3052
3053         /*
3054          * end of vn_open code 
3055          */
3056
3057         if ((error = falloc(p, &nfp, &indx)) != 0) {
3058                 if (fmode & FWRITE)
3059                         vp->v_writecount--;
3060                 goto bad;
3061         }
3062         fp = nfp;       
3063
3064         /*
3065          * hold an extra reference to avoid having fp ripped out
3066          * from under us while we block in the lock op.
3067          */
3068         fhold(fp);
3069         nfp->f_data = (caddr_t)vp;
3070         nfp->f_flag = fmode & FMASK;
3071         nfp->f_ops = &vnops;
3072         nfp->f_type = DTYPE_VNODE;
3073         if (fmode & (O_EXLOCK | O_SHLOCK)) {
3074                 lf.l_whence = SEEK_SET;
3075                 lf.l_start = 0;
3076                 lf.l_len = 0;
3077                 if (fmode & O_EXLOCK)
3078                         lf.l_type = F_WRLCK;
3079                 else
3080                         lf.l_type = F_RDLCK;
3081                 type = F_FLOCK;
3082                 if ((fmode & FNONBLOCK) == 0)
3083                         type |= F_WAIT;
3084                 VOP_UNLOCK(vp, NULL, 0, td);
3085                 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
3086                         /*
3087                          * lock request failed.  Normally close the descriptor
3088                          * but handle the case where someone might have dup()d
3089                          * or close()d it when we weren't looking.
3090                          */
3091                         if (fdp->fd_ofiles[indx] == fp) {
3092                                 fdp->fd_ofiles[indx] = NULL;
3093                                 fdrop(fp, td);
3094                         }
3095
3096                         /*
3097                          * release our private reference.
3098                          */
3099                         fdrop(fp, td);
3100                         return (error);
3101                 }
3102                 vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
3103                 fp->f_flag |= FHASLOCK;
3104         }
3105         if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3106                 vfs_object_create(vp, td);
3107
3108         VOP_UNLOCK(vp, NULL, 0, td);
3109         fdrop(fp, td);
3110         uap->sysmsg_result = indx;
3111         return (0);
3112
3113 bad:
3114         vput(vp);
3115         return (error);
3116 }
3117
3118 /*
3119  * fhstat_args(struct fhandle *u_fhp, struct stat *sb)
3120  */
3121 int
3122 fhstat(struct fhstat_args *uap)
3123 {
3124         struct thread *td = curthread;
3125         struct stat sb;
3126         fhandle_t fh;
3127         struct mount *mp;
3128         struct vnode *vp;
3129         int error;
3130
3131         /*
3132          * Must be super user
3133          */
3134         error = suser(td);
3135         if (error)
3136                 return (error);
3137         
3138         error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3139         if (error)
3140                 return (error);
3141
3142         if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3143                 return (ESTALE);
3144         if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3145                 return (error);
3146         error = vn_stat(vp, &sb, td);
3147         vput(vp);
3148         if (error)
3149                 return (error);
3150         error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3151         return (error);
3152 }
3153
3154 /*
3155  * fhstatfs_args(struct fhandle *u_fhp, struct statfs *buf)
3156  */
3157 int
3158 fhstatfs(struct fhstatfs_args *uap)
3159 {
3160         struct thread *td = curthread;
3161         struct statfs *sp;
3162         struct mount *mp;
3163         struct vnode *vp;
3164         struct statfs sb;
3165         fhandle_t fh;
3166         int error;
3167
3168         /*
3169          * Must be super user
3170          */
3171         if ((error = suser(td)))
3172                 return (error);
3173
3174         if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3175                 return (error);
3176
3177         if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3178                 return (ESTALE);
3179         if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3180                 return (error);
3181         mp = vp->v_mount;
3182         sp = &mp->mnt_stat;
3183         vput(vp);
3184         if ((error = VFS_STATFS(mp, sp, td)) != 0)
3185                 return (error);
3186         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3187         if (suser(td)) {
3188                 bcopy(sp, &sb, sizeof(sb));
3189                 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3190                 sp = &sb;
3191         }
3192         return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3193 }
3194
3195 /*
3196  * Syscall to push extended attribute configuration information into the
3197  * VFS.  Accepts a path, which it converts to a mountpoint, as well as
3198  * a command (int cmd), and attribute name and misc data.  For now, the
3199  * attribute name is left in userspace for consumption by the VFS_op.
3200  * It will probably be changed to be copied into sysspace by the
3201  * syscall in the future, once issues with various consumers of the
3202  * attribute code have raised their hands.
3203  *
3204  * Currently this is used only by UFS Extended Attributes.
3205  */
3206 int
3207 extattrctl(struct extattrctl_args *uap)
3208 {
3209         struct thread *td = curthread;
3210         struct nameidata nd;
3211         struct mount *mp;
3212         int error;
3213
3214         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3215         if ((error = namei(&nd)) != 0)
3216                 return (error);
3217         mp = nd.ni_vp->v_mount;
3218         NDFREE(&nd, 0);
3219         return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
3220             SCARG(uap, arg), td));
3221 }
3222
3223 /*
3224  * Syscall to set a named extended attribute on a file or directory.
3225  * Accepts attribute name, and a uio structure pointing to the data to set.
3226  * The uio is consumed in the style of writev().  The real work happens
3227  * in VOP_SETEXTATTR().
3228  */
3229 int
3230 extattr_set_file(struct extattr_set_file_args *uap)
3231 {
3232         struct thread *td = curthread;
3233         struct proc *p = td->td_proc;
3234         struct nameidata nd;
3235         struct uio auio;
3236         struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
3237         char attrname[EXTATTR_MAXNAMELEN];
3238         u_int iovlen, cnt;
3239         int error, i;
3240
3241         error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
3242         if (error)
3243                 return (error);
3244         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE,
3245             SCARG(uap, path), td);
3246         if ((error = namei(&nd)) != 0)
3247                 return(error);
3248         iovlen = uap->iovcnt * sizeof(struct iovec);
3249         if (uap->iovcnt > UIO_SMALLIOV) {
3250                 if (uap->iovcnt > UIO_MAXIOV) {
3251                         error = EINVAL;
3252                         goto done;
3253                 }
3254                 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
3255                 needfree = iov;
3256         } else
3257                 iov = aiov;
3258         auio.uio_iov = iov;
3259         auio.uio_iovcnt = uap->iovcnt;
3260         auio.uio_rw = UIO_WRITE;
3261         auio.uio_segflg = UIO_USERSPACE;
3262         auio.uio_td = td;
3263         auio.uio_offset = 0;
3264         if ((error = copyin(uap->iovp, iov, iovlen)))
3265                 goto done;
3266         auio.uio_resid = 0;
3267         for (i = 0; i < uap->iovcnt; i++) {
3268                 if (iov->iov_len > INT_MAX - auio.uio_resid) {
3269                         error = EINVAL;
3270                         goto done;
3271                 }
3272                 auio.uio_resid += iov->iov_len;
3273                 iov++;
3274         }
3275         cnt = auio.uio_resid;
3276         error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_ucred, td);
3277         cnt -= auio.uio_resid;
3278         uap->sysmsg_result = cnt;
3279 done:
3280         if (needfree)
3281                 FREE(needfree, M_IOV);
3282         NDFREE(&nd, 0);
3283         return (error);
3284 }
3285
3286 /*
3287  * Syscall to get a named extended attribute on a file or directory.
3288  * Accepts attribute name, and a uio structure pointing to a buffer for the
3289  * data.  The uio is consumed in the style of readv().  The real work
3290  * happens in VOP_GETEXTATTR();
3291  */
3292 int
3293 extattr_get_file(struct extattr_get_file_args *uap)
3294 {
3295         struct thread *td = curthread;
3296         struct proc *p = td->td_proc;
3297         struct nameidata nd;
3298         struct uio auio;
3299         struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
3300         char attrname[EXTATTR_MAXNAMELEN];
3301         u_int iovlen, cnt;
3302         int error, i;
3303
3304         error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
3305         if (error)
3306                 return (error);
3307         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE,
3308             SCARG(uap, path), td);
3309         if ((error = namei(&nd)) != 0)
3310                 return (error);
3311         iovlen = uap->iovcnt * sizeof (struct iovec);
3312         if (uap->iovcnt > UIO_SMALLIOV) {
3313                 if (uap->iovcnt > UIO_MAXIOV) {
3314                         NDFREE(&nd, 0);
3315                         return (EINVAL);
3316                 }
3317                 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
3318                 needfree = iov;
3319         } else {
3320                 iov = aiov;
3321                 needfree = NULL;
3322         }
3323         auio.uio_iov = iov;
3324         auio.uio_iovcnt = uap->iovcnt;
3325         auio.uio_rw = UIO_READ;
3326         auio.uio_segflg = UIO_USERSPACE;
3327         auio.uio_td = td;
3328         auio.uio_offset = 0;
3329         if ((error = copyin(uap->iovp, iov, iovlen)))
3330                 goto done;
3331         auio.uio_resid = 0;
3332         for (i = 0; i < uap->iovcnt; i++) {
3333                 if (iov->iov_len > INT_MAX - auio.uio_resid) {
3334                         error = EINVAL;
3335                         goto done;
3336                 }
3337                 auio.uio_resid += iov->iov_len;
3338                 iov++;
3339         }
3340         cnt = auio.uio_resid;
3341         error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_ucred, td);
3342         cnt -= auio.uio_resid;
3343         uap->sysmsg_result = cnt;
3344 done:
3345         if (needfree)
3346                 FREE(needfree, M_IOV);
3347         NDFREE(&nd, 0);
3348         return(error);
3349 }
3350
3351 /*
3352  * Syscall to delete a named extended attribute from a file or directory.
3353  * Accepts attribute name.  The real work happens in VOP_SETEXTATTR().
3354  */
3355 int
3356 extattr_delete_file(struct extattr_delete_file_args *uap)
3357 {
3358         struct thread *td = curthread;
3359         struct proc *p = td->td_proc;
3360         struct nameidata nd;
3361         char attrname[EXTATTR_MAXNAMELEN];
3362         int     error;
3363
3364         error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
3365         if (error)
3366                 return(error);
3367         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_LOCKLEAF, UIO_USERSPACE,
3368             SCARG(uap, path), td);
3369         if ((error = namei(&nd)) != 0)
3370                 return(error);
3371         error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_ucred, td);
3372         NDFREE(&nd, 0);
3373         return(error);
3374 }
3375
3376 /*
3377  * print out statistics from the current status of the buffer pool
3378  * this can be toggeled by the system control option debug.syncprt
3379  */
3380 #ifdef DEBUG
3381 void
3382 vfs_bufstats(void)
3383 {
3384         int s, i, j, count;
3385         struct buf *bp;
3386         struct bqueues *dp;
3387         int counts[(MAXBSIZE / PAGE_SIZE) + 1];
3388         static char *bname[3] = { "LOCKED", "LRU", "AGE" };
3389
3390         for (dp = bufqueues, i = 0; dp < &bufqueues[3]; dp++, i++) {
3391                 count = 0;
3392                 for (j = 0; j <= MAXBSIZE/PAGE_SIZE; j++)
3393                         counts[j] = 0;
3394                 s = splbio();
3395                 TAILQ_FOREACH(bp, dp, b_freelist) {
3396                         counts[bp->b_bufsize/PAGE_SIZE]++;
3397                         count++;
3398                 }
3399                 splx(s);
3400                 printf("%s: total-%d", bname[i], count);
3401                 for (j = 0; j <= MAXBSIZE/PAGE_SIZE; j++)
3402                         if (counts[j] != 0)
3403                                 printf(", %d-%d", j * PAGE_SIZE, counts[j]);
3404                 printf("\n");
3405         }
3406 }
3407 #endif