diff --git a/lib/libprocstat/common_kvm.c b/lib/libprocstat/common_kvm.c
index 2889f802775d..0ce2a2900f66 100644
--- a/lib/libprocstat/common_kvm.c
+++ b/lib/libprocstat/common_kvm.c
@@ -1,216 +1,215 @@
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
  * Copyright (c) 1988, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by the University of
  *	California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/user.h>
 #include <sys/stat.h>
 #include <sys/vnode.h>
 #include <sys/conf.h>
-#define	_KERNEL
 #include <sys/pipe.h>
+#define	_WANT_MOUNT
 #include <sys/mount.h>
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/extattr.h>
 #include <ufs/ufs/ufsmount.h>
 #include <fs/devfs/devfs.h>
 #include <fs/devfs/devfs_int.h>
-#undef _KERNEL
 #include <nfs/nfsproto.h>
 #include <nfsclient/nfs.h>
 #include <nfsclient/nfsnode.h>
 
 #include <assert.h>
 #include <err.h>
 #include <kvm.h>
 #include <stddef.h>
 #include <string.h>
 
 #include <libprocstat.h>
 #include "common_kvm.h"
 
 int
 kvm_read_all(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes)
 {
 	ssize_t error;
 
 	if (nbytes >= SSIZE_MAX)
 		return (0);
 	error = kvm_read(kd, addr, buf, nbytes);
 	return (error == (ssize_t)(nbytes));
 }
 
 int
 kdevtoname(kvm_t *kd, struct cdev *dev, char *buf)
 {
 	struct cdev si;
 
 	assert(buf);
 	if (!kvm_read_all(kd, (unsigned long)dev, &si, sizeof(si)))
 		return (1);
 	strlcpy(buf, si.si_name, SPECNAMELEN + 1);
 	return (0);
 }
 
 int
 ufs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
 {
 	struct inode inode;
 	struct ufsmount um;
 
 	if (!kvm_read_all(kd, (unsigned long)VTOI(vp), &inode, sizeof(inode))) {
 		warnx("can't read inode at %p", (void *)VTOI(vp));
 		return (1);
 	}
 	if (!kvm_read_all(kd, (unsigned long)inode.i_ump, &um, sizeof(um))) {
 		warnx("can't read ufsmount at %p", (void *)inode.i_ump);
 		return (1);
 	}
 	/*
 	 * The st_dev from stat(2) is a dev_t. These kernel structures
 	 * contain cdev pointers. We need to convert to dev_t to make
 	 * comparisons
 	 */
 	vn->vn_fsid = dev2udev(kd, um.um_dev);
 	vn->vn_fileid = inode.i_number;
 	vn->vn_mode = (mode_t)inode.i_mode;
 	vn->vn_size = inode.i_size;
 	return (0);
 }
 
 int
 devfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
 {
 	struct devfs_dirent devfs_dirent;
 	struct mount mount;
 
 	if (!kvm_read_all(kd, (unsigned long)getvnodedata(vp), &devfs_dirent,
 	    sizeof(devfs_dirent))) {
 		warnx("can't read devfs_dirent at %p",
 		    (void *)vp->v_data);
 		return (1);
 	}
 	if (!kvm_read_all(kd, (unsigned long)getvnodemount(vp), &mount,
 	    sizeof(mount))) {
 		warnx("can't read mount at %p",
 		    (void *)getvnodemount(vp));
 		return (1);
 	}
 	vn->vn_fsid = mount.mnt_stat.f_fsid.val[0];
 	vn->vn_fileid = devfs_dirent.de_inode;
 	vn->vn_mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR;
 	vn->vn_size = 0;
 	return (0);
 }
 
 int
 nfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
 {
 	struct nfsnode nfsnode;
 	mode_t mode;
 
 	if (!kvm_read_all(kd, (unsigned long)VTONFS(vp), &nfsnode,
 	    sizeof(nfsnode))) {
 		warnx("can't read nfsnode at %p",
 		    (void *)VTONFS(vp));
 		return (1);
 	}
 	vn->vn_fsid = nfsnode.n_vattr.va_fsid;
 	vn->vn_fileid = nfsnode.n_vattr.va_fileid;
 	vn->vn_size = nfsnode.n_size;
 	mode = (mode_t)nfsnode.n_vattr.va_mode;
 	switch (vp->v_type) {
 	case VREG:
 		mode |= S_IFREG;
 		break;
 	case VDIR:
 		mode |= S_IFDIR;
 		break;
 	case VBLK:
 		mode |= S_IFBLK;
 		break;
 	case VCHR:
 		mode |= S_IFCHR;
 		break;
 	case VLNK:
 		mode |= S_IFLNK;
 		break;
 	case VSOCK:
 		mode |= S_IFSOCK;
 		break;
 	case VFIFO:
 		mode |= S_IFIFO;
 		break;
 	default:
 		break;
 	};
 	vn->vn_mode = mode;
 	return (0);
 }
 
 /*
  * Read the cdev structure in the kernel in order to work out the
  * associated dev_t
  */
 dev_t
 dev2udev(kvm_t *kd, struct cdev *dev)
 {
 	struct cdev_priv priv;
 
 	assert(kd);
 	if (kvm_read_all(kd, (unsigned long)cdev2priv(dev), &priv,
 	    sizeof(priv))) {
 		return ((dev_t)priv.cdp_inode);
 	} else {
 		warnx("can't convert cdev *%p to a dev_t\n", dev);
 		return (-1);
 	}
 }
 
 void *
 getvnodedata(struct vnode *vp)
 {
 	return (vp->v_data);
 }
 
 struct mount *
 getvnodemount(struct vnode *vp)
 {
 	return (vp->v_mount);
 }
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
index a2de61855815..7ccf6c343705 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -1,2650 +1,2647 @@
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (c) 2017 Dell EMC
  * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
  * Copyright (c) 1988, 1993
  *      The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *      This product includes software developed by the University of
  *      California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/elf.h>
 #include <sys/time.h>
 #include <sys/resourcevar.h>
 #define	_WANT_UCRED
 #include <sys/ucred.h>
 #undef _WANT_UCRED
 #include <sys/proc.h>
 #include <sys/user.h>
 #include <sys/stat.h>
 #include <sys/vnode.h>
 #include <sys/socket.h>
 #define	_WANT_SOCKET
 #include <sys/socketvar.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
 #include <sys/un.h>
 #define	_WANT_UNPCB
 #include <sys/unpcb.h>
 #include <sys/sysctl.h>
 #include <sys/tty.h>
 #include <sys/filedesc.h>
 #include <sys/queue.h>
 #define	_WANT_FILE
 #include <sys/file.h>
 #include <sys/conf.h>
 #include <sys/ksem.h>
 #include <sys/mman.h>
 #include <sys/capsicum.h>
 #include <sys/ptrace.h>
-#define	_KERNEL
+#define	_WANT_MOUNT
 #include <sys/mount.h>
 #include <sys/filedesc.h>
 #include <sys/pipe.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
 #include <fs/devfs/devfs.h>
 #include <fs/devfs/devfs_int.h>
-#undef _KERNEL
 #include <nfs/nfsproto.h>
 #include <nfsclient/nfs.h>
 #include <nfsclient/nfsnode.h>
 
 #include <vm/vm.h>
 #include <vm/vm_map.h>
 #include <vm/vm_object.h>
 
 #include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #define	_WANT_INPCB
 #include <netinet/in_pcb.h>
 
 #include <assert.h>
 #include <ctype.h>
 #include <err.h>
 #include <fcntl.h>
 #include <kvm.h>
 #include <libutil.h>
 #include <limits.h>
 #include <paths.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <unistd.h>
 #include <netdb.h>
 
 #include <libprocstat.h>
 #include "libprocstat_internal.h"
 #include "common_kvm.h"
 #include "core.h"
 
 int     statfs(const char *, struct statfs *);	/* XXX */
 
 #define	PROCSTAT_KVM	1
 #define	PROCSTAT_SYSCTL	2
 #define	PROCSTAT_CORE	3
 
 static char	**getargv(struct procstat *procstat, struct kinfo_proc *kp,
     size_t nchr, int env);
 static char	*getmnton(kvm_t *kd, struct mount *m);
 static struct kinfo_vmentry *	kinfo_getvmmap_core(struct procstat_core *core,
     int *cntp);
 static Elf_Auxinfo	*procstat_getauxv_core(struct procstat_core *core,
     unsigned int *cntp);
 static Elf_Auxinfo	*procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp);
 static struct filestat_list	*procstat_getfiles_kvm(
     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
 static struct filestat_list	*procstat_getfiles_sysctl(
     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
 static int	procstat_get_pipe_info_sysctl(struct filestat *fst,
     struct pipestat *pipe, char *errbuf);
 static int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
     struct pipestat *pipe, char *errbuf);
 static int	procstat_get_pts_info_sysctl(struct filestat *fst,
     struct ptsstat *pts, char *errbuf);
 static int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
     struct ptsstat *pts, char *errbuf);
 static int	procstat_get_sem_info_sysctl(struct filestat *fst,
     struct semstat *sem, char *errbuf);
 static int	procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst,
     struct semstat *sem, char *errbuf);
 static int	procstat_get_shm_info_sysctl(struct filestat *fst,
     struct shmstat *shm, char *errbuf);
 static int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
     struct shmstat *shm, char *errbuf);
 static int	procstat_get_socket_info_sysctl(struct filestat *fst,
     struct sockstat *sock, char *errbuf);
 static int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
     struct sockstat *sock, char *errbuf);
 static int	to_filestat_flags(int flags);
 static int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
     struct vnstat *vn, char *errbuf);
 static int	procstat_get_vnode_info_sysctl(struct filestat *fst,
     struct vnstat *vn, char *errbuf);
 static gid_t	*procstat_getgroups_core(struct procstat_core *core,
     unsigned int *count);
 static gid_t *	procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp,
     unsigned int *count);
 static gid_t	*procstat_getgroups_sysctl(pid_t pid, unsigned int *count);
 static struct kinfo_kstack	*procstat_getkstack_sysctl(pid_t pid,
     int *cntp);
 static int	procstat_getosrel_core(struct procstat_core *core,
     int *osrelp);
 static int	procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp,
     int *osrelp);
 static int	procstat_getosrel_sysctl(pid_t pid, int *osrelp);
 static int	procstat_getpathname_core(struct procstat_core *core,
     char *pathname, size_t maxlen);
 static int	procstat_getpathname_sysctl(pid_t pid, char *pathname,
     size_t maxlen);
 static int	procstat_getrlimit_core(struct procstat_core *core, int which,
     struct rlimit* rlimit);
 static int	procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp,
     int which, struct rlimit* rlimit);
 static int	procstat_getrlimit_sysctl(pid_t pid, int which,
     struct rlimit* rlimit);
 static int	procstat_getumask_core(struct procstat_core *core,
     unsigned short *maskp);
 static int	procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp,
     unsigned short *maskp);
 static int	procstat_getumask_sysctl(pid_t pid, unsigned short *maskp);
 static int	vntype2psfsttype(int type);
 
 void
 procstat_close(struct procstat *procstat)
 {
 
 	assert(procstat);
 	if (procstat->type == PROCSTAT_KVM)
 		kvm_close(procstat->kd);
 	else if (procstat->type == PROCSTAT_CORE)
 		procstat_core_close(procstat->core);
 	procstat_freeargv(procstat);
 	procstat_freeenvv(procstat);
 	free(procstat);
 }
 
 struct procstat *
 procstat_open_sysctl(void)
 {
 	struct procstat *procstat;
 
 	procstat = calloc(1, sizeof(*procstat));
 	if (procstat == NULL) {
 		warn("malloc()");
 		return (NULL);
 	}
 	procstat->type = PROCSTAT_SYSCTL;
 	return (procstat);
 }
 
 struct procstat *
 procstat_open_kvm(const char *nlistf, const char *memf)
 {
 	struct procstat *procstat;
 	kvm_t *kd;
 	char buf[_POSIX2_LINE_MAX];
 
 	procstat = calloc(1, sizeof(*procstat));
 	if (procstat == NULL) {
 		warn("malloc()");
 		return (NULL);
 	}
 	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
 	if (kd == NULL) {
 		warnx("kvm_openfiles(): %s", buf);
 		free(procstat);
 		return (NULL);
 	}
 	procstat->type = PROCSTAT_KVM;
 	procstat->kd = kd;
 	return (procstat);
 }
 
 struct procstat *
 procstat_open_core(const char *filename)
 {
 	struct procstat *procstat;
 	struct procstat_core *core;
 
 	procstat = calloc(1, sizeof(*procstat));
 	if (procstat == NULL) {
 		warn("malloc()");
 		return (NULL);
 	}
 	core = procstat_core_open(filename);
 	if (core == NULL) {
 		free(procstat);
 		return (NULL);
 	}
 	procstat->type = PROCSTAT_CORE;
 	procstat->core = core;
 	return (procstat);
 }
 
 struct kinfo_proc *
 procstat_getprocs(struct procstat *procstat, int what, int arg,
     unsigned int *count)
 {
 	struct kinfo_proc *p0, *p;
 	size_t len, olen;
 	int name[4];
 	int cnt;
 	int error;
 
 	assert(procstat);
 	assert(count);
 	p = NULL;
 	if (procstat->type == PROCSTAT_KVM) {
 		*count = 0;
 		p0 = kvm_getprocs(procstat->kd, what, arg, &cnt);
 		if (p0 == NULL || cnt <= 0)
 			return (NULL);
 		*count = cnt;
 		len = *count * sizeof(*p);
 		p = malloc(len);
 		if (p == NULL) {
 			warnx("malloc(%zu)", len);
 			goto fail;
 		}
 		bcopy(p0, p, len);
 		return (p);
 	} else if (procstat->type == PROCSTAT_SYSCTL) {
 		len = 0;
 		name[0] = CTL_KERN;
 		name[1] = KERN_PROC;
 		name[2] = what;
 		name[3] = arg;
 		error = sysctl(name, nitems(name), NULL, &len, NULL, 0);
 		if (error < 0 && errno != EPERM) {
 			warn("sysctl(kern.proc)");
 			goto fail;
 		}
 		if (len == 0) {
 			warnx("no processes?");
 			goto fail;
 		}
 		do {
 			len += len / 10;
 			p = reallocf(p, len);
 			if (p == NULL) {
 				warnx("reallocf(%zu)", len);
 				goto fail;
 			}
 			olen = len;
 			error = sysctl(name, nitems(name), p, &len, NULL, 0);
 		} while (error < 0 && errno == ENOMEM && olen == len);
 		if (error < 0 && errno != EPERM) {
 			warn("sysctl(kern.proc)");
 			goto fail;
 		}
 		/* Perform simple consistency checks. */
 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
 			warnx("kinfo_proc structure size mismatch (len = %zu)", len);
 			goto fail;
 		}
 		*count = len / sizeof(*p);
 		return (p);
 	} else if (procstat->type == PROCSTAT_CORE) {
 		p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
 		    &len);
 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
 			warnx("kinfo_proc structure size mismatch");
 			goto fail;
 		}
 		*count = len / sizeof(*p);
 		return (p);
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 fail:
 	if (p)
 		free(p);
 	return (NULL);
 }
 
 void
 procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
 {
 
 	if (p != NULL)
 		free(p);
 	p = NULL;
 }
 
 struct filestat_list *
 procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
 {
 
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		return (procstat_getfiles_kvm(procstat, kp, mmapped));
 	case PROCSTAT_SYSCTL:
 	case PROCSTAT_CORE:
 		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 }
 
 void
 procstat_freefiles(struct procstat *procstat, struct filestat_list *head)
 {
 	struct filestat *fst, *tmp;
 
 	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
 		if (fst->fs_path != NULL)
 			free(fst->fs_path);
 		free(fst);
 	}
 	free(head);
 	if (procstat->vmentries != NULL) {
 		free(procstat->vmentries);
 		procstat->vmentries = NULL;
 	}
 	if (procstat->files != NULL) {
 		free(procstat->files);
 		procstat->files = NULL;
 	}
 }
 
 static struct filestat *
 filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags,
     int refcount, off_t offset, char *path, cap_rights_t *cap_rightsp)
 {
 	struct filestat *entry;
 
 	entry = calloc(1, sizeof(*entry));
 	if (entry == NULL) {
 		warn("malloc()");
 		return (NULL);
 	}
 	entry->fs_typedep = typedep;
 	entry->fs_fflags = fflags;
 	entry->fs_uflags = uflags;
 	entry->fs_fd = fd;
 	entry->fs_type = type;
 	entry->fs_ref_count = refcount;
 	entry->fs_offset = offset;
 	entry->fs_path = path;
 	if (cap_rightsp != NULL)
 		entry->fs_cap_rights = *cap_rightsp;
 	else
 		cap_rights_init(&entry->fs_cap_rights);
 	return (entry);
 }
 
 static struct vnode *
 getctty(kvm_t *kd, struct kinfo_proc *kp)
 {
 	struct pgrp pgrp;
 	struct proc proc;
 	struct session sess;
 	int error;
                         
 	assert(kp);
 	error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
 	    sizeof(proc));
 	if (error == 0) {
 		warnx("can't read proc struct at %p for pid %d",
 		    kp->ki_paddr, kp->ki_pid);
 		return (NULL);
 	}
 	if (proc.p_pgrp == NULL)
 		return (NULL);
 	error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp,
 	    sizeof(pgrp));
 	if (error == 0) {
 		warnx("can't read pgrp struct at %p for pid %d",
 		    proc.p_pgrp, kp->ki_pid);
 		return (NULL);
 	}
 	error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
 	    sizeof(sess));
 	if (error == 0) {
 		warnx("can't read session struct at %p for pid %d",
 		    pgrp.pg_session, kp->ki_pid);
 		return (NULL);
 	}
 	return (sess.s_ttyvp);
 }
 
 static int
 procstat_vm_map_reader(void *token, vm_map_entry_t addr, vm_map_entry_t dest)
 {
 	kvm_t *kd;
 
 	kd = (kvm_t *)token;
 	return (kvm_read_all(kd, (unsigned long)addr, dest, sizeof(*dest)));
 }
 
 static struct filestat_list *
 procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
 {
 	struct file file;
 	struct filedesc filed;
 	struct pwddesc pathsd;
 	struct fdescenttbl *fdt;
 	struct pwd pwd;
 	unsigned long pwd_addr;
 	struct vm_map_entry vmentry;
 	struct vm_object object;
 	struct vmspace vmspace;
 	vm_map_entry_t entryp;
 	vm_object_t objp;
 	struct vnode *vp;
 	struct filestat *entry;
 	struct filestat_list *head;
 	kvm_t *kd;
 	void *data;
 	int fflags;
 	unsigned int i;
 	int prot, type;
 	size_t fdt_size;
 	unsigned int nfiles;
 	bool haspwd;
 
 	assert(procstat);
 	kd = procstat->kd;
 	if (kd == NULL)
 		return (NULL);
 	if (kp->ki_fd == NULL || kp->ki_pd == NULL)
 		return (NULL);
 	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed,
 	    sizeof(filed))) {
 		warnx("can't read filedesc at %p", (void *)kp->ki_fd);
 		return (NULL);
 	}
 	if (!kvm_read_all(kd, (unsigned long)kp->ki_pd, &pathsd,
 	    sizeof(pathsd))) {
 		warnx("can't read pwddesc at %p", (void *)kp->ki_pd);
 		return (NULL);
 	}
 	haspwd = false;
 	pwd_addr = (unsigned long)(PWDDESC_KVM_LOAD_PWD(&pathsd));
 	if (pwd_addr != 0) {
 		if (!kvm_read_all(kd, pwd_addr, &pwd, sizeof(pwd))) {
 			warnx("can't read fd_pwd at %p", (void *)pwd_addr);
 			return (NULL);
 		}
 		haspwd = true;
 	}
 
 	/*
 	 * Allocate list head.
 	 */
 	head = malloc(sizeof(*head));
 	if (head == NULL)
 		return (NULL);
 	STAILQ_INIT(head);
 
 	/* root directory vnode, if one. */
 	if (haspwd) {
 		if (pwd.pwd_rdir) {
 			entry = filestat_new_entry(pwd.pwd_rdir, PS_FST_TYPE_VNODE, -1,
 			    PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, NULL);
 			if (entry != NULL)
 				STAILQ_INSERT_TAIL(head, entry, next);
 		}
 		/* current working directory vnode. */
 		if (pwd.pwd_cdir) {
 			entry = filestat_new_entry(pwd.pwd_cdir, PS_FST_TYPE_VNODE, -1,
 			    PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, NULL);
 			if (entry != NULL)
 				STAILQ_INSERT_TAIL(head, entry, next);
 		}
 		/* jail root, if any. */
 		if (pwd.pwd_jdir) {
 			entry = filestat_new_entry(pwd.pwd_jdir, PS_FST_TYPE_VNODE, -1,
 			    PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, NULL);
 			if (entry != NULL)
 				STAILQ_INSERT_TAIL(head, entry, next);
 		}
 	}
 	/* ktrace vnode, if one */
 	if (kp->ki_tracep) {
 		entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1,
 		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
 		    PS_FST_UFLAG_TRACE, 0, 0, NULL, NULL);
 		if (entry != NULL)
 			STAILQ_INSERT_TAIL(head, entry, next);
 	}
 	/* text vnode, if one */
 	if (kp->ki_textvp) {
 		entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1,
 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, NULL);
 		if (entry != NULL)
 			STAILQ_INSERT_TAIL(head, entry, next);
 	}
 	/* Controlling terminal. */
 	if ((vp = getctty(kd, kp)) != NULL) {
 		entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1,
 		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
 		    PS_FST_UFLAG_CTTY, 0, 0, NULL, NULL);
 		if (entry != NULL)
 			STAILQ_INSERT_TAIL(head, entry, next);
 	}
 
 	if (!kvm_read_all(kd, (unsigned long)filed.fd_files, &nfiles,
 	    sizeof(nfiles))) {
 		warnx("can't read fd_files at %p", (void *)filed.fd_files);
 		return (NULL);
 	}
 
 	fdt_size = sizeof(*fdt) + nfiles * sizeof(struct filedescent);
 	fdt = malloc(fdt_size);
 	if (fdt == NULL) {
 		warn("malloc(%zu)", fdt_size);
 		goto do_mmapped;
 	}
 	if (!kvm_read_all(kd, (unsigned long)filed.fd_files, fdt, fdt_size)) {
 		warnx("cannot read file structures at %p", (void *)filed.fd_files);
 		free(fdt);
 		goto do_mmapped;
 	}
 	for (i = 0; i < nfiles; i++) {
 		if (fdt->fdt_ofiles[i].fde_file == NULL) {
 			continue;
 		}
 		if (!kvm_read_all(kd, (unsigned long)fdt->fdt_ofiles[i].fde_file, &file,
 		    sizeof(struct file))) {
 			warnx("can't read file %d at %p", i,
 			    (void *)fdt->fdt_ofiles[i].fde_file);
 			continue;
 		}
 		switch (file.f_type) {
 		case DTYPE_VNODE:
 			type = PS_FST_TYPE_VNODE;
 			data = file.f_vnode;
 			break;
 		case DTYPE_SOCKET:
 			type = PS_FST_TYPE_SOCKET;
 			data = file.f_data;
 			break;
 		case DTYPE_PIPE:
 			type = PS_FST_TYPE_PIPE;
 			data = file.f_data;
 			break;
 		case DTYPE_FIFO:
 			type = PS_FST_TYPE_FIFO;
 			data = file.f_vnode;
 			break;
 #ifdef DTYPE_PTS
 		case DTYPE_PTS:
 			type = PS_FST_TYPE_PTS;
 			data = file.f_data;
 			break;
 #endif
 		case DTYPE_SEM:
 			type = PS_FST_TYPE_SEM;
 			data = file.f_data;
 			break;
 		case DTYPE_SHM:
 			type = PS_FST_TYPE_SHM;
 			data = file.f_data;
 			break;
 		case DTYPE_PROCDESC:
 			type = PS_FST_TYPE_PROCDESC;
 			data = file.f_data;
 			break;
 		case DTYPE_DEV:
 			type = PS_FST_TYPE_DEV;
 			data = file.f_data;
 			break;
 		case DTYPE_EVENTFD:
 			type = PS_FST_TYPE_EVENTFD;
 			data = file.f_data;
 			break;
 		default:
 			continue;
 		}
 		/* XXXRW: No capability rights support for kvm yet. */
 		entry = filestat_new_entry(data, type, i,
 		    to_filestat_flags(file.f_flag), 0, 0, 0, NULL, NULL);
 		if (entry != NULL)
 			STAILQ_INSERT_TAIL(head, entry, next);
 	}
 	free(fdt);
 
 do_mmapped:
 
 	/*
 	 * Process mmapped files if requested.
 	 */
 	if (mmapped) {
 		if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace,
 		    sizeof(vmspace))) {
 			warnx("can't read vmspace at %p",
 			    (void *)kp->ki_vmspace);
 			goto exit;
 		}
 
 		vmentry = vmspace.vm_map.header;
 		for (entryp = vm_map_entry_read_succ(kd, &vmentry, procstat_vm_map_reader);
 		    entryp != NULL && entryp != &kp->ki_vmspace->vm_map.header;
 		     entryp = vm_map_entry_read_succ(kd, &vmentry, procstat_vm_map_reader)) {
 			if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP)
 				continue;
 			if ((objp = vmentry.object.vm_object) == NULL)
 				continue;
 			for (; objp; objp = object.backing_object) {
 				if (!kvm_read_all(kd, (unsigned long)objp,
 				    &object, sizeof(object))) {
 					warnx("can't read vm_object at %p",
 					    (void *)objp);
 					break;
 				}
 			}
 
 			/* We want only vnode objects. */
 			if (object.type != OBJT_VNODE)
 				continue;
 
 			prot = vmentry.protection;
 			fflags = 0;
 			if (prot & VM_PROT_READ)
 				fflags = PS_FST_FFLAG_READ;
 			if ((vmentry.eflags & MAP_ENTRY_COW) == 0 &&
 			    prot & VM_PROT_WRITE)
 				fflags |= PS_FST_FFLAG_WRITE;
 
 			/*
 			 * Create filestat entry.
 			 */
 			entry = filestat_new_entry(object.handle,
 			    PS_FST_TYPE_VNODE, -1, fflags,
 			    PS_FST_UFLAG_MMAP, 0, 0, NULL, NULL);
 			if (entry != NULL)
 				STAILQ_INSERT_TAIL(head, entry, next);
 		}
 		if (entryp == NULL)
 			warnx("can't read vm_map_entry");
 	}
 exit:
 	return (head);
 }
 
 /*
  * kinfo types to filestat translation.
  */
 static int
 kinfo_type2fst(int kftype)
 {
 	static struct {
 		int	kf_type;
 		int	fst_type;
 	} kftypes2fst[] = {
 		{ KF_TYPE_PROCDESC, PS_FST_TYPE_PROCDESC },
 		{ KF_TYPE_DEV, PS_FST_TYPE_DEV },
 		{ KF_TYPE_FIFO, PS_FST_TYPE_FIFO },
 		{ KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE },
 		{ KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE },
 		{ KF_TYPE_NONE, PS_FST_TYPE_NONE },
 		{ KF_TYPE_PIPE, PS_FST_TYPE_PIPE },
 		{ KF_TYPE_PTS, PS_FST_TYPE_PTS },
 		{ KF_TYPE_SEM, PS_FST_TYPE_SEM },
 		{ KF_TYPE_SHM, PS_FST_TYPE_SHM },
 		{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
 		{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
 		{ KF_TYPE_EVENTFD, PS_FST_TYPE_EVENTFD },
 		{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
 	};
 #define NKFTYPES	(sizeof(kftypes2fst) / sizeof(*kftypes2fst))
 	unsigned int i;
 
 	for (i = 0; i < NKFTYPES; i++)
 		if (kftypes2fst[i].kf_type == kftype)
 			break;
 	if (i == NKFTYPES)
 		return (PS_FST_TYPE_UNKNOWN);
 	return (kftypes2fst[i].fst_type);
 }
 
 /*
  * kinfo flags to filestat translation.
  */
 static int
 kinfo_fflags2fst(int kfflags)
 {
 	static struct {
 		int	kf_flag;
 		int	fst_flag;
 	} kfflags2fst[] = {
 		{ KF_FLAG_APPEND, PS_FST_FFLAG_APPEND },
 		{ KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC },
 		{ KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
 		{ KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
 		{ KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
 		{ KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
 		{ KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
 		{ KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
 		{ KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
 		{ KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
 		{ KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
 		{ KF_FLAG_READ, PS_FST_FFLAG_READ },
 		{ KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
 		{ KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
 		{ KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
 	};
 #define NKFFLAGS	(sizeof(kfflags2fst) / sizeof(*kfflags2fst))
 	unsigned int i;
 	int flags;
 
 	flags = 0;
 	for (i = 0; i < NKFFLAGS; i++)
 		if ((kfflags & kfflags2fst[i].kf_flag) != 0)
 			flags |= kfflags2fst[i].fst_flag;
 	return (flags);
 }
 
 static int
 kinfo_uflags2fst(int fd)
 {
 
 	switch (fd) {
 	case KF_FD_TYPE_CTTY:
 		return (PS_FST_UFLAG_CTTY);
 	case KF_FD_TYPE_CWD:
 		return (PS_FST_UFLAG_CDIR);
 	case KF_FD_TYPE_JAIL:
 		return (PS_FST_UFLAG_JAIL);
 	case KF_FD_TYPE_TEXT:
 		return (PS_FST_UFLAG_TEXT);
 	case KF_FD_TYPE_TRACE:
 		return (PS_FST_UFLAG_TRACE);
 	case KF_FD_TYPE_ROOT:
 		return (PS_FST_UFLAG_RDIR);
 	}
 	return (0);
 }
 
 static struct kinfo_file *
 kinfo_getfile_core(struct procstat_core *core, int *cntp)
 {
 	int cnt;
 	size_t len;
 	char *buf, *bp, *eb;
 	struct kinfo_file *kif, *kp, *kf;
 
 	buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len);
 	if (buf == NULL)
 		return (NULL);
 	/*
 	 * XXXMG: The code below is just copy&past from libutil.
 	 * The code duplication can be avoided if libutil
 	 * is extended to provide something like:
 	 *   struct kinfo_file *kinfo_getfile_from_buf(const char *buf,
 	 *       size_t len, int *cntp);
 	 */
 
 	/* Pass 1: count items */
 	cnt = 0;
 	bp = buf;
 	eb = buf + len;
 	while (bp < eb) {
 		kf = (struct kinfo_file *)(uintptr_t)bp;
 		if (kf->kf_structsize == 0)
 			break;
 		bp += kf->kf_structsize;
 		cnt++;
 	}
 
 	kif = calloc(cnt, sizeof(*kif));
 	if (kif == NULL) {
 		free(buf);
 		return (NULL);
 	}
 	bp = buf;
 	eb = buf + len;
 	kp = kif;
 	/* Pass 2: unpack */
 	while (bp < eb) {
 		kf = (struct kinfo_file *)(uintptr_t)bp;
 		if (kf->kf_structsize == 0)
 			break;
 		/* Copy/expand into pre-zeroed buffer */
 		memcpy(kp, kf, kf->kf_structsize);
 		/* Advance to next packed record */
 		bp += kf->kf_structsize;
 		/* Set field size to fixed length, advance */
 		kp->kf_structsize = sizeof(*kp);
 		kp++;
 	}
 	free(buf);
 	*cntp = cnt;
 	return (kif);	/* Caller must free() return value */
 }
 
 static struct filestat_list *
 procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
     int mmapped)
 {
 	struct kinfo_file *kif, *files;
 	struct kinfo_vmentry *kve, *vmentries;
 	struct filestat_list *head;
 	struct filestat *entry;
 	char *path;
 	off_t offset;
 	int cnt, fd, fflags;
 	int i, type, uflags;
 	int refcount;
 	cap_rights_t cap_rights;
 
 	assert(kp);
 	if (kp->ki_fd == NULL)
 		return (NULL);
 	switch(procstat->type) {
 	case PROCSTAT_SYSCTL:
 		files = kinfo_getfile(kp->ki_pid, &cnt);
 		break;
 	case PROCSTAT_CORE:
 		files = kinfo_getfile_core(procstat->core, &cnt);
 		break;
 	default:
 		assert(!"invalid type");
 	}
 	if (files == NULL && errno != EPERM) {
 		warn("kinfo_getfile()");
 		return (NULL);
 	}
 	procstat->files = files;
 
 	/*
 	 * Allocate list head.
 	 */
 	head = malloc(sizeof(*head));
 	if (head == NULL)
 		return (NULL);
 	STAILQ_INIT(head);
 	for (i = 0; i < cnt; i++) {
 		kif = &files[i];
 
 		type = kinfo_type2fst(kif->kf_type);
 		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
 		fflags = kinfo_fflags2fst(kif->kf_flags);
 		uflags = kinfo_uflags2fst(kif->kf_fd);
 		refcount = kif->kf_ref_count;
 		offset = kif->kf_offset;
 		if (*kif->kf_path != '\0')
 			path = strdup(kif->kf_path);
 		else
 			path = NULL;
 		cap_rights = kif->kf_cap_rights;
 
 		/*
 		 * Create filestat entry.
 		 */
 		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
 		    refcount, offset, path, &cap_rights);
 		if (entry != NULL)
 			STAILQ_INSERT_TAIL(head, entry, next);
 	}
 	if (mmapped != 0) {
 		vmentries = procstat_getvmmap(procstat, kp, &cnt);
 		procstat->vmentries = vmentries;
 		if (vmentries == NULL || cnt == 0)
 			goto fail;
 		for (i = 0; i < cnt; i++) {
 			kve = &vmentries[i];
 			if (kve->kve_type != KVME_TYPE_VNODE)
 				continue;
 			fflags = 0;
 			if (kve->kve_protection & KVME_PROT_READ)
 				fflags = PS_FST_FFLAG_READ;
 			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
 			    kve->kve_protection & KVME_PROT_WRITE)
 				fflags |= PS_FST_FFLAG_WRITE;
 			offset = kve->kve_offset;
 			refcount = kve->kve_ref_count;
 			if (*kve->kve_path != '\0')
 				path = strdup(kve->kve_path);
 			else
 				path = NULL;
 			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
 			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
 			    NULL);
 			if (entry != NULL)
 				STAILQ_INSERT_TAIL(head, entry, next);
 		}
 	}
 fail:
 	return (head);
 }
 
 int
 procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
     struct pipestat *ps, char *errbuf)
 {
 
 	assert(ps);
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
 		    errbuf));
 	} else if (procstat->type == PROCSTAT_SYSCTL ||
 		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 		return (1);
 	}
 }
 
 static int
 procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
     struct pipestat *ps, char *errbuf)
 {
 	struct pipe pi;
 	void *pipep;
 
 	assert(kd);
 	assert(ps);
 	assert(fst);
 	bzero(ps, sizeof(*ps));
 	pipep = fst->fs_typedep;
 	if (pipep == NULL)
 		goto fail;
 	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
 		warnx("can't read pipe at %p", (void *)pipep);
 		goto fail;
 	}
 	ps->addr = (uintptr_t)pipep;
 	ps->peer = (uintptr_t)pi.pipe_peer;
 	ps->buffer_cnt = pi.pipe_buffer.cnt;
 	return (0);
 
 fail:
 	if (errbuf != NULL)
 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 	return (1);
 }
 
 static int
 procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
     char *errbuf __unused)
 {
 	struct kinfo_file *kif;
 
 	assert(ps);
 	assert(fst);
 	bzero(ps, sizeof(*ps));
 	kif = fst->fs_typedep;
 	if (kif == NULL)
 		return (1);
 	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
 	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
 	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
 	return (0);
 }
 
 int
 procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
     struct ptsstat *pts, char *errbuf)
 {
 
 	assert(pts);
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
 		    errbuf));
 	} else if (procstat->type == PROCSTAT_SYSCTL ||
 		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 		return (1);
 	}
 }
 
 static int
 procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
     struct ptsstat *pts, char *errbuf)
 {
 	struct tty tty;
 	void *ttyp;
 
 	assert(kd);
 	assert(pts);
 	assert(fst);
 	bzero(pts, sizeof(*pts));
 	ttyp = fst->fs_typedep;
 	if (ttyp == NULL)
 		goto fail;
 	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
 		warnx("can't read tty at %p", (void *)ttyp);
 		goto fail;
 	}
 	pts->dev = dev2udev(kd, tty.t_dev);
 	(void)kdevtoname(kd, tty.t_dev, pts->devname);
 	return (0);
 
 fail:
 	if (errbuf != NULL)
 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 	return (1);
 }
 
 static int
 procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
     char *errbuf __unused)
 {
 	struct kinfo_file *kif;
 
 	assert(pts);
 	assert(fst);
 	bzero(pts, sizeof(*pts));
 	kif = fst->fs_typedep;
 	if (kif == NULL)
 		return (0);
 	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
 	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
 	return (0);
 }
 
 int
 procstat_get_sem_info(struct procstat *procstat, struct filestat *fst,
     struct semstat *sem, char *errbuf)
 {
 
 	assert(sem);
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_sem_info_kvm(procstat->kd, fst, sem,
 		    errbuf));
 	} else if (procstat->type == PROCSTAT_SYSCTL ||
 	    procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_sem_info_sysctl(fst, sem, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 		return (1);
 	}
 }
 
 static int
 procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst,
     struct semstat *sem, char *errbuf)
 {
 	struct ksem ksem;
 	void *ksemp;
 	char *path;
 	int i;
 
 	assert(kd);
 	assert(sem);
 	assert(fst);
 	bzero(sem, sizeof(*sem));
 	ksemp = fst->fs_typedep;
 	if (ksemp == NULL)
 		goto fail;
 	if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem,
 	    sizeof(struct ksem))) {
 		warnx("can't read ksem at %p", (void *)ksemp);
 		goto fail;
 	}
 	sem->mode = S_IFREG | ksem.ks_mode;
 	sem->value = ksem.ks_value;
 	if (fst->fs_path == NULL && ksem.ks_path != NULL) {
 		path = malloc(MAXPATHLEN);
 		for (i = 0; i < MAXPATHLEN - 1; i++) {
 			if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i,
 			    path + i, 1))
 				break;
 			if (path[i] == '\0')
 				break;
 		}
 		path[i] = '\0';
 		if (i == 0)
 			free(path);
 		else
 			fst->fs_path = path;
 	}
 	return (0);
 
 fail:
 	if (errbuf != NULL)
 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 	return (1);
 }
 
 static int
 procstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem,
     char *errbuf __unused)
 {
 	struct kinfo_file *kif;
 
 	assert(sem);
 	assert(fst);
 	bzero(sem, sizeof(*sem));
 	kif = fst->fs_typedep;
 	if (kif == NULL)
 		return (0);
 	sem->value = kif->kf_un.kf_sem.kf_sem_value;
 	sem->mode = kif->kf_un.kf_sem.kf_sem_mode;
 	return (0);
 }
 
 int
 procstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
     struct shmstat *shm, char *errbuf)
 {
 
 	assert(shm);
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
 		    errbuf));
 	} else if (procstat->type == PROCSTAT_SYSCTL ||
 	    procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 		return (1);
 	}
 }
 
 static int
 procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
     struct shmstat *shm, char *errbuf)
 {
 	struct shmfd shmfd;
 	void *shmfdp;
 	char *path;
 	int i;
 
 	assert(kd);
 	assert(shm);
 	assert(fst);
 	bzero(shm, sizeof(*shm));
 	shmfdp = fst->fs_typedep;
 	if (shmfdp == NULL)
 		goto fail;
 	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
 	    sizeof(struct shmfd))) {
 		warnx("can't read shmfd at %p", (void *)shmfdp);
 		goto fail;
 	}
 	shm->mode = S_IFREG | shmfd.shm_mode;
 	shm->size = shmfd.shm_size;
 	if (fst->fs_path == NULL && shmfd.shm_path != NULL) {
 		path = malloc(MAXPATHLEN);
 		for (i = 0; i < MAXPATHLEN - 1; i++) {
 			if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i,
 			    path + i, 1))
 				break;
 			if (path[i] == '\0')
 				break;
 		}
 		path[i] = '\0';
 		if (i == 0)
 			free(path);
 		else
 			fst->fs_path = path;
 	}
 	return (0);
 
 fail:
 	if (errbuf != NULL)
 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 	return (1);
 }
 
 static int
 procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
     char *errbuf __unused)
 {
 	struct kinfo_file *kif;
 
 	assert(shm);
 	assert(fst);
 	bzero(shm, sizeof(*shm));
 	kif = fst->fs_typedep;
 	if (kif == NULL)
 		return (0);
 	shm->size = kif->kf_un.kf_file.kf_file_size;
 	shm->mode = kif->kf_un.kf_file.kf_file_mode;
 	return (0);
 }
 
 int
 procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
     struct vnstat *vn, char *errbuf)
 {
 
 	assert(vn);
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
 		    errbuf));
 	} else if (procstat->type == PROCSTAT_SYSCTL ||
 		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 		return (1);
 	}
 }
 
 static int
 procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
     struct vnstat *vn, char *errbuf)
 {
 	/* Filesystem specific handlers. */
 	#define FSTYPE(fst)     {#fst, fst##_filestat}
 	struct {
 		const char	*tag;
 		int		(*handler)(kvm_t *kd, struct vnode *vp,
 		    struct vnstat *vn);
 	} fstypes[] = {
 		FSTYPE(devfs),
 		FSTYPE(isofs),
 		FSTYPE(msdosfs),
 		FSTYPE(nfs),
 		FSTYPE(smbfs),
 		FSTYPE(udf), 
 		FSTYPE(ufs),
 #ifdef LIBPROCSTAT_ZFS
 		FSTYPE(zfs),
 #endif
 	};
 #define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
 	struct vnode vnode;
 	char tagstr[12];
 	void *vp;
 	int error;
 	unsigned int i;
 
 	assert(kd);
 	assert(vn);
 	assert(fst);
 	vp = fst->fs_typedep;
 	if (vp == NULL)
 		goto fail;
 	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
 	if (error == 0) {
 		warnx("can't read vnode at %p", (void *)vp);
 		goto fail;
 	}
 	bzero(vn, sizeof(*vn));
 	vn->vn_type = vntype2psfsttype(vnode.v_type);
 	if (vnode.v_type == VNON || vnode.v_type == VBAD)
 		return (0);
 	error = kvm_read_all(kd, (unsigned long)vnode.v_lock.lock_object.lo_name,
 	    tagstr, sizeof(tagstr));
 	if (error == 0) {
 		warnx("can't read lo_name at %p", (void *)vp);
 		goto fail;
 	}
 	tagstr[sizeof(tagstr) - 1] = '\0';
 
 	/*
 	 * Find appropriate handler.
 	 */
 	for (i = 0; i < NTYPES; i++)
 		if (!strcmp(fstypes[i].tag, tagstr)) {
 			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
 				goto fail;
 			}
 			break;
 		}
 	if (i == NTYPES) {
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
 		return (1);
 	}
 	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
 	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
 	    vnode.v_rdev != NULL){
 		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
 		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
 	} else {
 		vn->vn_dev = -1;
 	}
 	return (0);
 
 fail:
 	if (errbuf != NULL)
 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 	return (1);
 }
 
 /*
  * kinfo vnode type to filestat translation.
  */
 static int
 kinfo_vtype2fst(int kfvtype)
 {
 	static struct {
 		int	kf_vtype; 
 		int	fst_vtype;
 	} kfvtypes2fst[] = {
 		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
 		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
 		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
 		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
 		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
 		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
 		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
 		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
 		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
 	};
 #define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
 	unsigned int i;
 
 	for (i = 0; i < NKFVTYPES; i++)
 		if (kfvtypes2fst[i].kf_vtype == kfvtype)
 			break;
 	if (i == NKFVTYPES)
 		return (PS_FST_VTYPE_UNKNOWN);
 	return (kfvtypes2fst[i].fst_vtype);
 }
 
 static int
 procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
     char *errbuf)
 {
 	struct statfs stbuf;
 	struct kinfo_file *kif;
 	struct kinfo_vmentry *kve;
 	char *name, *path;
 	uint64_t fileid;
 	uint64_t size;
 	uint64_t fsid;
 	uint64_t rdev;
 	uint16_t mode;
 	int vntype;
 	int status;
 
 	assert(fst);
 	assert(vn);
 	bzero(vn, sizeof(*vn));
 	if (fst->fs_typedep == NULL)
 		return (1);
 	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
 		kve = fst->fs_typedep;
 		fileid = kve->kve_vn_fileid;
 		fsid = kve->kve_vn_fsid;
 		mode = kve->kve_vn_mode;
 		path = kve->kve_path;
 		rdev = kve->kve_vn_rdev;
 		size = kve->kve_vn_size;
 		vntype = kinfo_vtype2fst(kve->kve_vn_type);
 		status = kve->kve_status;
 	} else {
 		kif = fst->fs_typedep;
 		fileid = kif->kf_un.kf_file.kf_file_fileid;
 		fsid = kif->kf_un.kf_file.kf_file_fsid;
 		mode = kif->kf_un.kf_file.kf_file_mode;
 		path = kif->kf_path;
 		rdev = kif->kf_un.kf_file.kf_file_rdev;
 		size = kif->kf_un.kf_file.kf_file_size;
 		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
 		status = kif->kf_status;
 	}
 	vn->vn_type = vntype;
 	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
 		return (0);
 	if ((status & KF_ATTR_VALID) == 0) {
 		if (errbuf != NULL) {
 			snprintf(errbuf, _POSIX2_LINE_MAX,
 			    "? (no info available)");
 		}
 		return (1);
 	}
 	if (path && *path) {
 		statfs(path, &stbuf);
 		vn->vn_mntdir = strdup(stbuf.f_mntonname);
 	} else
 		vn->vn_mntdir = strdup("-");
 	vn->vn_dev = rdev;
 	if (vntype == PS_FST_VTYPE_VBLK) {
 		name = devname(rdev, S_IFBLK);
 		if (name != NULL)
 			strlcpy(vn->vn_devname, name,
 			    sizeof(vn->vn_devname));
 	} else if (vntype == PS_FST_VTYPE_VCHR) {
 		name = devname(vn->vn_dev, S_IFCHR);
 		if (name != NULL)
 			strlcpy(vn->vn_devname, name,
 			    sizeof(vn->vn_devname));
 	}
 	vn->vn_fsid = fsid;
 	vn->vn_fileid = fileid;
 	vn->vn_size = size;
 	vn->vn_mode = mode;
 	return (0);
 }
 
 int
 procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
     struct sockstat *sock, char *errbuf)
 {
 
 	assert(sock);
 	if (procstat->type == PROCSTAT_KVM) {
 		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
 		    errbuf));
 	} else if (procstat->type == PROCSTAT_SYSCTL ||
 		procstat->type == PROCSTAT_CORE) {
 		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
 	} else {
 		warnx("unknown access method: %d", procstat->type);
 		if (errbuf != NULL)
 			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 		return (1);
 	}
 }
 
 static int
 procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
     struct sockstat *sock, char *errbuf)
 {
 	struct domain dom;
 	struct inpcb inpcb;
 	struct protosw proto;
 	struct socket s;
 	struct unpcb unpcb;
 	ssize_t len;
 	void *so;
 
 	assert(kd);
 	assert(sock);
 	assert(fst);
 	bzero(sock, sizeof(*sock));
 	so = fst->fs_typedep;
 	if (so == NULL)
 		goto fail;
 	sock->so_addr = (uintptr_t)so;
 	/* fill in socket */
 	if (!kvm_read_all(kd, (unsigned long)so, &s,
 	    sizeof(struct socket))) {
 		warnx("can't read sock at %p", (void *)so);
 		goto fail;
 	}
 	/* fill in protosw entry */
 	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
 	    sizeof(struct protosw))) {
 		warnx("can't read protosw at %p", (void *)s.so_proto);
 		goto fail;
 	}
 	/* fill in domain */
 	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
 	    sizeof(struct domain))) {
 		warnx("can't read domain at %p",
 		    (void *)proto.pr_domain);
 		goto fail;
 	}
 	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
 	    sizeof(sock->dname) - 1)) < 0) {
 		warnx("can't read domain name at %p", (void *)dom.dom_name);
 		sock->dname[0] = '\0';
 	}
 	else
 		sock->dname[len] = '\0';
 	
 	/*
 	 * Fill in known data.
 	 */
 	sock->type = s.so_type;
 	sock->proto = proto.pr_protocol;
 	sock->dom_family = dom.dom_family;
 	sock->so_pcb = (uintptr_t)s.so_pcb;
 
 	/*
 	 * Protocol specific data.
 	 */
 	switch(dom.dom_family) {
 	case AF_INET:
 	case AF_INET6:
 		if (proto.pr_protocol == IPPROTO_TCP) {
 			if (s.so_pcb) {
 				if (kvm_read(kd, (u_long)s.so_pcb,
 				    (char *)&inpcb, sizeof(struct inpcb))
 				    != sizeof(struct inpcb)) {
 					warnx("can't read inpcb at %p",
 					    (void *)s.so_pcb);
 				} else
 					sock->inp_ppcb =
 					    (uintptr_t)inpcb.inp_ppcb;
 				sock->sendq = s.so_snd.sb_ccc;
 				sock->recvq = s.so_rcv.sb_ccc;
 			}
 		}
 		break;
 	case AF_UNIX:
 		if (s.so_pcb) {
 			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
 			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
 				warnx("can't read unpcb at %p",
 				    (void *)s.so_pcb);
 			} else if (unpcb.unp_conn) {
 				sock->so_rcv_sb_state = s.so_rcv.sb_state;
 				sock->so_snd_sb_state = s.so_snd.sb_state;
 				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
 				sock->sendq = s.so_snd.sb_ccc;
 				sock->recvq = s.so_rcv.sb_ccc;
 			}
 		}
 		break;
 	default:
 		break;
 	}
 	return (0);
 
 fail:
 	if (errbuf != NULL)
 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
 	return (1);
 }
 
 static int
 procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
     char *errbuf __unused)
 {
 	struct kinfo_file *kif;
 
 	assert(sock);
 	assert(fst);
 	bzero(sock, sizeof(*sock));
 	kif = fst->fs_typedep;
 	if (kif == NULL)
 		return (0);
 
 	/*
 	 * Fill in known data.
 	 */
 	sock->type = kif->kf_sock_type;
 	sock->proto = kif->kf_sock_protocol;
 	sock->dom_family = kif->kf_sock_domain;
 	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
 	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
 	bcopy(&kif->kf_un.kf_sock.kf_sa_local, &sock->sa_local,
 	    kif->kf_un.kf_sock.kf_sa_local.ss_len);
 	bcopy(&kif->kf_un.kf_sock.kf_sa_peer, &sock->sa_peer,
 	    kif->kf_un.kf_sock.kf_sa_peer.ss_len);
 
 	/*
 	 * Protocol specific data.
 	 */
 	switch(sock->dom_family) {
 	case AF_INET:
 	case AF_INET6:
 		if (sock->proto == IPPROTO_TCP) {
 			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
 			sock->sendq = kif->kf_un.kf_sock.kf_sock_sendq;
 			sock->recvq = kif->kf_un.kf_sock.kf_sock_recvq;
 		}
 		break;
 	case AF_UNIX:
 		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
 			sock->so_rcv_sb_state =
 			    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
 			sock->so_snd_sb_state =
 			    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
 			sock->unp_conn =
 			    kif->kf_un.kf_sock.kf_sock_unpconn;
 			sock->sendq = kif->kf_un.kf_sock.kf_sock_sendq;
 			sock->recvq = kif->kf_un.kf_sock.kf_sock_recvq;
 		}
 		break;
 	default:
 		break;
 	}
 	return (0);
 }
 
 /*
  * Descriptor flags to filestat translation.
  */
 static int
 to_filestat_flags(int flags)
 {
 	static struct {
 		int flag;
 		int fst_flag;
 	} fstflags[] = {
 		{ FREAD, PS_FST_FFLAG_READ },
 		{ FWRITE, PS_FST_FFLAG_WRITE },
 		{ O_APPEND, PS_FST_FFLAG_APPEND },
 		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
 		{ O_CREAT, PS_FST_FFLAG_CREAT },
 		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
 		{ O_EXCL, PS_FST_FFLAG_EXCL },
 		{ O_EXEC, PS_FST_FFLAG_EXEC },
 		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
 		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
 		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
 		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
 		{ O_SYNC, PS_FST_FFLAG_SYNC },
 		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
 	};
 #define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
 	int fst_flags;
 	unsigned int i;
 
 	fst_flags = 0;
 	for (i = 0; i < NFSTFLAGS; i++)
 		if (flags & fstflags[i].flag)
 			fst_flags |= fstflags[i].fst_flag;
 	return (fst_flags);
 }
 
 /*
  * Vnode type to filestate translation.
  */
 static int
 vntype2psfsttype(int type)
 {
 	static struct {
 		int	vtype; 
 		int	fst_vtype;
 	} vt2fst[] = {
 		{ VBAD, PS_FST_VTYPE_VBAD },
 		{ VBLK, PS_FST_VTYPE_VBLK },
 		{ VCHR, PS_FST_VTYPE_VCHR },
 		{ VDIR, PS_FST_VTYPE_VDIR },
 		{ VFIFO, PS_FST_VTYPE_VFIFO },
 		{ VLNK, PS_FST_VTYPE_VLNK },
 		{ VNON, PS_FST_VTYPE_VNON },
 		{ VREG, PS_FST_VTYPE_VREG },
 		{ VSOCK, PS_FST_VTYPE_VSOCK }
 	};
 #define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
 	unsigned int i, fst_type;
 
 	fst_type = PS_FST_VTYPE_UNKNOWN;
 	for (i = 0; i < NVFTYPES; i++) {
 		if (type == vt2fst[i].vtype) {
 			fst_type = vt2fst[i].fst_vtype;
 			break;
 		}
 	}
 	return (fst_type);
 }
 
 static char *
 getmnton(kvm_t *kd, struct mount *m)
 {
 	struct mount mnt;
 	static struct mtab {
 		struct mtab *next;
 		struct mount *m;
 		char mntonname[MNAMELEN + 1];
 	} *mhead = NULL;
 	struct mtab *mt;
 
 	for (mt = mhead; mt != NULL; mt = mt->next)
 		if (m == mt->m)
 			return (mt->mntonname);
 	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
 		warnx("can't read mount table at %p", (void *)m);
 		return (NULL);
 	}
 	if ((mt = malloc(sizeof (struct mtab))) == NULL)
 		err(1, NULL);
 	mt->m = m;
 	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
 	mt->mntonname[MNAMELEN] = '\0';
 	mt->next = mhead;
 	mhead = mt;
 	return (mt->mntonname);
 }
 
 /*
  * Auxiliary structures and functions to get process environment or
  * command line arguments.
  */
 struct argvec {
 	char	*buf;
 	size_t	bufsize;
 	char	**argv;
 	size_t	argc;
 };
 
 static struct argvec *
 argvec_alloc(size_t bufsize)
 {
 	struct argvec *av;
 
 	av = malloc(sizeof(*av));
 	if (av == NULL)
 		return (NULL);
 	av->bufsize = bufsize;
 	av->buf = malloc(av->bufsize);
 	if (av->buf == NULL) {
 		free(av);
 		return (NULL);
 	}
 	av->argc = 32;
 	av->argv = malloc(sizeof(char *) * av->argc);
 	if (av->argv == NULL) {
 		free(av->buf);
 		free(av);
 		return (NULL);
 	}
 	return av;
 }
 
 static void
 argvec_free(struct argvec * av)
 {
 
 	free(av->argv);
 	free(av->buf);
 	free(av);
 }
 
 static char **
 getargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env)
 {
 	int error, name[4], argc, i;
 	struct argvec *av, **avp;
 	enum psc_type type;
 	size_t len;
 	char *p, **argv;
 
 	assert(procstat);
 	assert(kp);
 	if (procstat->type == PROCSTAT_KVM) {
 		warnx("can't use kvm access method");
 		return (NULL);
 	}
 	if (procstat->type != PROCSTAT_SYSCTL &&
 	    procstat->type != PROCSTAT_CORE) {
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 
 	if (nchr == 0 || nchr > ARG_MAX)
 		nchr = ARG_MAX;
 
 	avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv);
 	av = *avp;
 
 	if (av == NULL)
 	{
 		av = argvec_alloc(nchr);
 		if (av == NULL)
 		{
 			warn("malloc(%zu)", nchr);
 			return (NULL);
 		}
 		*avp = av;
 	} else if (av->bufsize < nchr) {
 		av->buf = reallocf(av->buf, nchr);
 		if (av->buf == NULL) {
 			warn("malloc(%zu)", nchr);
 			return (NULL);
 		}
 	}
 	if (procstat->type == PROCSTAT_SYSCTL) {
 		name[0] = CTL_KERN;
 		name[1] = KERN_PROC;
 		name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
 		name[3] = kp->ki_pid;
 		len = nchr;
 		error = sysctl(name, nitems(name), av->buf, &len, NULL, 0);
 		if (error != 0 && errno != ESRCH && errno != EPERM)
 			warn("sysctl(kern.proc.%s)", env ? "env" : "args");
 		if (error != 0 || len == 0)
 			return (NULL);
 	} else /* procstat->type == PROCSTAT_CORE */ {
 		type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV;
 		len = nchr;
 		if (procstat_core_get(procstat->core, type, av->buf, &len)
 		    == NULL) {
 			return (NULL);
 		}
 	}
 
 	argv = av->argv;
 	argc = av->argc;
 	i = 0;
 	for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) {
 		argv[i++] = p;
 		if (i < argc)
 			continue;
 		/* Grow argv. */
 		argc += argc;
 		argv = realloc(argv, sizeof(char *) * argc);
 		if (argv == NULL) {
 			warn("malloc(%zu)", sizeof(char *) * argc);
 			return (NULL);
 		}
 		av->argv = argv;
 		av->argc = argc;
 	}
 	argv[i] = NULL;
 
 	return (argv);
 }
 
 /*
  * Return process command line arguments.
  */
 char **
 procstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
 {
 
 	return (getargv(procstat, p, nchr, 0));
 }
 
 /*
  * Free the buffer allocated by procstat_getargv().
  */
 void
 procstat_freeargv(struct procstat *procstat)
 {
 
 	if (procstat->argv != NULL) {
 		argvec_free(procstat->argv);
 		procstat->argv = NULL;
 	}
 }
 
 /*
  * Return process environment.
  */
 char **
 procstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
 {
 
 	return (getargv(procstat, p, nchr, 1));
 }
 
 /*
  * Free the buffer allocated by procstat_getenvv().
  */
 void
 procstat_freeenvv(struct procstat *procstat)
 {
 	if (procstat->envv != NULL) {
 		argvec_free(procstat->envv);
 		procstat->envv = NULL;
 	}
 }
 
 static struct kinfo_vmentry *
 kinfo_getvmmap_core(struct procstat_core *core, int *cntp)
 {
 	int cnt;
 	size_t len;
 	char *buf, *bp, *eb;
 	struct kinfo_vmentry *kiv, *kp, *kv;
 
 	buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len);
 	if (buf == NULL)
 		return (NULL);
 
 	/*
 	 * XXXMG: The code below is just copy&past from libutil.
 	 * The code duplication can be avoided if libutil
 	 * is extended to provide something like:
 	 *   struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf,
 	 *       size_t len, int *cntp);
 	 */
 
 	/* Pass 1: count items */
 	cnt = 0;
 	bp = buf;
 	eb = buf + len;
 	while (bp < eb) {
 		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
 		if (kv->kve_structsize == 0)
 			break;
 		bp += kv->kve_structsize;
 		cnt++;
 	}
 
 	kiv = calloc(cnt, sizeof(*kiv));
 	if (kiv == NULL) {
 		free(buf);
 		return (NULL);
 	}
 	bp = buf;
 	eb = buf + len;
 	kp = kiv;
 	/* Pass 2: unpack */
 	while (bp < eb) {
 		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
 		if (kv->kve_structsize == 0)
 			break;
 		/* Copy/expand into pre-zeroed buffer */
 		memcpy(kp, kv, kv->kve_structsize);
 		/* Advance to next packed record */
 		bp += kv->kve_structsize;
 		/* Set field size to fixed length, advance */
 		kp->kve_structsize = sizeof(*kp);
 		kp++;
 	}
 	free(buf);
 	*cntp = cnt;
 	return (kiv);	/* Caller must free() return value */
 }
 
 struct kinfo_vmentry *
 procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp,
     unsigned int *cntp)
 {
 
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		warnx("kvm method is not supported");
 		return (NULL);
 	case PROCSTAT_SYSCTL:
 		return (kinfo_getvmmap(kp->ki_pid, cntp));
 	case PROCSTAT_CORE:
 		return (kinfo_getvmmap_core(procstat->core, cntp));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 }
 
 void
 procstat_freevmmap(struct procstat *procstat __unused,
     struct kinfo_vmentry *vmmap)
 {
 
 	free(vmmap);
 }
 
 static gid_t *
 procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp)
 {
 	struct proc proc;
 	struct ucred ucred;
 	gid_t *groups;
 	size_t len;
 
 	assert(kd != NULL);
 	assert(kp != NULL);
 	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
 	    sizeof(proc))) {
 		warnx("can't read proc struct at %p for pid %d",
 		    kp->ki_paddr, kp->ki_pid);
 		return (NULL);
 	}
 	if (proc.p_ucred == NOCRED)
 		return (NULL);
 	if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred,
 	    sizeof(ucred))) {
 		warnx("can't read ucred struct at %p for pid %d",
 		    proc.p_ucred, kp->ki_pid);
 		return (NULL);
 	}
 	len = ucred.cr_ngroups * sizeof(gid_t);
 	groups = malloc(len);
 	if (groups == NULL) {
 		warn("malloc(%zu)", len);
 		return (NULL);
 	}
 	if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) {
 		warnx("can't read groups at %p for pid %d",
 		    ucred.cr_groups, kp->ki_pid);
 		free(groups);
 		return (NULL);
 	}
 	*cntp = ucred.cr_ngroups;
 	return (groups);
 }
 
 static gid_t *
 procstat_getgroups_sysctl(pid_t pid, unsigned int *cntp)
 {
 	int mib[4];
 	size_t len;
 	gid_t *groups;
 
 	mib[0] = CTL_KERN;
 	mib[1] = KERN_PROC;
 	mib[2] = KERN_PROC_GROUPS;
 	mib[3] = pid;
 	len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t);
 	groups = malloc(len);
 	if (groups == NULL) {
 		warn("malloc(%zu)", len);
 		return (NULL);
 	}
 	if (sysctl(mib, nitems(mib), groups, &len, NULL, 0) == -1) {
 		warn("sysctl: kern.proc.groups: %d", pid);
 		free(groups);
 		return (NULL);
 	}
 	*cntp = len / sizeof(gid_t);
 	return (groups);
 }
 
 static gid_t *
 procstat_getgroups_core(struct procstat_core *core, unsigned int *cntp)
 {
 	size_t len;
 	gid_t *groups;
 
 	groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len);
 	if (groups == NULL)
 		return (NULL);
 	*cntp = len / sizeof(gid_t);
 	return (groups);
 }
 
 gid_t *
 procstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
     unsigned int *cntp)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		return (procstat_getgroups_kvm(procstat->kd, kp, cntp));
 	case PROCSTAT_SYSCTL:
 		return (procstat_getgroups_sysctl(kp->ki_pid, cntp));
 	case PROCSTAT_CORE:
 		return (procstat_getgroups_core(procstat->core, cntp));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 }
 
 void
 procstat_freegroups(struct procstat *procstat __unused, gid_t *groups)
 {
 
 	free(groups);
 }
 
 static int
 procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp)
 {
 	struct pwddesc pd;
 
 	assert(kd != NULL);
 	assert(kp != NULL);
 	if (kp->ki_pd == NULL)
 		return (-1);
 	if (!kvm_read_all(kd, (unsigned long)kp->ki_pd, &pd, sizeof(pd))) {
 		warnx("can't read pwddesc at %p for pid %d", kp->ki_pd,
 		    kp->ki_pid);
 		return (-1);
 	}
 	*maskp = pd.pd_cmask;
 	return (0);
 }
 
 static int
 procstat_getumask_sysctl(pid_t pid, unsigned short *maskp)
 {
 	int error;
 	int mib[4];
 	size_t len;
 
 	mib[0] = CTL_KERN;
 	mib[1] = KERN_PROC;
 	mib[2] = KERN_PROC_UMASK;
 	mib[3] = pid;
 	len = sizeof(*maskp);
 	error = sysctl(mib, nitems(mib), maskp, &len, NULL, 0);
 	if (error != 0 && errno != ESRCH && errno != EPERM)
 		warn("sysctl: kern.proc.umask: %d", pid);
 	return (error);
 }
 
 static int
 procstat_getumask_core(struct procstat_core *core, unsigned short *maskp)
 {
 	size_t len;
 	unsigned short *buf;
 
 	buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len);
 	if (buf == NULL)
 		return (-1);
 	if (len < sizeof(*maskp)) {
 		free(buf);
 		return (-1);
 	}
 	*maskp = *buf;
 	free(buf);
 	return (0);
 }
 
 int
 procstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
     unsigned short *maskp)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		return (procstat_getumask_kvm(procstat->kd, kp, maskp));
 	case PROCSTAT_SYSCTL:
 		return (procstat_getumask_sysctl(kp->ki_pid, maskp));
 	case PROCSTAT_CORE:
 		return (procstat_getumask_core(procstat->core, maskp));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (-1);
 	}
 }
 
 static int
 procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which,
     struct rlimit* rlimit)
 {
 	struct proc proc;
 	unsigned long offset;
 
 	assert(kd != NULL);
 	assert(kp != NULL);
 	assert(which >= 0 && which < RLIM_NLIMITS);
 	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
 	    sizeof(proc))) {
 		warnx("can't read proc struct at %p for pid %d",
 		    kp->ki_paddr, kp->ki_pid);
 		return (-1);
 	}
 	if (proc.p_limit == NULL)
 		return (-1);
 	offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which;
 	if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) {
 		warnx("can't read rlimit struct at %p for pid %d",
 		    (void *)offset, kp->ki_pid);
 		return (-1);
 	}
 	return (0);
 }
 
 static int
 procstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit)
 {
 	int error, name[5];
 	size_t len;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_RLIMIT;
 	name[3] = pid;
 	name[4] = which;
 	len = sizeof(struct rlimit);
 	error = sysctl(name, nitems(name), rlimit, &len, NULL, 0);
 	if (error < 0 && errno != ESRCH) {
 		warn("sysctl: kern.proc.rlimit: %d", pid);
 		return (-1);
 	}
 	if (error < 0 || len != sizeof(struct rlimit))
 		return (-1);
 	return (0);
 }
 
 static int
 procstat_getrlimit_core(struct procstat_core *core, int which,
     struct rlimit* rlimit)
 {
 	size_t len;
 	struct rlimit* rlimits;
 
 	if (which < 0 || which >= RLIM_NLIMITS) {
 		errno = EINVAL;
 		warn("getrlimit: which");
 		return (-1);
 	}
 	rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len);
 	if (rlimits == NULL)
 		return (-1);
 	if (len < sizeof(struct rlimit) * RLIM_NLIMITS) {
 		free(rlimits);
 		return (-1);
 	}
 	*rlimit = rlimits[which];
 	free(rlimits);
 	return (0);
 }
 
 int
 procstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which,
     struct rlimit* rlimit)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		return (procstat_getrlimit_kvm(procstat->kd, kp, which,
 		    rlimit));
 	case PROCSTAT_SYSCTL:
 		return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit));
 	case PROCSTAT_CORE:
 		return (procstat_getrlimit_core(procstat->core, which, rlimit));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (-1);
 	}
 }
 
 static int
 procstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen)
 {
 	int error, name[4];
 	size_t len;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_PATHNAME;
 	name[3] = pid;
 	len = maxlen;
 	error = sysctl(name, nitems(name), pathname, &len, NULL, 0);
 	if (error != 0 && errno != ESRCH)
 		warn("sysctl: kern.proc.pathname: %d", pid);
 	if (len == 0)
 		pathname[0] = '\0';
 	return (error);
 }
 
 static int
 procstat_getpathname_core(struct procstat_core *core, char *pathname,
     size_t maxlen)
 {
 	struct kinfo_file *files;
 	int cnt, i, result;
 
 	files = kinfo_getfile_core(core, &cnt);
 	if (files == NULL)
 		return (-1);
 	result = -1;
 	for (i = 0; i < cnt; i++) {
 		if (files[i].kf_fd != KF_FD_TYPE_TEXT)
 			continue;
 		strncpy(pathname, files[i].kf_path, maxlen);
 		result = 0;
 		break;
 	}
 	free(files);
 	return (result);
 }
 
 int
 procstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
     char *pathname, size_t maxlen)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		/* XXX: Return empty string. */
 		if (maxlen > 0)
 			pathname[0] = '\0';
 		return (0);
 	case PROCSTAT_SYSCTL:
 		return (procstat_getpathname_sysctl(kp->ki_pid, pathname,
 		    maxlen));
 	case PROCSTAT_CORE:
 		return (procstat_getpathname_core(procstat->core, pathname,
 		    maxlen));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (-1);
 	}
 }
 
 static int
 procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp)
 {
 	struct proc proc;
 
 	assert(kd != NULL);
 	assert(kp != NULL);
 	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
 	    sizeof(proc))) {
 		warnx("can't read proc struct at %p for pid %d",
 		    kp->ki_paddr, kp->ki_pid);
 		return (-1);
 	}
 	*osrelp = proc.p_osrel;
 	return (0);
 }
 
 static int
 procstat_getosrel_sysctl(pid_t pid, int *osrelp)
 {
 	int error, name[4];
 	size_t len;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_OSREL;
 	name[3] = pid;
 	len = sizeof(*osrelp);
 	error = sysctl(name, nitems(name), osrelp, &len, NULL, 0);
 	if (error != 0 && errno != ESRCH)
 		warn("sysctl: kern.proc.osrel: %d", pid);
 	return (error);
 }
 
 static int
 procstat_getosrel_core(struct procstat_core *core, int *osrelp)
 {
 	size_t len;
 	int *buf;
 
 	buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len);
 	if (buf == NULL)
 		return (-1);
 	if (len < sizeof(*osrelp)) {
 		free(buf);
 		return (-1);
 	}
 	*osrelp = *buf;
 	free(buf);
 	return (0);
 }
 
 int
 procstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		return (procstat_getosrel_kvm(procstat->kd, kp, osrelp));
 	case PROCSTAT_SYSCTL:
 		return (procstat_getosrel_sysctl(kp->ki_pid, osrelp));
 	case PROCSTAT_CORE:
 		return (procstat_getosrel_core(procstat->core, osrelp));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (-1);
 	}
 }
 
 #define PROC_AUXV_MAX	256
 
 #if __ELF_WORD_SIZE == 64
 static const char *elf32_sv_names[] = {
 	"Linux ELF32",
 	"FreeBSD ELF32",
 };
 
 static int
 is_elf32_sysctl(pid_t pid)
 {
 	int error, name[4];
 	size_t len, i;
 	static char sv_name[256];
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_SV_NAME;
 	name[3] = pid;
 	len = sizeof(sv_name);
 	error = sysctl(name, nitems(name), sv_name, &len, NULL, 0);
 	if (error != 0 || len == 0)
 		return (0);
 	for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) {
 		if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0)
 			return (1);
 	}
 	return (0);
 }
 
 static Elf_Auxinfo *
 procstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp)
 {
 	Elf_Auxinfo *auxv;
 	Elf32_Auxinfo *auxv32;
 	void *ptr;
 	size_t len;
 	unsigned int i, count;
 	int name[4];
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_AUXV;
 	name[3] = pid;
 	len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo);
 	auxv = NULL;
 	auxv32 = malloc(len);
 	if (auxv32 == NULL) {
 		warn("malloc(%zu)", len);
 		goto out;
 	}
 	if (sysctl(name, nitems(name), auxv32, &len, NULL, 0) == -1) {
 		if (errno != ESRCH && errno != EPERM)
 			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
 		goto out;
 	}
 	count = len / sizeof(Elf_Auxinfo);
 	auxv = malloc(count  * sizeof(Elf_Auxinfo));
 	if (auxv == NULL) {
 		warn("malloc(%zu)", count * sizeof(Elf_Auxinfo));
 		goto out;
 	}
 	for (i = 0; i < count; i++) {
 		/*
 		 * XXX: We expect that values for a_type on a 32-bit platform
 		 * are directly mapped to values on 64-bit one, which is not
 		 * necessarily true.
 		 */
 		auxv[i].a_type = auxv32[i].a_type;
 		ptr = &auxv32[i].a_un;
 		auxv[i].a_un.a_val = *((uint32_t *)ptr);
 	}
 	*cntp = count;
 out:
 	free(auxv32);
 	return (auxv);
 }
 #endif /* __ELF_WORD_SIZE == 64 */
 
 static Elf_Auxinfo *
 procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp)
 {
 	Elf_Auxinfo *auxv;
 	int name[4];
 	size_t len;
 
 #if __ELF_WORD_SIZE == 64
 	if (is_elf32_sysctl(pid))
 		return (procstat_getauxv32_sysctl(pid, cntp));
 #endif
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_AUXV;
 	name[3] = pid;
 	len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo);
 	auxv = malloc(len);
 	if (auxv == NULL) {
 		warn("malloc(%zu)", len);
 		return (NULL);
 	}
 	if (sysctl(name, nitems(name), auxv, &len, NULL, 0) == -1) {
 		if (errno != ESRCH && errno != EPERM)
 			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
 		free(auxv);
 		return (NULL);
 	}
 	*cntp = len / sizeof(Elf_Auxinfo);
 	return (auxv);
 }
 
 static Elf_Auxinfo *
 procstat_getauxv_core(struct procstat_core *core, unsigned int *cntp)
 {
 	Elf_Auxinfo *auxv;
 	size_t len;
 
 	auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len);
 	if (auxv == NULL)
 		return (NULL);
 	*cntp = len / sizeof(Elf_Auxinfo);
 	return (auxv);
 }
 
 Elf_Auxinfo *
 procstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp,
     unsigned int *cntp)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		warnx("kvm method is not supported");
 		return (NULL);
 	case PROCSTAT_SYSCTL:
 		return (procstat_getauxv_sysctl(kp->ki_pid, cntp));
 	case PROCSTAT_CORE:
 		return (procstat_getauxv_core(procstat->core, cntp));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 }
 
 void
 procstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv)
 {
 
 	free(auxv);
 }
 
 static struct ptrace_lwpinfo *
 procstat_getptlwpinfo_core(struct procstat_core *core, unsigned int *cntp)
 {
 	void *buf;
 	struct ptrace_lwpinfo *pl;
 	unsigned int cnt;
 	size_t len;
 
 	cnt = procstat_core_note_count(core, PSC_TYPE_PTLWPINFO);
 	if (cnt == 0)
 		return (NULL);
 
 	len = cnt * sizeof(*pl);
 	buf = calloc(1, len);
 	pl = procstat_core_get(core, PSC_TYPE_PTLWPINFO, buf, &len);
 	if (pl == NULL) {
 		free(buf);
 		return (NULL);
 	}
 	*cntp = len / sizeof(*pl);
 	return (pl);
 }
 
 struct ptrace_lwpinfo *
 procstat_getptlwpinfo(struct procstat *procstat, unsigned int *cntp)
 {
 	switch (procstat->type) {
 	case PROCSTAT_KVM:
 		warnx("kvm method is not supported");
 		return (NULL);
 	case PROCSTAT_SYSCTL:
 		warnx("sysctl method is not supported");
 		return (NULL);
 	case PROCSTAT_CORE:
 	 	return (procstat_getptlwpinfo_core(procstat->core, cntp));
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 }
 
 void
 procstat_freeptlwpinfo(struct procstat *procstat __unused,
     struct ptrace_lwpinfo *pl)
 {
 	free(pl);
 }
 
 static struct kinfo_kstack *
 procstat_getkstack_sysctl(pid_t pid, int *cntp)
 {
 	struct kinfo_kstack *kkstp;
 	int error, name[4];
 	size_t len;
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_PROC;
 	name[2] = KERN_PROC_KSTACK;
 	name[3] = pid;
 
 	len = 0;
 	error = sysctl(name, nitems(name), NULL, &len, NULL, 0);
 	if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
 		warn("sysctl: kern.proc.kstack: %d", pid);
 		return (NULL);
 	}
 	if (error == -1 && errno == ENOENT) {
 		warnx("sysctl: kern.proc.kstack unavailable"
 		    " (options DDB or options STACK required in kernel)");
 		return (NULL);
 	}
 	if (error == -1)
 		return (NULL);
 	kkstp = malloc(len);
 	if (kkstp == NULL) {
 		warn("malloc(%zu)", len);
 		return (NULL);
 	}
 	if (sysctl(name, nitems(name), kkstp, &len, NULL, 0) == -1) {
 		warn("sysctl: kern.proc.pid: %d", pid);
 		free(kkstp);
 		return (NULL);
 	}
 	*cntp = len / sizeof(*kkstp);
 
 	return (kkstp);
 }
 
 struct kinfo_kstack *
 procstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp,
     unsigned int *cntp)
 {
 	switch(procstat->type) {
 	case PROCSTAT_KVM:
 		warnx("kvm method is not supported");
 		return (NULL);
 	case PROCSTAT_SYSCTL:
 		return (procstat_getkstack_sysctl(kp->ki_pid, cntp));
 	case PROCSTAT_CORE:
 		warnx("core method is not supported");
 		return (NULL);
 	default:
 		warnx("unknown access method: %d", procstat->type);
 		return (NULL);
 	}
 }
 
 void
 procstat_freekstack(struct procstat *procstat __unused,
     struct kinfo_kstack *kkstp)
 {
 
 	free(kkstp);
 }
diff --git a/lib/libprocstat/zfs_defs.c b/lib/libprocstat/zfs_defs.c
index c41054f05136..66acef743dc4 100644
--- a/lib/libprocstat/zfs_defs.c
+++ b/lib/libprocstat/zfs_defs.c
@@ -1,85 +1,85 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2020 Andriy Gapon <avg@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
 __FBSDID("$FreeBSD$");
 
 
 /*
  * Prevent some headers from getting included and fake some types
  * in order to allow this file to compile without bringing in
  * too many kernel build dependencies.
  */
 #define _OPENSOLARIS_SYS_PATHNAME_H_
 #define _OPENSOLARIS_SYS_POLICY_H_
 #define _VNODE_PAGER_
 
 
 enum vtype	{ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD,
 		  VMARKER };
 
 /*
  * Vnode attributes.  A field value of VNOVAL represents a field whose value
  * is unavailable (getattr) or which is not to be changed (setattr).
  */
 struct vattr {
 	enum vtype	va_type;	/* vnode type (for create) */
 	u_short		va_mode;	/* files access mode and type */
 	u_short		va_padding0;
 	uid_t		va_uid;		/* owner user id */
 	gid_t		va_gid;		/* owner group id */
 	nlink_t		va_nlink;	/* number of references to file */
 	dev_t		va_fsid;	/* filesystem id */
 	ino_t		va_fileid;	/* file id */
 	u_quad_t	va_size;	/* file size in bytes */
 	long		va_blocksize;	/* blocksize preferred for i/o */
 	struct timespec	va_atime;	/* time of last access */
 	struct timespec	va_mtime;	/* time of last modification */
 	struct timespec	va_ctime;	/* time file changed */
 	struct timespec	va_birthtime;	/* time file created */
 	u_long		va_gen;		/* generation number of file */
 	u_long		va_flags;	/* flags defined for file */
 	dev_t		va_rdev;	/* device the special file represents */
 	u_quad_t	va_bytes;	/* bytes of disk space held by file */
 	u_quad_t	va_filerev;	/* file modification number */
 	u_int		va_vaflags;	/* operations flags, see below */
 	long		va_spare;	/* remain quad aligned */
 };
 
-
+#define _WANT_MOUNT
 #include <sys/zfs_context.h>
 #include <sys/zfs_znode.h>
 
 size_t sizeof_znode_t = sizeof(znode_t);
 size_t offsetof_z_id = offsetof(znode_t, z_id);
 size_t offsetof_z_size = offsetof(znode_t, z_size);
 size_t offsetof_z_mode = offsetof(znode_t, z_mode);
 
 /* Keep pcpu.h satisfied. */
 uintptr_t *__start_set_pcpu;
 uintptr_t *__stop_set_pcpu;
diff --git a/lib/libufs/block.c b/lib/libufs/block.c
index 7accc8863693..3c99d288a402 100644
--- a/lib/libufs/block.c
+++ b/lib/libufs/block.c
@@ -1,203 +1,205 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2002 Juli Mallett.  All rights reserved.
  *
  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
  * FreeBSD project.  Redistribution and use in source and binary forms, with
  * or without modification, are permitted provided that the following
  * conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistribution in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/disk.h>
 #include <sys/disklabel.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <libufs.h>
 
 ssize_t
 bread(struct uufsd *disk, ufs2_daddr_t blockno, void *data, size_t size)
 {
 	void *p2;
 	ssize_t cnt;
 
 	ERROR(disk, NULL);
 
 	p2 = data;
 	/*
 	 * XXX: various disk controllers require alignment of our buffer
 	 * XXX: which is stricter than struct alignment.
 	 * XXX: Bounce the buffer if not 64 byte aligned.
 	 * XXX: this can be removed if/when the kernel is fixed
 	 */
 	if (((intptr_t)data) & 0x3f) {
 		p2 = malloc(size);
 		if (p2 == NULL) {
 			ERROR(disk, "allocate bounce buffer");
 			goto fail;
 		}
 	}
 	cnt = pread(disk->d_fd, p2, size, (off_t)(blockno * disk->d_bsize));
 	if (cnt == -1) {
 		ERROR(disk, "read error from block device");
 		goto fail;
 	}
 	if (cnt == 0) {
 		ERROR(disk, "end of file from block device");
 		goto fail;
 	}
 	if ((size_t)cnt != size) {
 		ERROR(disk, "short read or read error from block device");
 		goto fail;
 	}
 	if (p2 != data) {
 		memcpy(data, p2, size);
 		free(p2);
 	}
 	return (cnt);
 fail:	memset(data, 0, size);
 	if (p2 != data) {
 		free(p2);
 	}
 	return (-1);
 }
 
 ssize_t
 bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size)
 {
 	ssize_t cnt;
 	int rv;
 	void *p2 = NULL;
 
 	ERROR(disk, NULL);
 
 	rv = ufs_disk_write(disk);
 	if (rv == -1) {
 		ERROR(disk, "failed to open disk for writing");
 		return (-1);
 	}
 
 	/*
 	 * XXX: various disk controllers require alignment of our buffer
 	 * XXX: which is stricter than struct alignment.
 	 * XXX: Bounce the buffer if not 64 byte aligned.
 	 * XXX: this can be removed if/when the kernel is fixed
 	 */
 	if (((intptr_t)data) & 0x3f) {
 		p2 = malloc(size);
 		if (p2 == NULL) {
 			ERROR(disk, "allocate bounce buffer");
 			return (-1);
 		}
 		memcpy(p2, data, size);
 		data = p2;
 	}
 	cnt = pwrite(disk->d_fd, data, size, (off_t)(blockno * disk->d_bsize));
 	if (p2 != NULL)
 		free(p2);
 	if (cnt == -1) {
 		ERROR(disk, "write error to block device");
 		return (-1);
 	}
 	if ((size_t)cnt != size) {
 		ERROR(disk, "short write to block device");
 		return (-1);
 	}
 
 	return (cnt);
 }
 
 #ifdef __FreeBSD_kernel__
 
 static int
 berase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
 {
 	off_t ioarg[2];
 
 	ioarg[0] = blockno * disk->d_bsize;
 	ioarg[1] = size;
 	return (ioctl(disk->d_fd, DIOCGDELETE, ioarg));
 }
 
 #else
 
 static int
 berase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
 {
 	char *zero_chunk;
 	off_t offset, zero_chunk_size, pwrite_size;
 	int rv;
 
 	offset = blockno * disk->d_bsize;
 	zero_chunk_size = 65536 * disk->d_bsize;
 	zero_chunk = calloc(1, zero_chunk_size);
 	if (zero_chunk == NULL) {
 		ERROR(disk, "failed to allocate memory");
 		return (-1);
 	}
 	while (size > 0) { 
 		pwrite_size = size;
 		if (pwrite_size > zero_chunk_size)
 			pwrite_size = zero_chunk_size;
 		rv = pwrite(disk->d_fd, zero_chunk, pwrite_size, offset);
 		if (rv == -1) {
 			ERROR(disk, "failed writing to disk");
 			break;
 		}
 		size -= rv;
 		offset += rv;
 		rv = 0;
 	}
 	free(zero_chunk);
 	return (rv);
 }
 
 #endif
 
 int
 berase(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
 {
 	int rv;
 
 	ERROR(disk, NULL);
 	rv = ufs_disk_write(disk);
 	if (rv == -1) {
 		ERROR(disk, "failed to open disk for writing");
 		return(rv);
 	}
 	return (berase_helper(disk, blockno, size));
 }
diff --git a/lib/libufs/cgroup.c b/lib/libufs/cgroup.c
index 1c3e271c4295..90b28eadad2c 100644
--- a/lib/libufs/cgroup.c
+++ b/lib/libufs/cgroup.c
@@ -1,314 +1,316 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2003 Juli Mallett.  All rights reserved.
  *
  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
  * FreeBSD project.  Redistribution and use in source and binary forms, with
  * or without modification, are permitted provided that the following
  * conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistribution in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/disklabel.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <libufs.h>
 
 ufs2_daddr_t
 cgballoc(struct uufsd *disk)
 {
 	u_int8_t *blksfree;
 	struct cg *cgp;
 	struct fs *fs;
 	long bno;
 
 	fs = &disk->d_fs;
 	cgp = &disk->d_cg;
 	blksfree = cg_blksfree(cgp);
 	for (bno = 0; bno < fs->fs_fpg / fs->fs_frag; bno++)
 		if (ffs_isblock(fs, blksfree, bno))
 			goto gotit;
 	return (0);
 gotit:
 	fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--;
 	ffs_clrblock(fs, blksfree, (long)bno);
 	ffs_clusteracct(fs, cgp, bno, -1);
 	cgp->cg_cs.cs_nbfree--;
 	fs->fs_cstotal.cs_nbfree--;
 	fs->fs_fmod = 1;
 	return (cgbase(fs, cgp->cg_cgx) + blkstofrags(fs, bno));
 }
 
 int
 cgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size)
 {
 	u_int8_t *blksfree;
 	struct fs *fs;
 	struct cg *cgp;
 	ufs1_daddr_t fragno, cgbno;
 	int i, cg, blk, frags, bbase;
 
 	fs = &disk->d_fs;
 	cg = dtog(fs, bno);
 	if (cgread1(disk, cg) != 1)
 		return (-1);
 	cgp = &disk->d_cg;
 	cgbno = dtogd(fs, bno);
 	blksfree = cg_blksfree(cgp);
 	if (size == fs->fs_bsize) {
 		fragno = fragstoblks(fs, cgbno);
 		ffs_setblock(fs, blksfree, fragno);
 		ffs_clusteracct(fs, cgp, fragno, 1);
 		cgp->cg_cs.cs_nbfree++;
 		fs->fs_cstotal.cs_nbfree++;
 		fs->fs_cs(fs, cg).cs_nbfree++;
 	} else {
 		bbase = cgbno - fragnum(fs, cgbno);
 		/*
 		 * decrement the counts associated with the old frags
 		 */
 		blk = blkmap(fs, blksfree, bbase);
 		ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
 		/*
 		 * deallocate the fragment
 		 */
 		frags = numfrags(fs, size);
 		for (i = 0; i < frags; i++)
 			setbit(blksfree, cgbno + i);
 		cgp->cg_cs.cs_nffree += i;
 		fs->fs_cstotal.cs_nffree += i;
 		fs->fs_cs(fs, cg).cs_nffree += i;
 		/*
 		 * add back in counts associated with the new frags
 		 */
 		blk = blkmap(fs, blksfree, bbase);
 		ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
 		/*
 		 * if a complete block has been reassembled, account for it
 		 */
 		fragno = fragstoblks(fs, bbase);
 		if (ffs_isblock(fs, blksfree, fragno)) {
 			cgp->cg_cs.cs_nffree -= fs->fs_frag;
 			fs->fs_cstotal.cs_nffree -= fs->fs_frag;
 			fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
 			ffs_clusteracct(fs, cgp, fragno, 1);
 			cgp->cg_cs.cs_nbfree++;
 			fs->fs_cstotal.cs_nbfree++;
 			fs->fs_cs(fs, cg).cs_nbfree++;
 		}
 	}
 	return cgwrite(disk);
 }
 
 ino_t
 cgialloc(struct uufsd *disk)
 {
 	struct ufs2_dinode *dp2;
 	u_int8_t *inosused;
 	struct cg *cgp;
 	struct fs *fs;
 	ino_t ino;
 	int i;
 
 	fs = &disk->d_fs;
 	cgp = &disk->d_cg;
 	inosused = cg_inosused(cgp);
 	for (ino = 0; ino < fs->fs_ipg; ino++)
 		if (isclr(inosused, ino))
 			goto gotit;
 	return (0);
 gotit:
 	if (fs->fs_magic == FS_UFS2_MAGIC &&
 	    ino + INOPB(fs) > cgp->cg_initediblk &&
 	    cgp->cg_initediblk < cgp->cg_niblk) {
 		char block[MAXBSIZE];
 		bzero(block, (int)fs->fs_bsize);
 		dp2 = (struct ufs2_dinode *)&block;
 		for (i = 0; i < INOPB(fs); i++) {
 			dp2->di_gen = arc4random();
 			dp2++;
 		}
 		if (bwrite(disk, ino_to_fsba(fs,
 		    cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk),
 		    block, fs->fs_bsize))
 			return (0);
 		cgp->cg_initediblk += INOPB(fs);
 	}
 
 	setbit(inosused, ino);
 	cgp->cg_irotor = ino;
 	cgp->cg_cs.cs_nifree--;
 	fs->fs_cstotal.cs_nifree--;
 	fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--;
 	fs->fs_fmod = 1;
 
 	return (ino + (cgp->cg_cgx * fs->fs_ipg));
 }
 
 int
 cgread(struct uufsd *disk)
 {
 
 	if (disk->d_ccg >= disk->d_fs.fs_ncg)
 		return (0);
 	return (cgread1(disk, disk->d_ccg++));
 }
 
 /* Short read/write error messages from cgget()/cgput() */
 static const char *failmsg;
 
 int
 cgread1(struct uufsd *disk, int c)
 {
 
 	if (cgget(disk->d_fd, &disk->d_fs, c, &disk->d_cg) == 0) {
 		disk->d_lcg = c;
 		return (1);
 	}
 	ERROR(disk, NULL);
 	if (failmsg != NULL) {
 		ERROR(disk, failmsg);
 		return (-1);
 	}
 	switch (errno) {
 	case EINTEGRITY:
 		ERROR(disk, "cylinder group checks failed");
 		break;
 	case EIO:
 		ERROR(disk, "read error from block device");
 		break;
 	default:
 		ERROR(disk, strerror(errno));
 		break;
 	}
 	return (-1);
 }
 
 int
 cgget(int devfd, struct fs *fs, int cg, struct cg *cgp)
 {
 	uint32_t cghash, calchash;
 	size_t cnt;
 
 	failmsg = NULL;
 	if ((cnt = pread(devfd, cgp, fs->fs_cgsize,
 	    fsbtodb(fs, cgtod(fs, cg)) * (fs->fs_fsize / fsbtodb(fs,1)))) < 0)
 		return (-1);
 	if (cnt == 0) {
 		failmsg = "end of file from block device";
 		errno = EIO;
 		return (-1);
 	}
 	if (cnt != fs->fs_cgsize) {
 		failmsg = "short read from block device";
 		errno = EIO;
 		return (-1);
 	}
 	calchash = cgp->cg_ckhash;
 	if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
 		cghash = cgp->cg_ckhash;
 		cgp->cg_ckhash = 0;
 		calchash = calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize);
 		cgp->cg_ckhash = cghash;
 	}
 	if (cgp->cg_ckhash != calchash || !cg_chkmagic(cgp) ||
 	    cgp->cg_cgx != cg) {
 		errno = EINTEGRITY;
 		return (-1);
 	}
 	return (0);
 }
 
 int
 cgwrite(struct uufsd *disk)
 {
 
 	return (cgwrite1(disk, disk->d_cg.cg_cgx));
 }
 
 int
 cgwrite1(struct uufsd *disk, int cg)
 {
 	static char errmsg[BUFSIZ];
 
 	if (cg == disk->d_cg.cg_cgx) {
 		if (cgput(disk->d_fd, &disk->d_fs, &disk->d_cg) == 0)
 			return (0);
 		ERROR(disk, NULL);
 		if (failmsg != NULL) {
 			ERROR(disk, failmsg);
 			return (-1);
 		}
 		switch (errno) {
 		case EIO:
 			ERROR(disk, "unable to write cylinder group");
 			break;
 		default:
 			ERROR(disk, strerror(errno));
 			break;
 		}
 		return (-1);
 	}
 	snprintf(errmsg, BUFSIZ, "Cylinder group %d in buffer does not match "
 	    "the cylinder group %d that cgwrite1 requested",
 	    disk->d_cg.cg_cgx, cg);
 	ERROR(disk, errmsg);
 	errno = EDOOFUS;
 	return (-1);
 }
 
 int
 cgput(int devfd, struct fs *fs, struct cg *cgp)
 {
 	size_t cnt;
 
 	if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
 		cgp->cg_ckhash = 0;
 		cgp->cg_ckhash =
 		    calculate_crc32c(~0L, (void *)cgp, fs->fs_cgsize);
 	}
 	failmsg = NULL;
 	if ((cnt = pwrite(devfd, cgp, fs->fs_cgsize,
 	    fsbtodb(fs, cgtod(fs, cgp->cg_cgx)) *
 	    (fs->fs_fsize / fsbtodb(fs,1)))) < 0)
 		return (-1);
 	if (cnt != fs->fs_cgsize) {
 		failmsg = "short write to block device";
 		return (-1);
 	}
 	return (0);
 }
diff --git a/lib/libufs/inode.c b/lib/libufs/inode.c
index 497ff4c854f6..c4a0cab9e95a 100644
--- a/lib/libufs/inode.c
+++ b/lib/libufs/inode.c
@@ -1,120 +1,122 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2002 Juli Mallett.  All rights reserved.
  *
  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
  * FreeBSD project.  Redistribution and use in source and binary forms, with
  * or without modification, are permitted provided that the following
  * conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistribution in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/disklabel.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <libufs.h>
 
 int
 getinode(struct uufsd *disk, union dinodep *dp, ino_t inum)
 {
 	ino_t min, max;
 	caddr_t inoblock;
 	struct fs *fs;
 
 	ERROR(disk, NULL);
 
 	fs = &disk->d_fs;
 	if (inum >= (ino_t)fs->fs_ipg * fs->fs_ncg) {
 		ERROR(disk, "inode number out of range");
 		return (-1);
 	}
 	inoblock = disk->d_inoblock;
 	min = disk->d_inomin;
 	max = disk->d_inomax;
 
 	if (inoblock == NULL) {
 		inoblock = malloc(fs->fs_bsize);
 		if (inoblock == NULL) {
 			ERROR(disk, "unable to allocate inode block");
 			return (-1);
 		}
 		disk->d_inoblock = inoblock;
 	}
 	if (inum >= min && inum < max)
 		goto gotit;
 	bread(disk, fsbtodb(fs, ino_to_fsba(fs, inum)), inoblock,
 	    fs->fs_bsize);
 	disk->d_inomin = min = inum - (inum % INOPB(fs));
 	disk->d_inomax = max = min + INOPB(fs);
 gotit:	switch (disk->d_ufs) {
 	case 1:
 		disk->d_dp.dp1 = &((struct ufs1_dinode *)inoblock)[inum - min];
 		if (dp != NULL)
 			*dp = disk->d_dp;
 		return (0);
 	case 2:
 		disk->d_dp.dp2 = &((struct ufs2_dinode *)inoblock)[inum - min];
 		if (dp != NULL)
 			*dp = disk->d_dp;
 		if (ffs_verify_dinode_ckhash(fs, disk->d_dp.dp2) == 0)
 			return (0);
 		ERROR(disk, "check-hash failed for inode read from disk");
 		return (-1);
 	default:
 		break;
 	}
 	ERROR(disk, "unknown UFS filesystem type");
 	return (-1);
 }
 
 int
 putinode(struct uufsd *disk)
 {
 	struct fs *fs;
 
 	fs = &disk->d_fs;
 	if (disk->d_inoblock == NULL) {
 		ERROR(disk, "No inode block allocated");
 		return (-1);
 	}
 	if (disk->d_ufs == 2)
 		ffs_update_dinode_ckhash(fs, disk->d_dp.dp2);
 	if (bwrite(disk, fsbtodb(fs, ino_to_fsba(&disk->d_fs, disk->d_inomin)),
 	    disk->d_inoblock, disk->d_fs.fs_bsize) <= 0)
 		return (-1);
 	return (0);
 }
diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c
index 1d687d6d41aa..3b65e79b02b5 100644
--- a/lib/libufs/sblock.c
+++ b/lib/libufs/sblock.c
@@ -1,209 +1,211 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2002 Juli Mallett.  All rights reserved.
  *
  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
  * FreeBSD project.  Redistribution and use in source and binary forms, with
  * or without modification, are permitted provided that the following
  * conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistribution in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/disklabel.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include <libufs.h>
 
 int
 sbread(struct uufsd *disk)
 {
 	struct fs *fs;
 
 	ERROR(disk, NULL);
 
 	if ((errno = sbget(disk->d_fd, &fs, STDSB)) != 0) {
 		switch (errno) {
 		case EIO:
 			ERROR(disk, "non-existent or truncated superblock");
 			break;
 		case ENOENT:
 			ERROR(disk, "no usable known superblock found");
 			break;
 		case ENOSPC:
 			ERROR(disk, "failed to allocate space for superblock "
 			    "information");
 			break;
 		case EINVAL:
 			ERROR(disk, "The previous newfs operation on this "
 			    "volume did not complete.\nYou must complete "
 			    "newfs before using this volume.");
 			break;
 		default:
 			ERROR(disk, "unknown superblock read error");
 			errno = EIO;
 			break;
 		}
 		disk->d_ufs = 0;
 		return (-1);
 	}
 	memcpy(&disk->d_fs, fs, fs->fs_sbsize);
 	free(fs);
 	fs = &disk->d_fs;
 	if (fs->fs_magic == FS_UFS1_MAGIC)
 		disk->d_ufs = 1;
 	if (fs->fs_magic == FS_UFS2_MAGIC)
 		disk->d_ufs = 2;
 	disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1);
 	disk->d_sblock = fs->fs_sblockloc / disk->d_bsize;
 	disk->d_si = fs->fs_si;
 	return (0);
 }
 
 int
 sbwrite(struct uufsd *disk, int all)
 {
 	struct fs *fs;
 	int rv;
 
 	ERROR(disk, NULL);
 
 	rv = ufs_disk_write(disk);
 	if (rv == -1) {
 		ERROR(disk, "failed to open disk for writing");
 		return (-1);
 	}
 
 	fs = &disk->d_fs;
 	if ((errno = sbput(disk->d_fd, fs, all ? fs->fs_ncg : 0)) != 0) {
 		switch (errno) {
 		case EIO:
 			ERROR(disk, "failed to write superblock");
 			break;
 		default:
 			ERROR(disk, "unknown superblock write error");
 			errno = EIO;
 			break;
 		}
 		return (-1);
 	}
 	return (0);
 }
 
 /*
  * These are the low-level functions that actually read and write
  * the superblock and its associated data. The actual work is done by
  * the functions ffs_sbget and ffs_sbput in /sys/ufs/ffs/ffs_subr.c.
  */
 static int use_pread(void *devfd, off_t loc, void **bufp, int size);
 static int use_pwrite(void *devfd, off_t loc, void *buf, int size);
 
 /*
  * Read a superblock from the devfd device allocating memory returned
  * in fsp. Also read the superblock summary information.
  */
 int
 sbget(int devfd, struct fs **fsp, off_t sblockloc)
 {
 
 	return (ffs_sbget(&devfd, fsp, sblockloc, "user", use_pread));
 }
 
 /*
  * A read function for use by user-level programs using libufs.
  */
 static int
 use_pread(void *devfd, off_t loc, void **bufp, int size)
 {
 	int fd;
 
 	fd = *(int *)devfd;
 	if ((*bufp = malloc(size)) == NULL)
 		return (ENOSPC);
 	if (pread(fd, *bufp, size, loc) != size)
 		return (EIO);
 	return (0);
 }
 
 /*
  * Write a superblock to the devfd device from the memory pointed to by fs.
  * Also write out the superblock summary information but do not free the
  * summary information memory.
  *
  * Additionally write out numaltwrite of the alternate superblocks. Use
  * fs->fs_ncg to write out all of the alternate superblocks.
  */
 int
 sbput(int devfd, struct fs *fs, int numaltwrite)
 {
 	struct csum *savedcsp;
 	off_t savedactualloc;
 	int i, error;
 
 	if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
 	     use_pwrite)) != 0)
 		return (error);
 	if (numaltwrite == 0)
 		return (0);
 	savedactualloc = fs->fs_sblockactualloc;
 	savedcsp = fs->fs_csp;
 	fs->fs_csp = NULL;
 	for (i = 0; i < numaltwrite; i++) {
 		fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i)));
 		if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
 		     use_pwrite)) != 0) {
 			fs->fs_sblockactualloc = savedactualloc;
 			fs->fs_csp = savedcsp;
 			return (error);
 		}
 	}
 	fs->fs_sblockactualloc = savedactualloc;
 	fs->fs_csp = savedcsp;
 	return (0);
 }
 
 /*
  * A write function for use by user-level programs using sbput in libufs.
  */
 static int
 use_pwrite(void *devfd, off_t loc, void *buf, int size)
 {
 	int fd;
 
 	fd = *(int *)devfd;
 	if (pwrite(fd, buf, size, loc) != size)
 		return (EIO);
 	return (0);
 }
diff --git a/lib/libufs/type.c b/lib/libufs/type.c
index 653ef8ceeea1..a060f8ec5abf 100644
--- a/lib/libufs/type.c
+++ b/lib/libufs/type.c
@@ -1,204 +1,206 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2002 Juli Mallett.  All rights reserved.
  *
  * This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
  * FreeBSD project.  Redistribution and use in source and binary forms, with
  * or without modification, are permitted provided that the following
  * conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice,
  *    this list of conditions and the following disclaimer.
  * 2. Redistribution in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/disklabel.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include <errno.h>
 #include <fcntl.h>
 #include <fstab.h>
 #include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <libufs.h>
 
 /* Internally, track the 'name' value, it's ours. */
 #define	MINE_NAME	0x01
 /* Track if its fd points to a writable device. */
 #define	MINE_WRITE	0x02
 
 int
 ufs_disk_close(struct uufsd *disk)
 {
 	ERROR(disk, NULL);
 	close(disk->d_fd);
 	disk->d_fd = -1;
 	if (disk->d_inoblock != NULL) {
 		free(disk->d_inoblock);
 		disk->d_inoblock = NULL;
 	}
 	if (disk->d_mine & MINE_NAME) {
 		free((char *)(uintptr_t)disk->d_name);
 		disk->d_name = NULL;
 	}
 	if (disk->d_si != NULL) {
 		free(disk->d_si->si_csp);
 		free(disk->d_si);
 		disk->d_si = NULL;
 	}
 	return (0);
 }
 
 int
 ufs_disk_fillout(struct uufsd *disk, const char *name)
 {
 	if (ufs_disk_fillout_blank(disk, name) == -1) {
 		return (-1);
 	}
 	if (sbread(disk) == -1) {
 		ERROR(disk, "could not read superblock to fill out disk");
 		ufs_disk_close(disk);
 		return (-1);
 	}
 	return (0);
 }
 
 int
 ufs_disk_fillout_blank(struct uufsd *disk, const char *name)
 {
 	struct stat st;
 	struct fstab *fs;
 	struct statfs sfs;
 	const char *oname;
 	char dev[MAXPATHLEN];
 	int fd, ret;
 
 	ERROR(disk, NULL);
 
 	oname = name;
 again:	if ((ret = stat(name, &st)) < 0) {
 		if (*name != '/') {
 			snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name);
 			name = dev;
 			goto again;
 		}
 		/*
 		 * The given object doesn't exist, but don't panic just yet -
 		 * it may be still mount point listed in /etc/fstab, but without
 		 * existing corresponding directory.
 		 */
 		name = oname;
 	}
 	if (ret >= 0 && S_ISREG(st.st_mode)) {
 		/* Possibly a disk image, give it a try.  */
 		;
 	} else if (ret >= 0 && S_ISCHR(st.st_mode)) {
 		/* This is what we need, do nothing. */
 		;
 	} else if ((fs = getfsfile(name)) != NULL) {
 		/*
 		 * The given mount point is listed in /etc/fstab.
 		 * It is possible that someone unmounted file system by hand
 		 * and different file system is mounted on this mount point,
 		 * but we still prefer /etc/fstab entry, because on the other
 		 * hand, there could be /etc/fstab entry for this mount
 		 * point, but file system is not mounted yet (eg. noauto) and
 		 * statfs(2) will point us at different file system.
 		 */
 		name = fs->fs_spec;
 	} else if (ret >= 0 && S_ISDIR(st.st_mode)) {
 		/*
 		 * The mount point is not listed in /etc/fstab, so it may be
 		 * file system mounted by hand.
 		 */
 		if (statfs(name, &sfs) < 0) {
 			ERROR(disk, "could not find special device");
 			return (-1);
 		}
 		strlcpy(dev, sfs.f_mntfromname, sizeof(dev));
 		name = dev;
 	} else {
 		ERROR(disk, "could not find special device");
 		return (-1);
 	}
 	fd = open(name, O_RDONLY);
 	if (fd == -1) {
 		ERROR(disk, "could not open special device");
 		return (-1);
 	}
 
 	disk->d_bsize = 1;
 	disk->d_ccg = 0;
 	disk->d_fd = fd;
 	disk->d_inoblock = NULL;
 	disk->d_inomin = 0;
 	disk->d_inomax = 0;
 	disk->d_lcg = 0;
 	disk->d_mine = 0;
 	disk->d_ufs = 0;
 	disk->d_error = NULL;
 	disk->d_si = NULL;
 
 	if (oname != name) {
 		name = strdup(name);
 		if (name == NULL) {
 			ERROR(disk, "could not allocate memory for disk name");
 			return (-1);
 		}
 		disk->d_mine |= MINE_NAME;
 	}
 	disk->d_name = name;
 
 	return (0);
 }
 
 int
 ufs_disk_write(struct uufsd *disk)
 {
 	int fd;
 
 	ERROR(disk, NULL);
 
 	if (disk->d_mine & MINE_WRITE)
 		return (0);
 
 	fd = open(disk->d_name, O_RDWR);
 	if (fd < 0) {
 		ERROR(disk, "failed to open disk for writing");
 		return (-1);
 	}
 
 	close(disk->d_fd);
 	disk->d_fd = fd;
 	disk->d_mine |= MINE_WRITE;
 
 	return (0);
 }
diff --git a/sbin/dump/main.c b/sbin/dump/main.c
index bbc54d7ab5d7..8752f2c1bea5 100644
--- a/sbin/dump/main.c
+++ b/sbin/dump/main.c
@@ -1,795 +1,797 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1980, 1991, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #ifndef lint
 static const char copyright[] =
 "@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
 	The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/1/95";
 #endif
 static const char rcsid[] =
   "$FreeBSD$";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
 #include <sys/disklabel.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ffs/fs.h>
 
 #include <protocols/dumprestore.h>
 
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <fstab.h>
 #include <libufs.h>
 #include <limits.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <timeconv.h>
 #include <unistd.h>
 
 #include "dump.h"
 #include "pathnames.h"
 
 int	mapsize;	/* size of the state maps */
 char	*usedinomap;	/* map of allocated inodes */
 char	*dumpdirmap;	/* map of directories to be dumped */
 char	*dumpinomap;	/* map of files to be dumped */
 char	*disk;		/* name of the disk file */
 char	*tape;		/* name of the tape file */
 char	*popenout;	/* popen(3) per-"tape" command */
 int	level;		/* dump level of this dump */
 int	uflag;		/* update flag */
 int	diskfd;		/* disk file descriptor */
 int	pipeout;	/* true => output to standard output */
 int	density = 0;	/* density in bytes/0.1" " <- this is for hilit19 */
 long	tapesize;	/* estimated tape size, blocks */
 long	tsize;		/* tape size in 0.1" units */
 int	etapes;		/* estimated number of tapes */
 int	nonodump;	/* if set, do not honor UF_NODUMP user flags */
 int	unlimited;	/* if set, write to end of medium */
 int	cachesize = 0;	/* block cache size (in bytes), defaults to 0 */
 int	rsync_friendly;	/* be friendly with rsync */
 int	notify = 0;	/* notify operator flag */
 int	blockswritten = 0; /* number of blocks written on current tape */
 int	tapeno = 0;	/* current tape number */
 int	ntrec = NTREC;	/* # tape blocks in each tape record */
 long	blocksperfile;	/* number of blocks per output file */
 int	cartridge = 0;	/* Assume non-cartridge tape */
 char	*host = NULL;	/* remote host (if any) */
 time_t	tstart_writing;	/* when started writing the first tape block */
 time_t	tend_writing;	/* after writing the last tape block */
 int	passno;		/* current dump pass number */
 struct	fs *sblock;	/* the file system super block */
 long	dev_bsize = 1;	/* recalculated below */
 int	dev_bshift;	/* log2(dev_bsize) */
 int	tp_bshift;	/* log2(TP_BSIZE) */
 int	snapdump = 0;	/* dumping live filesystem, so use snapshot */
 
 static char *getmntpt(char *, int *);
 static long numarg(const char *, long, long);
 static void obsolete(int *, char **[]);
 static void usage(void) __dead2;
 
 int
 main(int argc, char *argv[])
 {
 	struct stat sb;
 	ino_t ino;
 	int dirty;
 	union dinode *dp;
 	struct fstab *dt;
 	char *map, *mntpt;
 	int ch, mode, mntflags;
 	int i, ret, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1;
 	int just_estimate = 0;
 	ino_t maxino;
 	char *tmsg;
 
 	spcl.c_date = _time_to_time64(time(NULL));
 
 	tsize = 0;	/* Default later, based on 'c' option for cart tapes */
 	dumpdates = _PATH_DUMPDATES;
 	popenout = NULL;
 	tape = NULL;
 	if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
 		quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
 	level = 0;
 	rsync_friendly = 0;
 
 	if (argc < 2)
 		usage();
 
 	obsolete(&argc, &argv);
 	while ((ch = getopt(argc, argv,
 	    "0123456789aB:b:C:cD:d:f:h:LnP:RrSs:T:uWw")) != -1)
 		switch (ch) {
 		/* dump level */
 		case '0': case '1': case '2': case '3': case '4':
 		case '5': case '6': case '7': case '8': case '9':
 			level = 10 * level + ch - '0';
 			break;
 
 		case 'a':		/* `auto-size', Write to EOM. */
 			unlimited = 1;
 			break;
 
 		case 'B':		/* blocks per output file */
 			blocksperfile = numarg("number of blocks per file",
 			    1L, 0L);
 			break;
 
 		case 'b':		/* blocks per tape write */
 			ntrec = numarg("number of blocks per write",
 			    1L, 1000L);
 			break;
 
 		case 'C':
 			cachesize = numarg("cachesize", 0, 0) * 1024 * 1024;
 			break;
 
 		case 'c':		/* Tape is cart. not 9-track */
 			cartridge = 1;
 			break;
 
 		case 'D':
 			dumpdates = optarg;
 			break;
 
 		case 'd':		/* density, in bits per inch */
 			density = numarg("density", 10L, 327670L) / 10;
 			if (density >= 625 && !bflag)
 				ntrec = HIGHDENSITYTREC;
 			break;
 
 		case 'f':		/* output file */
 			if (popenout != NULL)
 				errx(X_STARTUP, "You cannot use the P and f "
 				    "flags together.\n");
 			tape = optarg;
 			break;
 
 		case 'h':
 			honorlevel = numarg("honor level", 0L, 10L);
 			break;
 
 		case 'L':
 			snapdump = 1;
 			break;
 
 		case 'n':		/* notify operators */
 			notify = 1;
 			break;
 
 		case 'P':
 			if (tape != NULL)
 				errx(X_STARTUP, "You cannot use the P and f "
 				    "flags together.\n");
 			popenout = optarg;
 			break;
 
 		case 'r': /* store slightly less data to be friendly to rsync */
 			if (rsync_friendly < 1)
 				rsync_friendly = 1;
 			break;
 
 		case 'R': /* store even less data to be friendlier to rsync */
 			if (rsync_friendly < 2)
 				rsync_friendly = 2;
 			break;
 
 		case 'S':               /* exit after estimating # of tapes */
 			just_estimate = 1;
 			break;
 
 		case 's':		/* tape size, feet */
 			tsize = numarg("tape size", 1L, 0L) * 12 * 10;
 			break;
 
 		case 'T':		/* time of last dump */
 			spcl.c_ddate = unctime(optarg);
 			if (spcl.c_ddate < 0) {
 				(void)fprintf(stderr, "bad time \"%s\"\n",
 				    optarg);
 				exit(X_STARTUP);
 			}
 			Tflag = 1;
 			lastlevel = -1;
 			break;
 
 		case 'u':		/* update /etc/dumpdates */
 			uflag = 1;
 			break;
 
 		case 'W':		/* what to do */
 		case 'w':
 			lastdump(ch);
 			exit(X_FINOK);	/* do nothing else */
 
 		default:
 			usage();
 		}
 	argc -= optind;
 	argv += optind;
 
 	if (argc < 1) {
 		(void)fprintf(stderr, "Must specify disk or file system\n");
 		exit(X_STARTUP);
 	}
 	disk = *argv++;
 	argc--;
 	if (argc >= 1) {
 		(void)fprintf(stderr, "Unknown arguments to dump:");
 		while (argc--)
 			(void)fprintf(stderr, " %s", *argv++);
 		(void)fprintf(stderr, "\n");
 		exit(X_STARTUP);
 	}
 	if (rsync_friendly && (level > 0)) {
 		(void)fprintf(stderr, "%s %s\n", "rsync friendly options",
 		    "can be used only with level 0 dumps.");
 		exit(X_STARTUP);
 	}
 	if (Tflag && uflag) {
 	        (void)fprintf(stderr,
 		    "You cannot use the T and u flags together.\n");
 		exit(X_STARTUP);
 	}
 	if (popenout) {
 		tape = "child pipeline process";
 	} else if (tape == NULL && (tape = getenv("TAPE")) == NULL)
 		tape = _PATH_DEFTAPE;
 	if (strcmp(tape, "-") == 0) {
 		pipeout++;
 		tape = "standard output";
 	}
 
 	if (blocksperfile)
 		blocksperfile = rounddown(blocksperfile, ntrec);
 	else if (!unlimited) {
 		/*
 		 * Determine how to default tape size and density
 		 *
 		 *         	density				tape size
 		 * 9-track	1600 bpi (160 bytes/.1")	2300 ft.
 		 * 9-track	6250 bpi (625 bytes/.1")	2300 ft.
 		 * cartridge	8000 bpi (100 bytes/.1")	1700 ft.
 		 *						(450*4 - slop)
 		 * hilit19 hits again: "
 		 */
 		if (density == 0)
 			density = cartridge ? 100 : 160;
 		if (tsize == 0)
 			tsize = cartridge ? 1700L*120L : 2300L*120L;
 	}
 
 	if (strchr(tape, ':')) {
 		host = tape;
 		tape = strchr(host, ':');
 		*tape++ = '\0';
 #ifdef RDUMP
 		if (strchr(tape, '\n')) {
 		    (void)fprintf(stderr, "invalid characters in tape\n");
 		    exit(X_STARTUP);
 		}
 		if (rmthost(host) == 0)
 			exit(X_STARTUP);
 #else
 		(void)fprintf(stderr, "remote dump not enabled\n");
 		exit(X_STARTUP);
 #endif
 	}
 	(void)setuid(getuid()); /* rmthost() is the only reason to be setuid */
 
 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
 		signal(SIGHUP, sig);
 	if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
 		signal(SIGTRAP, sig);
 	if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
 		signal(SIGFPE, sig);
 	if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
 		signal(SIGBUS, sig);
 	if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
 		signal(SIGSEGV, sig);
 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
 		signal(SIGTERM, sig);
 	if (signal(SIGINT, interrupt) == SIG_IGN)
 		signal(SIGINT, SIG_IGN);
 
 	dump_getfstab();	/* /etc/fstab snarfed */
 	/*
 	 *	disk can be either the full special file name,
 	 *	the suffix of the special file name,
 	 *	the special name missing the leading '/',
 	 *	the file system name with or without the leading '/'.
 	 */
 	dt = fstabsearch(disk);
 	if (dt != NULL) {
 		disk = rawname(dt->fs_spec);
  		if (disk == NULL)
  			errx(X_STARTUP, "%s: unknown file system", dt->fs_spec);
 		(void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
 		(void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
 	} else {
 		(void)strncpy(spcl.c_dev, disk, NAMELEN);
 		(void)strncpy(spcl.c_filesys, "an unlisted file system",
 		    NAMELEN);
 	}
 	spcl.c_dev[NAMELEN-1]='\0';
 	spcl.c_filesys[NAMELEN-1]='\0';
 
 	if ((mntpt = getmntpt(disk, &mntflags)) != NULL) {
 		if (mntflags & MNT_RDONLY) {
 			if (snapdump != 0) {
 				msg("WARNING: %s\n",
 				    "-L ignored for read-only filesystem.");
 				snapdump = 0;
 			}
 		} else if (snapdump == 0) {
 			msg("WARNING: %s\n",
 			    "should use -L when dumping live read-write "
 			    "filesystems!");
 		} else {
 			char snapname[BUFSIZ], snapcmd[BUFSIZ];
 
 			snprintf(snapname, sizeof snapname, "%s/.snap", mntpt);
 			if ((stat(snapname, &sb) < 0) || !S_ISDIR(sb.st_mode)) {
 				msg("WARNING: %s %s\n",
 				    "-L requested but snapshot location",
 				    snapname);
 				msg("         %s: %s\n",
 				    "is not a directory",
 				    "dump downgraded, -L ignored");
 				snapdump = 0;
 			} else {
 				snprintf(snapname, sizeof snapname,
 				    "%s/.snap/dump_snapshot", mntpt);
 				snprintf(snapcmd, sizeof snapcmd, "%s %s %s",
 				    _PATH_MKSNAP_FFS, mntpt, snapname);
 				unlink(snapname);
 				if (system(snapcmd) != 0)
 					errx(X_STARTUP, "Cannot create %s: %s\n",
 					    snapname, strerror(errno));
 				if ((diskfd = open(snapname, O_RDONLY)) < 0) {
 					unlink(snapname);
 					errx(X_STARTUP, "Cannot open %s: %s\n",
 					    snapname, strerror(errno));
 				}
 				unlink(snapname);
 				if (fstat(diskfd, &sb) != 0)
 					err(X_STARTUP, "%s: stat", snapname);
 				spcl.c_date = _time_to_time64(sb.st_mtime);
 			}
 		}
 	} else if (snapdump != 0) {
 		msg("WARNING: Cannot use -L on an unmounted filesystem.\n");
 		snapdump = 0;
 	}
 	if (snapdump == 0) {
 		if ((diskfd = open(disk, O_RDONLY)) < 0)
 			err(X_STARTUP, "Cannot open %s", disk);
 		if (fstat(diskfd, &sb) != 0)
 			err(X_STARTUP, "%s: stat", disk);
 		if (S_ISDIR(sb.st_mode))
 			errx(X_STARTUP, "%s: unknown file system", disk);
 	}
 
 	(void)strcpy(spcl.c_label, "none");
 	(void)gethostname(spcl.c_host, NAMELEN);
 	spcl.c_level = level;
 	spcl.c_type = TS_TAPE;
 	if (rsync_friendly) {
 		/* don't store real dump times */
 		spcl.c_date = 0;
 		spcl.c_ddate = 0;
 	}
 	if (spcl.c_date == 0) {
 		tmsg = "the epoch\n";
 	} else {
 		time_t t = _time64_to_time(spcl.c_date);
 		tmsg = ctime(&t);
 	}
 	msg("Date of this level %d dump: %s", level, tmsg);
 
 	if (!Tflag && (!rsync_friendly))
 	        getdumptime();		/* /etc/dumpdates snarfed */
 	if (spcl.c_ddate == 0) {
 		tmsg = "the epoch\n";
 	} else {
 		time_t t = _time64_to_time(spcl.c_ddate);
 		tmsg = ctime(&t);
 	}
 	if (lastlevel < 0)
 		msg("Date of last (level unknown) dump: %s", tmsg);
 	else
 		msg("Date of last level %d dump: %s", lastlevel, tmsg);
 
 	msg("Dumping %s%s ", snapdump ? "snapshot of ": "", disk);
 	if (dt != NULL)
 		msgtail("(%s) ", dt->fs_file);
 	if (host)
 		msgtail("to %s on host %s\n", tape, host);
 	else
 		msgtail("to %s\n", tape);
 
 	sync();
 	if ((ret = sbget(diskfd, &sblock, STDSB)) != 0) {
 		switch (ret) {
 		case ENOENT:
 			warn("Cannot find file system superblock");
 			return (1);
 		default:
 			warn("Unable to read file system superblock");
 			return (1);
 		}
 	}
 	dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
 	dev_bshift = ffs(dev_bsize) - 1;
 	if (dev_bsize != (1 << dev_bshift))
 		quit("dev_bsize (%ld) is not a power of 2", dev_bsize);
 	tp_bshift = ffs(TP_BSIZE) - 1;
 	if (TP_BSIZE != (1 << tp_bshift))
 		quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
 	maxino = sblock->fs_ipg * sblock->fs_ncg;
 	mapsize = roundup(howmany(maxino, CHAR_BIT), TP_BSIZE);
 	usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
 	dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
 	dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
 	tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
 
 	nonodump = spcl.c_level < honorlevel;
 
 	passno = 1;
 	setproctitle("%s: pass 1: regular files", disk);
 	msg("mapping (Pass I) [regular files]\n");
 	anydirskipped = mapfiles(maxino, &tapesize);
 
 	passno = 2;
 	setproctitle("%s: pass 2: directories", disk);
 	msg("mapping (Pass II) [directories]\n");
 	while (anydirskipped) {
 		anydirskipped = mapdirs(maxino, &tapesize);
 	}
 
 	if (pipeout || unlimited) {
 		tapesize += 10;	/* 10 trailer blocks */
 		msg("estimated %ld tape blocks.\n", tapesize);
 	} else {
 		double fetapes;
 
 		if (blocksperfile)
 			fetapes = (double) tapesize / blocksperfile;
 		else if (cartridge) {
 			/* Estimate number of tapes, assuming streaming stops at
 			   the end of each block written, and not in mid-block.
 			   Assume no erroneous blocks; this can be compensated
 			   for with an artificially low tape size. */
 			fetapes =
 			(	  (double) tapesize	/* blocks */
 				* TP_BSIZE	/* bytes/block */
 				* (1.0/density)	/* 0.1" / byte " */
 			  +
 				  (double) tapesize	/* blocks */
 				* (1.0/ntrec)	/* streaming-stops per block */
 				* 15.48		/* 0.1" / streaming-stop " */
 			) * (1.0 / tsize );	/* tape / 0.1" " */
 		} else {
 			/* Estimate number of tapes, for old fashioned 9-track
 			   tape */
 			int tenthsperirg = (density == 625) ? 3 : 7;
 			fetapes =
 			(	  (double) tapesize	/* blocks */
 				* TP_BSIZE	/* bytes / block */
 				* (1.0/density)	/* 0.1" / byte " */
 			  +
 				  (double) tapesize	/* blocks */
 				* (1.0/ntrec)	/* IRG's / block */
 				* tenthsperirg	/* 0.1" / IRG " */
 			) * (1.0 / tsize );	/* tape / 0.1" " */
 		}
 		etapes = fetapes;		/* truncating assignment */
 		etapes++;
 		/* count the dumped inodes map on each additional tape */
 		tapesize += (etapes - 1) *
 			(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
 		tapesize += etapes + 10;	/* headers + 10 trailer blks */
 		msg("estimated %ld tape blocks on %3.2f tape(s).\n",
 		    tapesize, fetapes);
 	}
 
         /*
          * If the user only wants an estimate of the number of
          * tapes, exit now.
          */
         if (just_estimate)
                 exit(0);
 
 	/*
 	 * Allocate tape buffer.
 	 */
 	if (!alloctape())
 		quit(
 	"can't allocate tape buffers - try a smaller blocking factor.\n");
 
 	startnewtape(1);
 	(void)time((time_t *)&(tstart_writing));
 	dumpmap(usedinomap, TS_CLRI, maxino - 1);
 
 	passno = 3;
 	setproctitle("%s: pass 3: directories", disk);
 	msg("dumping (Pass III) [directories]\n");
 	dirty = 0;		/* XXX just to get gcc to shut up */
 	for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
 		if (((ino - 1) % CHAR_BIT) == 0)	/* map is offset by 1 */
 			dirty = *map++;
 		else
 			dirty >>= 1;
 		if ((dirty & 1) == 0)
 			continue;
 		/*
 		 * Skip directory inodes deleted and maybe reallocated
 		 */
 		dp = getino(ino, &mode);
 		if (mode != IFDIR)
 			continue;
 		(void)dumpino(dp, ino);
 	}
 
 	passno = 4;
 	setproctitle("%s: pass 4: regular files", disk);
 	msg("dumping (Pass IV) [regular files]\n");
 	for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
 		if (((ino - 1) % CHAR_BIT) == 0)	/* map is offset by 1 */
 			dirty = *map++;
 		else
 			dirty >>= 1;
 		if ((dirty & 1) == 0)
 			continue;
 		/*
 		 * Skip inodes deleted and reallocated as directories.
 		 */
 		dp = getino(ino, &mode);
 		if (mode == IFDIR)
 			continue;
 		(void)dumpino(dp, ino);
 	}
 
 	(void)time((time_t *)&(tend_writing));
 	spcl.c_type = TS_END;
 	for (i = 0; i < ntrec; i++)
 		writeheader(maxino - 1);
 	if (pipeout)
 		msg("DUMP: %jd tape blocks\n", (intmax_t)spcl.c_tapea);
 	else
 		msg("DUMP: %jd tape blocks on %d volume%s\n",
 		    (intmax_t)spcl.c_tapea, spcl.c_volume,
 		    (spcl.c_volume == 1) ? "" : "s");
 
 	/* report dump performance, avoid division through zero */
 	if (tend_writing - tstart_writing == 0)
 		msg("finished in less than a second\n");
 	else
 		msg("finished in %jd seconds, throughput %jd KBytes/sec\n",
 		    (intmax_t)tend_writing - tstart_writing, 
 		    (intmax_t)(spcl.c_tapea / 
 		    (tend_writing - tstart_writing)));
 
 	putdumptime();
 	trewind();
 	broadcast("DUMP IS DONE!\a\a\n");
 	msg("DUMP IS DONE\n");
 	Exit(X_FINOK);
 	/* NOTREACHED */
 }
 
 static void
 usage(void)
 {
 	fprintf(stderr,
 		"usage: dump [-0123456789acLnSu] [-B records] [-b blocksize] [-C cachesize]\n"
 		"            [-D dumpdates] [-d density] [-f file | -P pipecommand] [-h level]\n"
 		"            [-s feet] [-T date] filesystem\n"
 		"       dump -W | -w\n");
 	exit(X_STARTUP);
 }
 
 /*
  * Check to see if a disk is currently mounted.
  */
 static char *
 getmntpt(char *name, int *mntflagsp)
 {
 	long mntsize, i;
 	struct statfs *mntbuf;
 
 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
 	for (i = 0; i < mntsize; i++) {
 		if (!strcmp(mntbuf[i].f_mntfromname, name)) {
 			*mntflagsp = mntbuf[i].f_flags;
 			return (mntbuf[i].f_mntonname);
 		}
 	}
 	return (0);
 }
 
 /*
  * Pick up a numeric argument.  It must be nonnegative and in the given
  * range (except that a vmax of 0 means unlimited).
  */
 static long
 numarg(const char *meaning, long vmin, long vmax)
 {
 	char *p;
 	long val;
 
 	val = strtol(optarg, &p, 10);
 	if (*p)
 		errx(1, "illegal %s -- %s", meaning, optarg);
 	if (val < vmin || (vmax && val > vmax))
 		errx(1, "%s must be between %ld and %ld", meaning, vmin, vmax);
 	return (val);
 }
 
 void
 sig(int signo)
 {
 	switch(signo) {
 	case SIGALRM:
 	case SIGBUS:
 	case SIGFPE:
 	case SIGHUP:
 	case SIGTERM:
 	case SIGTRAP:
 		if (pipeout)
 			quit("Signal on pipe: cannot recover\n");
 		msg("Rewriting attempted as response to unknown signal.\n");
 		(void)fflush(stderr);
 		(void)fflush(stdout);
 		close_rewind();
 		exit(X_REWRITE);
 		/* NOTREACHED */
 	case SIGSEGV:
 		msg("SIGSEGV: ABORTING!\n");
 		(void)signal(SIGSEGV, SIG_DFL);
 		(void)kill(0, SIGSEGV);
 		/* NOTREACHED */
 	}
 }
 
 char *
 rawname(char *cp)
 {
 	struct stat sb;
 
 	/*
 	 * Ensure that the device passed in is a raw device.
 	 */
 	if (stat(cp, &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFCHR)
 		return (cp);
 
 	/*
 	 * Since there's only one device type now, we can't construct any
 	 * better name, so we have to return NULL.
 	 */
 	return (NULL);
 }
 
 /*
  * obsolete --
  *	Change set of key letters and ordered arguments into something
  *	getopt(3) will like.
  */
 static void
 obsolete(int *argcp, char **argvp[])
 {
 	int argc, flags;
 	char *ap, **argv, *flagsp, **nargv, *p;
 
 	/* Setup. */
 	argv = *argvp;
 	argc = *argcp;
 
 	/*
 	 * Return if no arguments or first argument has leading
 	 * dash or slash.
 	 */
 	ap = argv[1];
 	if (argc == 1 || *ap == '-' || *ap == '/')
 		return;
 
 	/* Allocate space for new arguments. */
 	if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
 	    (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
 		err(1, NULL);
 
 	*nargv++ = *argv;
 	argv += 2;
 
 	for (flags = 0; *ap; ++ap) {
 		switch (*ap) {
 		case 'B':
 		case 'b':
 		case 'd':
 		case 'f':
 		case 'D':
 		case 'C':
 		case 'h':
 		case 's':
 		case 'T':
 			if (*argv == NULL) {
 				warnx("option requires an argument -- %c", *ap);
 				usage();
 			}
 			if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
 				err(1, NULL);
 			nargv[0][0] = '-';
 			nargv[0][1] = *ap;
 			(void)strcpy(&nargv[0][2], *argv);
 			++argv;
 			++nargv;
 			break;
 		default:
 			if (!flags) {
 				*p++ = '-';
 				flags = 1;
 			}
 			*p++ = *ap;
 			break;
 		}
 	}
 
 	/* Terminate flags. */
 	if (flags) {
 		*p = '\0';
 		*nargv++ = flagsp;
 	} else
 		free(flagsp);
 
 	/* Copy remaining arguments. */
 	while ((*nargv++ = *argv++));
 
 	/* Update argument count. */
 	*argcp = nargv - *argvp - 1;
 }
diff --git a/sbin/ffsinfo/ffsinfo.c b/sbin/ffsinfo/ffsinfo.c
index 9bd3210986a9..33ec5f175cbd 100644
--- a/sbin/ffsinfo/ffsinfo.c
+++ b/sbin/ffsinfo/ffsinfo.c
@@ -1,649 +1,651 @@
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz
  * Copyright (c) 1980, 1989, 1993 The Regents of the University of California.
  * All rights reserved.
  * 
  * This code is derived from software contributed to Berkeley by
  * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt.
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgment:
  *      This product includes software developed by the University of
  *      California, Berkeley and its contributors, as well as Christoph
  *      Herrmann and Thomas-Henning von Kamptz.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  * 
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $TSHeader: src/sbin/ffsinfo/ffsinfo.c,v 1.4 2000/12/12 19:30:55 tomsoft Exp $
  *
  */
 
 #ifndef lint
 static const char copyright[] =
 "@(#) Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz\n\
 Copyright (c) 1980, 1989, 1993 The Regents of the University of California.\n\
 All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 static const char rcsid[] =
   "$FreeBSD$";
 #endif /* not lint */
 
 /* ********************************************************** INCLUDES ***** */
 #include <sys/param.h>
 #include <sys/disklabel.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libufs.h>
 #include <paths.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "debug.h"
 
 /* *********************************************************** GLOBALS ***** */
 #ifdef FS_DEBUG
 int	_dbg_lvl_ = (DL_INFO); /* DL_TRC */
 #endif /* FS_DEBUG */
 
 static struct uufsd disk;
 
 #define sblock disk.d_fs
 #define acg    disk.d_cg
 
 static union {
 	struct fs fs;
 	char pad[SBLOCKSIZE];
 } fsun;
 
 #define osblock fsun.fs
 
 static char	i1blk[MAXBSIZE];
 static char	i2blk[MAXBSIZE];
 static char	i3blk[MAXBSIZE];
 
 static struct csum	*fscs;
 
 /* ******************************************************** PROTOTYPES ***** */
 static void	usage(void);
 static void	dump_whole_ufs1_inode(ino_t, int);
 static void	dump_whole_ufs2_inode(ino_t, int);
 
 #define DUMP_WHOLE_INODE(A,B) \
 	( disk.d_ufs == 1 \
 		? dump_whole_ufs1_inode((A),(B)) : dump_whole_ufs2_inode((A),(B)) )
 
 /* ************************************************************** main ***** */
 /*
  * ffsinfo(8) is a tool to dump all metadata of a file system. It helps to find
  * errors is the file system much easier. You can run ffsinfo before and  after
  * an  fsck(8),  and compare the two ascii dumps easy with diff, and  you  see
  * directly where the problem is. You can control how much detail you want  to
  * see  with some command line arguments. You can also easy check  the  status
  * of  a file system, like is there is enough space for growing  a  file system,
  * or  how  many active snapshots do we have. It provides much  more  detailed
  * information  then dumpfs. Snapshots, as they are very new, are  not  really
  * supported.  They  are just mentioned currently, but it is  planned  to  run
  * also over active snapshots, to even get that output.
  */
 int
 main(int argc, char **argv)
 {
 	DBG_FUNC("main")
 	char	*device, *special;
 	int	ch;
 	size_t	len;
 	struct stat	st;
 	struct csum	*dbg_csp;
 	int	dbg_csc;
 	char	dbg_line[80];
 	int	cylno,i;
 	int	cfg_cg, cfg_in, cfg_lv;
 	int	cg_start, cg_stop;
 	ino_t	in;
 	char	*out_file;
 
 	DBG_ENTER;
 
 	cfg_lv = 0xff;
 	cfg_in = -2;
 	cfg_cg = -2;
 	out_file = strdup("-");
 
 	while ((ch = getopt(argc, argv, "g:i:l:o:")) != -1) {
 		switch (ch) {
 		case 'g':
 			cfg_cg = strtol(optarg, NULL, 0);
 			if (errno == EINVAL || errno == ERANGE)
 				err(1, "%s", optarg);
 			if (cfg_cg < -1)
 				usage();
 			break;
 		case 'i':
 			cfg_in = strtol(optarg, NULL, 0);
 			if (errno == EINVAL || errno == ERANGE)
 				err(1, "%s", optarg);
 			if (cfg_in < 0)
 				usage();
 			break; 
 		case 'l':
 			cfg_lv = strtol(optarg, NULL, 0);
 			if (errno == EINVAL||errno == ERANGE)
 				err(1, "%s", optarg);
 			if (cfg_lv < 0x1 || cfg_lv > 0x3ff)
 				usage();
 			break;
 		case 'o':
 			free(out_file);
 			out_file = strdup(optarg);
 			if (out_file == NULL)
 				errx(1, "strdup failed");
 			break;
 		case '?':
 			/* FALLTHROUGH */
 		default:
 			usage();
 		}
 	}
 	argc -= optind;
 	argv += optind;
 
 	if (argc != 1)
 		usage();
 	device = *argv;
 
 	/*
 	 * Now we try to guess the (raw)device name.
 	 */
 	if (0 == strrchr(device, '/') && stat(device, &st) == -1) {
 		/*-
 		 * No path prefix was given, so try in this order:
 		 *     /dev/r%s
 		 *     /dev/%s
 		 *     /dev/vinum/r%s
 		 *     /dev/vinum/%s.
 		 * 
 		 * FreeBSD now doesn't distinguish between raw and  block
 		 * devices any longer, but it should still work this way.
 		 */
 		len = strlen(device) + strlen(_PATH_DEV) + 2 + strlen("vinum/");
 		special = (char *)malloc(len);
 		if (special == NULL)
 			errx(1, "malloc failed");
 		snprintf(special, len, "%sr%s", _PATH_DEV, device);
 		if (stat(special, &st) == -1) {
 			snprintf(special, len, "%s%s", _PATH_DEV, device);
 			if (stat(special, &st) == -1) {
 				snprintf(special, len, "%svinum/r%s",
 				    _PATH_DEV, device);
 				if (stat(special, &st) == -1)
 					/* For now this is the 'last resort' */
 					snprintf(special, len, "%svinum/%s",
 					    _PATH_DEV, device);
 			}
 		}
 		device = special;
 	}
 
 	if (ufs_disk_fillout(&disk, device) == -1)
 		err(1, "ufs_disk_fillout(%s) failed: %s", device, disk.d_error);
 
 	DBG_OPEN(out_file);	/* already here we need a superblock */
 
 	if (cfg_lv & 0x001)
 		DBG_DUMP_FS(&sblock, "primary sblock");
 
 	/* Determine here what cylinder groups to dump */
 	if (cfg_cg==-2) {
 		cg_start = 0;
 		cg_stop = sblock.fs_ncg;
 	} else if (cfg_cg == -1) {
 		cg_start = sblock.fs_ncg - 1;
 		cg_stop = sblock.fs_ncg;
 	} else if (cfg_cg < sblock.fs_ncg) {
 		cg_start = cfg_cg;
 		cg_stop = cfg_cg + 1;
 	} else {
 		cg_start = sblock.fs_ncg;
 		cg_stop = sblock.fs_ncg;
 	}
 
 	if (cfg_lv & 0x004) {
 		fscs = (struct csum *)calloc((size_t)1,
 		    (size_t)sblock.fs_cssize);
 		if (fscs == NULL)
 			errx(1, "calloc failed");
 
 		/* get the cylinder summary into the memory ... */
 		for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) {
 			if (bread(&disk, fsbtodb(&sblock,
 			    sblock.fs_csaddr + numfrags(&sblock, i)), 
 			    (void *)(((char *)fscs)+i), 
 			    (size_t)(sblock.fs_cssize-i < sblock.fs_bsize ?
 			    sblock.fs_cssize - i : sblock.fs_bsize)) == -1)
 				err(1, "bread: %s", disk.d_error);
 		}
 
 		dbg_csp = fscs;
 		/* ... and dump it */
 		for (dbg_csc = 0; dbg_csc < sblock.fs_ncg; dbg_csc++) {
 			snprintf(dbg_line, sizeof(dbg_line),
 			    "%d. csum in fscs", dbg_csc);
 			DBG_DUMP_CSUM(&sblock,
 			    dbg_line,
 			    dbg_csp++);
 		}
 	}
 
 	if (cfg_lv & 0xf8) {
 		/* for each requested cylinder group ... */
 		for (cylno = cg_start; cylno < cg_stop; cylno++) {
 			snprintf(dbg_line, sizeof(dbg_line), "cgr %d", cylno);
 			if (cfg_lv & 0x002) {
 				/* dump the superblock copies */
 				if (bread(&disk, fsbtodb(&sblock,
 				    cgsblock(&sblock, cylno)), 
 				    (void *)&osblock, SBLOCKSIZE) == -1)
 					err(1, "bread: %s", disk.d_error);
 				DBG_DUMP_FS(&osblock, dbg_line);
 			}
 
 			/*
 			 * Read the cylinder group and dump whatever was
 			 * requested.
 			 */
 			if (bread(&disk, fsbtodb(&sblock,
 			    cgtod(&sblock, cylno)), (void *)&acg,
 			    (size_t)sblock.fs_cgsize) == -1)
 				err(1, "bread: %s", disk.d_error);
 
 			if (cfg_lv & 0x008)
 				DBG_DUMP_CG(&sblock, dbg_line, &acg);
 			if (cfg_lv & 0x010)
 				DBG_DUMP_INMAP(&sblock, dbg_line, &acg);
 			if (cfg_lv & 0x020)
 				DBG_DUMP_FRMAP(&sblock, dbg_line, &acg);
 			if (cfg_lv & 0x040) {
 				DBG_DUMP_CLMAP(&sblock, dbg_line, &acg);
 				DBG_DUMP_CLSUM(&sblock, dbg_line, &acg);
 			}
 	#ifdef NOT_CURRENTLY
 			/*
 			 * See the comment in sbin/growfs/debug.c for why this
 			 * is currently disabled, and what needs to be done to
 			 * re-enable it.
 			 */
 			if (disk.d_ufs == 1 && cfg_lv & 0x080)
 				DBG_DUMP_SPTBL(&sblock, dbg_line, &acg);
 	#endif
 		}
 	}
 
 	if (cfg_lv & 0x300) {
 		/* Dump the requested inode(s) */
 		if (cfg_in != -2)
 			DUMP_WHOLE_INODE((ino_t)cfg_in, cfg_lv);
 		else {
 			for (in = cg_start * sblock.fs_ipg;
 			    in < (ino_t)cg_stop * sblock.fs_ipg; 
 			    in++)
 				DUMP_WHOLE_INODE(in, cfg_lv);
 		}
 	}
 
 	DBG_CLOSE;
 	DBG_LEAVE;
 
 	return 0;
 }
 
 /* ********************************************** dump_whole_ufs1_inode ***** */
 /*
  * Here we dump a list of all blocks allocated by this inode. We follow
  * all indirect blocks.
  */
 void
 dump_whole_ufs1_inode(ino_t inode, int level)
 {
 	DBG_FUNC("dump_whole_ufs1_inode")
 	union dinodep dp;
 	int	rb;
 	unsigned int	ind2ctr, ind3ctr;
 	ufs1_daddr_t	*ind2ptr, *ind3ptr;
 	char	comment[80];
 	
 	DBG_ENTER;
 
 	/*
 	 * Read the inode from disk/cache.
 	 */
 	if (getinode(&disk, &dp, inode) == -1)
 		err(1, "getinode: %s", disk.d_error);
 
 	if (dp.dp1->di_nlink == 0) {
 		DBG_LEAVE;
 		return;	/* inode not in use */
 	}
 
 	/*
 	 * Dump the main inode structure.
 	 */
 	snprintf(comment, sizeof(comment), "Inode 0x%08jx", (uintmax_t)inode);
 	if (level & 0x100) {
 		DBG_DUMP_INO(&sblock,
 		    comment,
 		    dp.dp1);
 	}
 
 	if (!(level & 0x200)) {
 		DBG_LEAVE;
 		return;
 	}
 
 	/*
 	 * Ok, now prepare for dumping all direct and indirect pointers.
 	 */
 	rb = howmany(dp.dp1->di_size, sblock.fs_bsize) - UFS_NDADDR;
 	if (rb > 0) {
 		/*
 		 * Dump single indirect block.
 		 */
 		if (bread(&disk, fsbtodb(&sblock, dp.dp1->di_ib[0]),
 		    (void *)&i1blk, (size_t)sblock.fs_bsize) == -1) {
 			err(1, "bread: %s", disk.d_error);
 		}
 		snprintf(comment, sizeof(comment), "Inode 0x%08jx: indirect 0",
 		    (uintmax_t)inode);
 		DBG_DUMP_IBLK(&sblock,
 		    comment,
 		    i1blk,
 		    (size_t)rb);
 		rb -= howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t));
 	}
 	if (rb > 0) {
 		/*
 		 * Dump double indirect blocks.
 		 */
 		if (bread(&disk, fsbtodb(&sblock, dp.dp1->di_ib[1]),
 		    (void *)&i2blk, (size_t)sblock.fs_bsize) == -1) {
 			err(1, "bread: %s", disk.d_error);
 		}
 		snprintf(comment, sizeof(comment), "Inode 0x%08jx: indirect 1",
 		    (uintmax_t)inode);
 		DBG_DUMP_IBLK(&sblock,
 		    comment,
 		    i2blk,
 		    howmany(rb, howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t))));
 		for (ind2ctr = 0; ((ind2ctr < howmany(sblock.fs_bsize,
 			sizeof(ufs1_daddr_t))) && (rb > 0)); ind2ctr++) {
 			ind2ptr = &((ufs1_daddr_t *)(void *)&i2blk)[ind2ctr];
 
 			if (bread(&disk, fsbtodb(&sblock, *ind2ptr),
 			    (void *)&i1blk, (size_t)sblock.fs_bsize) == -1) {
 				err(1, "bread: %s", disk.d_error);
 			}
 			snprintf(comment, sizeof(comment),
 			    "Inode 0x%08jx: indirect 1->%d", (uintmax_t)inode,
 			    ind2ctr);
 			DBG_DUMP_IBLK(&sblock,
 			    comment,
 			    i1blk,
 			    (size_t)rb);
 			rb -= howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t));
 		}
 	}
 	if (rb > 0) {
 		/*
 		 * Dump triple indirect blocks.
 		 */
 		if (bread(&disk, fsbtodb(&sblock, dp.dp1->di_ib[2]),
 		    (void *)&i3blk, (size_t)sblock.fs_bsize) == -1) {
 			err(1, "bread: %s", disk.d_error);
 		}
 		snprintf(comment, sizeof(comment), "Inode 0x%08jx: indirect 2",
 		    (uintmax_t)inode);
 #define SQUARE(a) ((a)*(a))
 		DBG_DUMP_IBLK(&sblock,
 		    comment,
 		    i3blk,
 		    howmany(rb,
 		      SQUARE(howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t)))));
 #undef SQUARE
 		for (ind3ctr = 0; ((ind3ctr < howmany(sblock.fs_bsize,
 			sizeof(ufs1_daddr_t))) && (rb > 0)); ind3ctr++) {
 			ind3ptr = &((ufs1_daddr_t *)(void *)&i3blk)[ind3ctr];
 
 			if (bread(&disk, fsbtodb(&sblock, *ind3ptr),
 			    (void *)&i2blk, (size_t)sblock.fs_bsize) == -1) {
 				err(1, "bread: %s", disk.d_error);
 			}
 			snprintf(comment, sizeof(comment),
 			    "Inode 0x%08jx: indirect 2->%d", (uintmax_t)inode,
 			    ind3ctr);
 			DBG_DUMP_IBLK(&sblock,
 			    comment,
 			    i2blk,
 			    howmany(rb,
 			      howmany(sblock.fs_bsize, sizeof(ufs1_daddr_t))));
 			for (ind2ctr = 0; ((ind2ctr < howmany(sblock.fs_bsize,
 			     sizeof(ufs1_daddr_t))) && (rb > 0)); ind2ctr++) {
 				ind2ptr=&((ufs1_daddr_t *)(void *)&i2blk)
 				    [ind2ctr];
 				if (bread(&disk, fsbtodb(&sblock, *ind2ptr),
 				    (void *)&i1blk, (size_t)sblock.fs_bsize)
 				    == -1) {
 					err(1, "bread: %s", disk.d_error);
 				}
 				snprintf(comment, sizeof(comment),
 				    "Inode 0x%08jx: indirect 2->%d->%d",
 				    (uintmax_t)inode, ind3ctr, ind3ctr);
 				DBG_DUMP_IBLK(&sblock,
 				    comment,
 				    i1blk,
 				    (size_t)rb);
 				rb -= howmany(sblock.fs_bsize,
 				    sizeof(ufs1_daddr_t));
 			}
 		}
 	}
 
 	DBG_LEAVE;
 	return;
 }
 
 /* ********************************************** dump_whole_ufs2_inode ***** */
 /*
  * Here we dump a list of all blocks allocated by this inode. We follow
  * all indirect blocks.
  */
 void
 dump_whole_ufs2_inode(ino_t inode, int level)
 {
 	DBG_FUNC("dump_whole_ufs2_inode")
 	union dinodep dp;
 	int	rb;
 	unsigned int	ind2ctr, ind3ctr;
 	ufs2_daddr_t	*ind2ptr, *ind3ptr;
 	char	comment[80];
 	
 	DBG_ENTER;
 
 	/*
 	 * Read the inode from disk/cache.
 	 */
 	if (getinode(&disk, &dp, inode) == -1)
 		err(1, "getinode: %s", disk.d_error);
 
 	if (dp.dp2->di_nlink == 0) {
 		DBG_LEAVE;
 		return;	/* inode not in use */
 	}
 
 	/*
 	 * Dump the main inode structure.
 	 */
 	snprintf(comment, sizeof(comment), "Inode 0x%08jx", (uintmax_t)inode);
 	if (level & 0x100) {
 		DBG_DUMP_INO(&sblock, comment, dp.dp2);
 	}
 
 	if (!(level & 0x200)) {
 		DBG_LEAVE;
 		return;
 	}
 
 	/*
 	 * Ok, now prepare for dumping all direct and indirect pointers.
 	 */
 	rb = howmany(dp.dp2->di_size, sblock.fs_bsize) - UFS_NDADDR;
 	if (rb > 0) {
 		/*
 		 * Dump single indirect block.
 		 */
 		if (bread(&disk, fsbtodb(&sblock, dp.dp2->di_ib[0]),
 		    (void *)&i1blk, (size_t)sblock.fs_bsize) == -1) {
 			err(1, "bread: %s", disk.d_error);
 		}
 		snprintf(comment, sizeof(comment), "Inode 0x%08jx: indirect 0",
 		    (uintmax_t)inode);
 		DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb);
 		rb -= howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t));
 	}
 	if (rb > 0) {
 		/*
 		 * Dump double indirect blocks.
 		 */
 		if (bread(&disk, fsbtodb(&sblock, dp.dp2->di_ib[1]),
 		    (void *)&i2blk, (size_t)sblock.fs_bsize) == -1) {
 			err(1, "bread: %s", disk.d_error);
 		}
 		snprintf(comment, sizeof(comment), "Inode 0x%08jx: indirect 1",
 		    (uintmax_t)inode);
 		DBG_DUMP_IBLK(&sblock,
 			comment,
 			i2blk,
 			howmany(rb, howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t))));
 		for (ind2ctr = 0; ((ind2ctr < howmany(sblock.fs_bsize,
 			sizeof(ufs2_daddr_t))) && (rb>0)); ind2ctr++) {
 			ind2ptr = &((ufs2_daddr_t *)(void *)&i2blk)[ind2ctr];
 
 			if (bread(&disk, fsbtodb(&sblock, *ind2ptr),
 			    (void *)&i1blk, (size_t)sblock.fs_bsize) == -1) {
 				err(1, "bread: %s", disk.d_error);
 			}
 			snprintf(comment, sizeof(comment),
 				"Inode 0x%08jx: indirect 1->%d",
 				(uintmax_t)inode, ind2ctr);
 			DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb);
 			rb -= howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t));
 		}
 	}
 	if (rb > 0) {
 		/*
 		 * Dump triple indirect blocks.
 		 */
 		if (bread(&disk, fsbtodb(&sblock, dp.dp2->di_ib[2]),
 		    (void *)&i3blk, (size_t)sblock.fs_bsize) == -1) {
 			err(1, "bread: %s", disk.d_error);
 		}
 		snprintf(comment, sizeof(comment), "Inode 0x%08jx: indirect 2",
 		    (uintmax_t)inode);
 #define SQUARE(a) ((a)*(a))
 		DBG_DUMP_IBLK(&sblock,
 			comment,
 			i3blk,
 			howmany(rb,
 				SQUARE(howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t)))));
 #undef SQUARE
 		for (ind3ctr = 0; ((ind3ctr < howmany(sblock.fs_bsize,
 			sizeof(ufs2_daddr_t))) && (rb > 0)); ind3ctr++) {
 			ind3ptr = &((ufs2_daddr_t *)(void *)&i3blk)[ind3ctr];
 
 			if (bread(&disk, fsbtodb(&sblock, *ind3ptr),
 			    (void *)&i2blk, (size_t)sblock.fs_bsize) == -1) {
 				err(1, "bread: %s", disk.d_error);
 			}
 			snprintf(comment, sizeof(comment),
 				"Inode 0x%08jx: indirect 2->%d",
 				(uintmax_t)inode, ind3ctr);
 			DBG_DUMP_IBLK(&sblock,
 				comment,
 				i2blk,
 				howmany(rb,
 					howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t))));
 			for (ind2ctr = 0; ((ind2ctr < howmany(sblock.fs_bsize,
 				sizeof(ufs2_daddr_t))) && (rb > 0)); ind2ctr++) {
 				ind2ptr = &((ufs2_daddr_t *)(void *)&i2blk) [ind2ctr];
 				if (bread(&disk, fsbtodb(&sblock, *ind2ptr),
 				    (void *)&i1blk, (size_t)sblock.fs_bsize)
 				    == -1) {
 					err(1, "bread: %s", disk.d_error);
 				}
 				snprintf(comment, sizeof(comment),
 					"Inode 0x%08jx: indirect 2->%d->%d",
 					(uintmax_t)inode, ind3ctr, ind3ctr);
 				DBG_DUMP_IBLK(&sblock, comment, i1blk, (size_t)rb);
 				rb -= howmany(sblock.fs_bsize, sizeof(ufs2_daddr_t));
 			}
 		}
 	}
 
 	DBG_LEAVE;
 	return;
 }
 
 /* ************************************************************* usage ***** */
 /*
  * Dump a line of usage.
  */
 void
 usage(void)
 {
 	DBG_FUNC("usage")	
 
 	DBG_ENTER;
 
 	fprintf(stderr,
 	    "usage: ffsinfo [-g cylinder_group] [-i inode] [-l level] "
 	    "[-o outfile]\n"
 	    "               special | file\n");
 
 	DBG_LEAVE;
 	exit(1);
 }
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index aa2085e2fa77..4ad86b0dc14d 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -1,2454 +1,2456 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright 2009, 2010 Jeffrey W. Roberson <jeff@FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/disk.h>
 #include <sys/disklabel.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ffs/fs.h>
 
 #include <assert.h>
 #include <err.h>
 #include <setjmp.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <libufs.h>
 #include <string.h>
 #include <strings.h>
 #include <sysexits.h>
 #include <time.h>
 
 #include "fsck.h"
 
 #define	DOTDOT_OFFSET	DIRECTSIZ(1)
 
 struct suj_seg {
 	TAILQ_ENTRY(suj_seg) ss_next;
 	struct jsegrec	ss_rec;
 	uint8_t		*ss_blk;
 };
 
 struct suj_rec {
 	TAILQ_ENTRY(suj_rec) sr_next;
 	union jrec	*sr_rec;
 };
 TAILQ_HEAD(srechd, suj_rec);
 
 struct suj_ino {
 	LIST_ENTRY(suj_ino)	si_next;
 	struct srechd		si_recs;
 	struct srechd		si_newrecs;
 	struct srechd		si_movs;
 	struct jtrncrec		*si_trunc;
 	ino_t			si_ino;
 	char			si_skipparent;
 	char			si_hasrecs;
 	char			si_blkadj;
 	char			si_linkadj;
 	int			si_mode;
 	nlink_t			si_nlinkadj;
 	nlink_t			si_nlink;
 	nlink_t			si_dotlinks;
 };
 LIST_HEAD(inohd, suj_ino);
 
 struct suj_blk {
 	LIST_ENTRY(suj_blk)	sb_next;
 	struct srechd		sb_recs;
 	ufs2_daddr_t		sb_blk;
 };
 LIST_HEAD(blkhd, suj_blk);
 
 struct suj_cg {
 	LIST_ENTRY(suj_cg)	sc_next;
 	struct blkhd		sc_blkhash[HASHSIZE];
 	struct inohd		sc_inohash[HASHSIZE];
 	struct ino_blk		*sc_lastiblk;
 	struct suj_ino		*sc_lastino;
 	struct suj_blk		*sc_lastblk;
 	struct bufarea		*sc_cgbp;
 	struct cg		*sc_cgp;
 	int			sc_cgx;
 };
 
 static LIST_HEAD(cghd, suj_cg) cghash[HASHSIZE];
 static struct suj_cg *lastcg;
 
 static TAILQ_HEAD(seghd, suj_seg) allsegs;
 static uint64_t oldseq;
 static struct fs *fs = NULL;
 static ino_t sujino;
 
 /*
  * Summary statistics.
  */
 static uint64_t freefrags;
 static uint64_t freeblocks;
 static uint64_t freeinos;
 static uint64_t freedir;
 static uint64_t jbytes;
 static uint64_t jrecs;
 
 static jmp_buf	jmpbuf;
 
 typedef void (*ino_visitor)(ino_t, ufs_lbn_t, ufs2_daddr_t, int);
 static void err_suj(const char *, ...) __dead2;
 static void ino_trunc(ino_t, off_t);
 static void ino_decr(ino_t);
 static void ino_adjust(struct suj_ino *);
 static void ino_build(struct suj_ino *);
 static int blk_isfree(ufs2_daddr_t);
 static void initsuj(void);
 
 static void *
 errmalloc(size_t n)
 {
 	void *a;
 
 	a = Malloc(n);
 	if (a == NULL)
 		err(EX_OSERR, "malloc(%zu)", n);
 	return (a);
 }
 
 /*
  * When hit a fatal error in journalling check, print out
  * the error and then offer to fallback to normal fsck.
  */
 static void
 err_suj(const char * restrict fmt, ...)
 {
 	va_list ap;
 
 	if (preen)
 		(void)fprintf(stdout, "%s: ", cdevname);
 
 	va_start(ap, fmt);
 	(void)vfprintf(stdout, fmt, ap);
 	va_end(ap);
 
 	longjmp(jmpbuf, -1);
 }
 
 /*
  * Lookup a cg by number in the hash so we can keep track of which cgs
  * need stats rebuilt.
  */
 static struct suj_cg *
 cg_lookup(int cgx)
 {
 	struct cghd *hd;
 	struct suj_cg *sc;
 	struct bufarea *cgbp;
 
 	if (cgx < 0 || cgx >= fs->fs_ncg)
 		err_suj("Bad cg number %d\n", cgx);
 	if (lastcg && lastcg->sc_cgx == cgx)
 		return (lastcg);
 	cgbp = cglookup(cgx);
 	if (!check_cgmagic(cgx, cgbp, 0))
 		err_suj("UNABLE TO REBUILD CYLINDER GROUP %d", cgx);
 	hd = &cghash[HASH(cgx)];
 	LIST_FOREACH(sc, hd, sc_next)
 		if (sc->sc_cgx == cgx) {
 			sc->sc_cgbp = cgbp;
 			sc->sc_cgp = sc->sc_cgbp->b_un.b_cg;
 			lastcg = sc;
 			return (sc);
 		}
 	sc = errmalloc(sizeof(*sc));
 	bzero(sc, sizeof(*sc));
 	sc->sc_cgbp = cgbp;
 	sc->sc_cgp = sc->sc_cgbp->b_un.b_cg;
 	sc->sc_cgx = cgx;
 	LIST_INSERT_HEAD(hd, sc, sc_next);
 	return (sc);
 }
 
 /*
  * Lookup an inode number in the hash and allocate a suj_ino if it does
  * not exist.
  */
 static struct suj_ino *
 ino_lookup(ino_t ino, int creat)
 {
 	struct suj_ino *sino;
 	struct inohd *hd;
 	struct suj_cg *sc;
 
 	sc = cg_lookup(ino_to_cg(fs, ino));
 	if (sc->sc_lastino && sc->sc_lastino->si_ino == ino)
 		return (sc->sc_lastino);
 	hd = &sc->sc_inohash[HASH(ino)];
 	LIST_FOREACH(sino, hd, si_next)
 		if (sino->si_ino == ino)
 			return (sino);
 	if (creat == 0)
 		return (NULL);
 	sino = errmalloc(sizeof(*sino));
 	bzero(sino, sizeof(*sino));
 	sino->si_ino = ino;
 	TAILQ_INIT(&sino->si_recs);
 	TAILQ_INIT(&sino->si_newrecs);
 	TAILQ_INIT(&sino->si_movs);
 	LIST_INSERT_HEAD(hd, sino, si_next);
 
 	return (sino);
 }
 
 /*
  * Lookup a block number in the hash and allocate a suj_blk if it does
  * not exist.
  */
 static struct suj_blk *
 blk_lookup(ufs2_daddr_t blk, int creat)
 {
 	struct suj_blk *sblk;
 	struct suj_cg *sc;
 	struct blkhd *hd;
 
 	sc = cg_lookup(dtog(fs, blk));
 	if (sc->sc_lastblk && sc->sc_lastblk->sb_blk == blk)
 		return (sc->sc_lastblk);
 	hd = &sc->sc_blkhash[HASH(fragstoblks(fs, blk))];
 	LIST_FOREACH(sblk, hd, sb_next)
 		if (sblk->sb_blk == blk)
 			return (sblk);
 	if (creat == 0)
 		return (NULL);
 	sblk = errmalloc(sizeof(*sblk));
 	bzero(sblk, sizeof(*sblk));
 	sblk->sb_blk = blk;
 	TAILQ_INIT(&sblk->sb_recs);
 	LIST_INSERT_HEAD(hd, sblk, sb_next);
 
 	return (sblk);
 }
 
 static int
 blk_overlaps(struct jblkrec *brec, ufs2_daddr_t start, int frags)
 {
 	ufs2_daddr_t bstart;
 	ufs2_daddr_t bend;
 	ufs2_daddr_t end;
 
 	end = start + frags;
 	bstart = brec->jb_blkno + brec->jb_oldfrags;
 	bend = bstart + brec->jb_frags;
 	if (start < bend && end > bstart)
 		return (1);
 	return (0);
 }
 
 static int
 blk_equals(struct jblkrec *brec, ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t start,
     int frags)
 {
 
 	if (brec->jb_ino != ino || brec->jb_lbn != lbn)
 		return (0);
 	if (brec->jb_blkno + brec->jb_oldfrags != start)
 		return (0);
 	if (brec->jb_frags < frags)
 		return (0);
 	return (1);
 }
 
 static void
 blk_setmask(struct jblkrec *brec, int *mask)
 {
 	int i;
 
 	for (i = brec->jb_oldfrags; i < brec->jb_oldfrags + brec->jb_frags; i++)
 		*mask |= 1 << i;
 }
 
 /*
  * Determine whether a given block has been reallocated to a new location.
  * Returns a mask of overlapping bits if any frags have been reused or
  * zero if the block has not been re-used and the contents can be trusted.
  *
  * This is used to ensure that an orphaned pointer due to truncate is safe
  * to be freed.  The mask value can be used to free partial blocks.
  */
 static int
 blk_freemask(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn, int frags)
 {
 	struct suj_blk *sblk;
 	struct suj_rec *srec;
 	struct jblkrec *brec;
 	int mask;
 	int off;
 
 	/*
 	 * To be certain we're not freeing a reallocated block we lookup
 	 * this block in the blk hash and see if there is an allocation
 	 * journal record that overlaps with any fragments in the block
 	 * we're concerned with.  If any fragments have ben reallocated
 	 * the block has already been freed and re-used for another purpose.
 	 */
 	mask = 0;
 	sblk = blk_lookup(blknum(fs, blk), 0);
 	if (sblk == NULL)
 		return (0);
 	off = blk - sblk->sb_blk;
 	TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) {
 		brec = (struct jblkrec *)srec->sr_rec;
 		/*
 		 * If the block overlaps but does not match
 		 * exactly this record refers to the current
 		 * location.
 		 */
 		if (blk_overlaps(brec, blk, frags) == 0)
 			continue;
 		if (blk_equals(brec, ino, lbn, blk, frags) == 1)
 			mask = 0;
 		else
 			blk_setmask(brec, &mask);
 	}
 	if (debug)
 		printf("blk_freemask: blk %jd sblk %jd off %d mask 0x%X\n",
 		    blk, sblk->sb_blk, off, mask);
 	return (mask >> off);
 }
 
 /*
  * Determine whether it is safe to follow an indirect.  It is not safe
  * if any part of the indirect has been reallocated or the last journal
  * entry was an allocation.  Just allocated indirects may not have valid
  * pointers yet and all of their children will have their own records.
  * It is also not safe to follow an indirect if the cg bitmap has been
  * cleared as a new allocation may write to the block prior to the journal
  * being written.
  *
  * Returns 1 if it's safe to follow the indirect and 0 otherwise.
  */
 static int
 blk_isindir(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn)
 {
 	struct suj_blk *sblk;
 	struct jblkrec *brec;
 
 	sblk = blk_lookup(blk, 0);
 	if (sblk == NULL)
 		return (1);
 	if (TAILQ_EMPTY(&sblk->sb_recs))
 		return (1);
 	brec = (struct jblkrec *)TAILQ_LAST(&sblk->sb_recs, srechd)->sr_rec;
 	if (blk_equals(brec, ino, lbn, blk, fs->fs_frag))
 		if (brec->jb_op == JOP_FREEBLK)
 			return (!blk_isfree(blk));
 	return (0);
 }
 
 /*
  * Clear an inode from the cg bitmap.  If the inode was already clear return
  * 0 so the caller knows it does not have to check the inode contents.
  */
 static int
 ino_free(ino_t ino, int mode)
 {
 	struct suj_cg *sc;
 	uint8_t *inosused;
 	struct cg *cgp;
 	int cg;
 
 	cg = ino_to_cg(fs, ino);
 	ino = ino % fs->fs_ipg;
 	sc = cg_lookup(cg);
 	cgp = sc->sc_cgp;
 	inosused = cg_inosused(cgp);
 	/*
 	 * The bitmap may never have made it to the disk so we have to
 	 * conditionally clear.  We can avoid writing the cg in this case.
 	 */
 	if (isclr(inosused, ino))
 		return (0);
 	freeinos++;
 	clrbit(inosused, ino);
 	if (ino < cgp->cg_irotor)
 		cgp->cg_irotor = ino;
 	cgp->cg_cs.cs_nifree++;
 	if ((mode & IFMT) == IFDIR) {
 		freedir++;
 		cgp->cg_cs.cs_ndir--;
 	}
 	cgdirty(sc->sc_cgbp);
 
 	return (1);
 }
 
 /*
  * Free 'frags' frags starting at filesystem block 'bno' skipping any frags
  * set in the mask.
  */
 static void
 blk_free(ufs2_daddr_t bno, int mask, int frags)
 {
 	ufs1_daddr_t fragno, cgbno;
 	struct suj_cg *sc;
 	struct cg *cgp;
 	int i, cg;
 	uint8_t *blksfree;
 
 	if (debug)
 		printf("Freeing %d frags at blk %jd mask 0x%x\n",
 		    frags, bno, mask);
 	cg = dtog(fs, bno);
 	sc = cg_lookup(cg);
 	cgp = sc->sc_cgp;
 	cgbno = dtogd(fs, bno);
 	blksfree = cg_blksfree(cgp);
 
 	/*
 	 * If it's not allocated we only wrote the journal entry
 	 * and never the bitmaps.  Here we unconditionally clear and
 	 * resolve the cg summary later.
 	 */
 	if (frags == fs->fs_frag && mask == 0) {
 		fragno = fragstoblks(fs, cgbno);
 		ffs_setblock(fs, blksfree, fragno);
 		freeblocks++;
 	} else {
 		/*
 		 * deallocate the fragment
 		 */
 		for (i = 0; i < frags; i++)
 			if ((mask & (1 << i)) == 0 && isclr(blksfree, cgbno +i)) {
 				freefrags++;
 				setbit(blksfree, cgbno + i);
 			}
 	}
 	cgdirty(sc->sc_cgbp);
 }
 
 /*
  * Returns 1 if the whole block starting at 'bno' is marked free and 0
  * otherwise.
  */
 static int
 blk_isfree(ufs2_daddr_t bno)
 {
 	struct suj_cg *sc;
 
 	sc = cg_lookup(dtog(fs, bno));
 	return ffs_isblock(fs, cg_blksfree(sc->sc_cgp), dtogd(fs, bno));
 }
 
 /*
  * Determine whether a block exists at a particular lbn in an inode.
  * Returns 1 if found, 0 if not.  lbn may be negative for indirects
  * or ext blocks.
  */
 static int
 blk_isat(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int *frags)
 {
 	struct inode ip;
 	union dinode *dp;
 	ufs2_daddr_t nblk;
 
 	ginode(ino, &ip);
 	dp = ip.i_dp;
 	if (DIP(dp, di_nlink) == 0 || DIP(dp, di_mode) == 0) {
 		irelse(&ip);
 		return (0);
 	}
 	nblk = ino_blkatoff(dp, ino, lbn, frags, NULL);
 	irelse(&ip);
 	return (nblk == blk);
 }
 
 /*
  * Clear the directory entry at diroff that should point to child.  Minimal
  * checking is done and it is assumed that this path was verified with isat.
  */
 static void
 ino_clrat(ino_t parent, off_t diroff, ino_t child)
 {
 	union dinode *dip;
 	struct direct *dp;
 	struct inode ip;
 	ufs2_daddr_t blk;
 	struct bufarea *bp;
 	ufs_lbn_t lbn;
 	int blksize;
 	int frags;
 	int doff;
 
 	if (debug)
 		printf("Clearing inode %ju from parent %ju at offset %jd\n",
 		    (uintmax_t)child, (uintmax_t)parent, diroff);
 
 	lbn = lblkno(fs, diroff);
 	doff = blkoff(fs, diroff);
 	ginode(parent, &ip);
 	dip = ip.i_dp;
 	blk = ino_blkatoff(dip, parent, lbn, &frags, NULL);
 	blksize = sblksize(fs, DIP(dip, di_size), lbn);
 	irelse(&ip);
 	bp = getdatablk(blk, blksize, BT_DIRDATA);
 	if (bp->b_errs != 0)
 		err_suj("ino_clrat: UNRECOVERABLE I/O ERROR");
 	dp = (struct direct *)&bp->b_un.b_buf[doff];
 	if (dp->d_ino != child)
 		errx(1, "Inode %ju does not exist in %ju at %jd",
 		    (uintmax_t)child, (uintmax_t)parent, diroff);
 	dp->d_ino = 0;
 	dirty(bp);
 	brelse(bp);
 	/*
 	 * The actual .. reference count will already have been removed
 	 * from the parent by the .. remref record.
 	 */
 }
 
 /*
  * Determines whether a pointer to an inode exists within a directory
  * at a specified offset.  Returns the mode of the found entry.
  */
 static int
 ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
 {
 	struct inode ip;
 	union dinode *dip;
 	struct bufarea *bp;
 	struct direct *dp;
 	ufs2_daddr_t blk;
 	ufs_lbn_t lbn;
 	int blksize;
 	int frags;
 	int dpoff;
 	int doff;
 
 	*isdot = 0;
 	ginode(parent, &ip);
 	dip = ip.i_dp;
 	*mode = DIP(dip, di_mode);
 	if ((*mode & IFMT) != IFDIR) {
 		if (debug) {
 			/*
 			 * This can happen if the parent inode
 			 * was reallocated.
 			 */
 			if (*mode != 0)
 				printf("Directory %ju has bad mode %o\n",
 				    (uintmax_t)parent, *mode);
 			else
 				printf("Directory %ju has zero mode\n",
 				    (uintmax_t)parent);
 		}
 		irelse(&ip);
 		return (0);
 	}
 	lbn = lblkno(fs, diroff);
 	doff = blkoff(fs, diroff);
 	blksize = sblksize(fs, DIP(dip, di_size), lbn);
 	if (diroff + DIRECTSIZ(1) > DIP(dip, di_size) || doff >= blksize) {
 		if (debug)
 			printf("ino %ju absent from %ju due to offset %jd"
 			    " exceeding size %jd\n",
 			    (uintmax_t)child, (uintmax_t)parent, diroff,
 			    DIP(dip, di_size));
 		irelse(&ip);
 		return (0);
 	}
 	blk = ino_blkatoff(dip, parent, lbn, &frags, NULL);
 	irelse(&ip);
 	if (blk <= 0) {
 		if (debug)
 			printf("Sparse directory %ju", (uintmax_t)parent);
 		return (0);
 	}
 	bp = getdatablk(blk, blksize, BT_DIRDATA);
 	if (bp->b_errs != 0)
 		err_suj("ino_isat: UNRECOVERABLE I/O ERROR");
 	/*
 	 * Walk through the records from the start of the block to be
 	 * certain we hit a valid record and not some junk in the middle
 	 * of a file name.  Stop when we reach or pass the expected offset.
 	 */
 	dpoff = rounddown(doff, DIRBLKSIZ);
 	do {
 		dp = (struct direct *)&bp->b_un.b_buf[dpoff];
 		if (dpoff == doff)
 			break;
 		if (dp->d_reclen == 0)
 			break;
 		dpoff += dp->d_reclen;
 	} while (dpoff <= doff);
 	if (dpoff > fs->fs_bsize)
 		err_suj("Corrupt directory block in dir ino %ju\n",
 		    (uintmax_t)parent);
 	/* Not found. */
 	if (dpoff != doff) {
 		if (debug)
 			printf("ino %ju not found in %ju, lbn %jd, dpoff %d\n",
 			    (uintmax_t)child, (uintmax_t)parent, lbn, dpoff);
 		brelse(bp);
 		return (0);
 	}
 	/*
 	 * We found the item in question.  Record the mode and whether it's
 	 * a . or .. link for the caller.
 	 */
 	if (dp->d_ino == child) {
 		if (child == parent)
 			*isdot = 1;
 		else if (dp->d_namlen == 2 &&
 		    dp->d_name[0] == '.' && dp->d_name[1] == '.')
 			*isdot = 1;
 		*mode = DTTOIF(dp->d_type);
 		brelse(bp);
 		return (1);
 	}
 	if (debug)
 		printf("ino %ju doesn't match dirent ino %ju in parent %ju\n",
 		    (uintmax_t)child, (uintmax_t)dp->d_ino, (uintmax_t)parent);
 	brelse(bp);
 	return (0);
 }
 
 #define	VISIT_INDIR	0x0001
 #define	VISIT_EXT	0x0002
 #define	VISIT_ROOT	0x0004	/* Operation came via root & valid pointers. */
 
 /*
  * Read an indirect level which may or may not be linked into an inode.
  */
 static void
 indir_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, uint64_t *frags,
     ino_visitor visitor, int flags)
 {
 	struct bufarea *bp;
 	ufs_lbn_t lbnadd;
 	ufs2_daddr_t nblk;
 	ufs_lbn_t nlbn;
 	int level;
 	int i;
 
 	/*
 	 * Don't visit indirect blocks with contents we can't trust.  This
 	 * should only happen when indir_visit() is called to complete a
 	 * truncate that never finished and not when a pointer is found via
 	 * an inode.
 	 */
 	if (blk == 0)
 		return;
 	level = lbn_level(lbn);
 	if (level == -1)
 		err_suj("Invalid level for lbn %jd\n", lbn);
 	if ((flags & VISIT_ROOT) == 0 && blk_isindir(blk, ino, lbn) == 0) {
 		if (debug)
 			printf("blk %jd ino %ju lbn %jd(%d) is not indir.\n",
 			    blk, (uintmax_t)ino, lbn, level);
 		goto out;
 	}
 	lbnadd = 1;
 	for (i = level; i > 0; i--)
 		lbnadd *= NINDIR(fs);
 	bp = getdatablk(blk, fs->fs_bsize, BT_LEVEL1 + level);
 	if (bp->b_errs != 0)
 		err_suj("indir_visit: UNRECOVERABLE I/O ERROR");
 	for (i = 0; i < NINDIR(fs); i++) {
 		if ((nblk = IBLK(bp, i)) == 0)
 			continue;
 		if (level == 0) {
 			nlbn = -lbn + i * lbnadd;
 			(*frags) += fs->fs_frag;
 			visitor(ino, nlbn, nblk, fs->fs_frag);
 		} else {
 			nlbn = (lbn + 1) - (i * lbnadd);
 			indir_visit(ino, nlbn, nblk, frags, visitor, flags);
 		}
 	}
 	brelse(bp);
 out:
 	if (flags & VISIT_INDIR) {
 		(*frags) += fs->fs_frag;
 		visitor(ino, lbn, blk, fs->fs_frag);
 	}
 }
 
 /*
  * Visit each block in an inode as specified by 'flags' and call a
  * callback function.  The callback may inspect or free blocks.  The
  * count of frags found according to the size in the file is returned.
  * This is not valid for sparse files but may be used to determine
  * the correct di_blocks for a file.
  */
 static uint64_t
 ino_visit(union dinode *dp, ino_t ino, ino_visitor visitor, int flags)
 {
 	ufs_lbn_t nextlbn;
 	ufs_lbn_t tmpval;
 	ufs_lbn_t lbn;
 	uint64_t size;
 	uint64_t fragcnt;
 	int mode;
 	int frags;
 	int i;
 
 	size = DIP(dp, di_size);
 	mode = DIP(dp, di_mode) & IFMT;
 	fragcnt = 0;
 	if ((flags & VISIT_EXT) &&
 	    fs->fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize) {
 		for (i = 0; i < UFS_NXADDR; i++) {
 			if (dp->dp2.di_extb[i] == 0)
 				continue;
 			frags = sblksize(fs, dp->dp2.di_extsize, i);
 			frags = numfrags(fs, frags);
 			fragcnt += frags;
 			visitor(ino, -1 - i, dp->dp2.di_extb[i], frags);
 		}
 	}
 	/* Skip datablocks for short links and devices. */
 	if (mode == IFBLK || mode == IFCHR ||
 	    (mode == IFLNK && size < fs->fs_maxsymlinklen))
 		return (fragcnt);
 	for (i = 0; i < UFS_NDADDR; i++) {
 		if (DIP(dp, di_db[i]) == 0)
 			continue;
 		frags = sblksize(fs, size, i);
 		frags = numfrags(fs, frags);
 		fragcnt += frags;
 		visitor(ino, i, DIP(dp, di_db[i]), frags);
 	}
 	/*
 	 * We know the following indirects are real as we're following
 	 * real pointers to them.
 	 */
 	flags |= VISIT_ROOT;
 	for (i = 0, tmpval = NINDIR(fs), lbn = UFS_NDADDR; i < UFS_NIADDR; i++,
 	    lbn = nextlbn) {
 		nextlbn = lbn + tmpval;
 		tmpval *= NINDIR(fs);
 		if (DIP(dp, di_ib[i]) == 0)
 			continue;
 		indir_visit(ino, -lbn - i, DIP(dp, di_ib[i]), &fragcnt, visitor,
 		    flags);
 	}
 	return (fragcnt);
 }
 
 /*
  * Null visitor function used when we just want to count blocks and
  * record the lbn.
  */
 ufs_lbn_t visitlbn;
 static void
 null_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
 {
 	if (lbn > 0)
 		visitlbn = lbn;
 }
 
 /*
  * Recalculate di_blocks when we discover that a block allocation or
  * free was not successfully completed.  The kernel does not roll this back
  * because it would be too expensive to compute which indirects were
  * reachable at the time the inode was written.
  */
 static void
 ino_adjblks(struct suj_ino *sino)
 {
 	struct inode ip;
 	union dinode *dp;
 	uint64_t blocks;
 	uint64_t frags;
 	off_t isize;
 	off_t size;
 	ino_t ino;
 
 	ino = sino->si_ino;
 	ginode(ino, &ip);
 	dp = ip.i_dp;
 	/* No need to adjust zero'd inodes. */
 	if (DIP(dp, di_mode) == 0) {
 		irelse(&ip);
 		return;
 	}
 	/*
 	 * Visit all blocks and count them as well as recording the last
 	 * valid lbn in the file.  If the file size doesn't agree with the
 	 * last lbn we need to truncate to fix it.  Otherwise just adjust
 	 * the blocks count.
 	 */
 	visitlbn = 0;
 	frags = ino_visit(dp, ino, null_visit, VISIT_INDIR | VISIT_EXT);
 	blocks = fsbtodb(fs, frags);
 	/*
 	 * We assume the size and direct block list is kept coherent by
 	 * softdep.  For files that have extended into indirects we truncate
 	 * to the size in the inode or the maximum size permitted by
 	 * populated indirects.
 	 */
 	if (visitlbn >= UFS_NDADDR) {
 		isize = DIP(dp, di_size);
 		size = lblktosize(fs, visitlbn + 1);
 		if (isize > size)
 			isize = size;
 		/* Always truncate to free any unpopulated indirects. */
 		ino_trunc(ino, isize);
 		irelse(&ip);
 		return;
 	}
 	if (blocks == DIP(dp, di_blocks)) {
 		irelse(&ip);
 		return;
 	}
 	if (debug)
 		printf("ino %ju adjusting block count from %jd to %jd\n",
 		    (uintmax_t)ino, DIP(dp, di_blocks), blocks);
 	DIP_SET(dp, di_blocks, blocks);
 	inodirty(&ip);
 	irelse(&ip);
 }
 
 static void
 blk_free_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
 {
 
 	blk_free(blk, blk_freemask(blk, ino, lbn, frags), frags);
 }
 
 /*
  * Free a block or tree of blocks that was previously rooted in ino at
  * the given lbn.  If the lbn is an indirect all children are freed
  * recursively.
  */
 static void
 blk_free_lbn(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn, int frags, int follow)
 {
 	uint64_t resid;
 	int mask;
 
 	mask = blk_freemask(blk, ino, lbn, frags);
 	resid = 0;
 	if (lbn <= -UFS_NDADDR && follow && mask == 0)
 		indir_visit(ino, lbn, blk, &resid, blk_free_visit, VISIT_INDIR);
 	else
 		blk_free(blk, mask, frags);
 }
 
 static void
 ino_setskip(struct suj_ino *sino, ino_t parent)
 {
 	int isdot;
 	int mode;
 
 	if (ino_isat(sino->si_ino, DOTDOT_OFFSET, parent, &mode, &isdot))
 		sino->si_skipparent = 1;
 }
 
 static void
 ino_remref(ino_t parent, ino_t child, uint64_t diroff, int isdotdot)
 {
 	struct suj_ino *sino;
 	struct suj_rec *srec;
 	struct jrefrec *rrec;
 
 	/*
 	 * Lookup this inode to see if we have a record for it.
 	 */
 	sino = ino_lookup(child, 0);
 	/*
 	 * Tell any child directories we've already removed their
 	 * parent link cnt.  Don't try to adjust our link down again.
 	 */
 	if (sino != NULL && isdotdot == 0)
 		ino_setskip(sino, parent);
 	/*
 	 * No valid record for this inode.  Just drop the on-disk
 	 * link by one.
 	 */
 	if (sino == NULL || sino->si_hasrecs == 0) {
 		ino_decr(child);
 		return;
 	}
 	/*
 	 * Use ino_adjust() if ino_check() has already processed this
 	 * child.  If we lose the last non-dot reference to a
 	 * directory it will be discarded.
 	 */
 	if (sino->si_linkadj) {
 		if (sino->si_nlink == 0)
 			err_suj("ino_remref: ino %ld mode 0%o about to go "
 			    "negative\n", sino->si_ino, sino->si_mode);
 		sino->si_nlink--;
 		if (isdotdot)
 			sino->si_dotlinks--;
 		ino_adjust(sino);
 		return;
 	}
 	/*
 	 * If we haven't yet processed this inode we need to make
 	 * sure we will successfully discover the lost path.  If not
 	 * use nlinkadj to remember.
 	 */
 	TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
 		rrec = (struct jrefrec *)srec->sr_rec;
 		if (rrec->jr_parent == parent &&
 		    rrec->jr_diroff == diroff)
 			return;
 	}
 	sino->si_nlinkadj++;
 }
 
 /*
  * Free the children of a directory when the directory is discarded.
  */
 static void
 ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
 {
 	struct suj_ino *sino;
 	struct bufarea *bp;
 	struct direct *dp;
 	off_t diroff;
 	int skipparent;
 	int isdotdot;
 	int dpoff;
 	int size;
 
 	sino = ino_lookup(ino, 0);
 	if (sino)
 		skipparent = sino->si_skipparent;
 	else
 		skipparent = 0;
 	size = lfragtosize(fs, frags);
 	bp = getdatablk(blk, size, BT_DIRDATA);
 	if (bp->b_errs != 0)
 		err_suj("ino_free_children: UNRECOVERABLE I/O ERROR");
 	dp = (struct direct *)&bp->b_un.b_buf[0];
 	for (dpoff = 0; dpoff < size && dp->d_reclen; dpoff += dp->d_reclen) {
 		dp = (struct direct *)&bp->b_un.b_buf[dpoff];
 		if (dp->d_ino == 0 || dp->d_ino == UFS_WINO)
 			continue;
 		if (dp->d_namlen == 1 && dp->d_name[0] == '.')
 			continue;
 		isdotdot = dp->d_namlen == 2 && dp->d_name[0] == '.' &&
 		    dp->d_name[1] == '.';
 		if (isdotdot && skipparent == 1)
 			continue;
 		if (debug)
 			printf("Directory %ju removing ino %ju name %s\n",
 			    (uintmax_t)ino, (uintmax_t)dp->d_ino, dp->d_name);
 		diroff = lblktosize(fs, lbn) + dpoff;
 		ino_remref(ino, dp->d_ino, diroff, isdotdot);
 	}
 	brelse(bp);
 }
 
 /*
  * Reclaim an inode, freeing all blocks and decrementing all children's
  * link counts.  Free the inode back to the cg.
  */
 static void
 ino_reclaim(struct inode *ip, ino_t ino, int mode)
 {
 	union dinode *dp;
 	uint32_t gen;
 
 	dp = ip->i_dp;
 	if (ino == UFS_ROOTINO)
 		err_suj("Attempting to free UFS_ROOTINO\n");
 	if (debug)
 		printf("Truncating and freeing ino %ju, nlink %d, mode %o\n",
 		    (uintmax_t)ino, DIP(dp, di_nlink), DIP(dp, di_mode));
 
 	/* We are freeing an inode or directory. */
 	if ((DIP(dp, di_mode) & IFMT) == IFDIR)
 		ino_visit(dp, ino, ino_free_children, 0);
 	DIP_SET(dp, di_nlink, 0);
 	ino_visit(dp, ino, blk_free_visit, VISIT_EXT | VISIT_INDIR);
 	/* Here we have to clear the inode and release any blocks it holds. */
 	gen = DIP(dp, di_gen);
 	if (fs->fs_magic == FS_UFS1_MAGIC)
 		bzero(dp, sizeof(struct ufs1_dinode));
 	else
 		bzero(dp, sizeof(struct ufs2_dinode));
 	DIP_SET(dp, di_gen, gen);
 	inodirty(ip);
 	ino_free(ino, mode);
 	return;
 }
 
 /*
  * Adjust an inode's link count down by one when a directory goes away.
  */
 static void
 ino_decr(ino_t ino)
 {
 	struct inode ip;
 	union dinode *dp;
 	int reqlink;
 	int nlink;
 	int mode;
 
 	ginode(ino, &ip);
 	dp = ip.i_dp;
 	nlink = DIP(dp, di_nlink);
 	mode = DIP(dp, di_mode);
 	if (nlink < 1)
 		err_suj("Inode %d link count %d invalid\n", ino, nlink);
 	if (mode == 0)
 		err_suj("Inode %d has a link of %d with 0 mode\n", ino, nlink);
 	nlink--;
 	if ((mode & IFMT) == IFDIR)
 		reqlink = 2;
 	else
 		reqlink = 1;
 	if (nlink < reqlink) {
 		if (debug)
 			printf("ino %ju not enough links to live %d < %d\n",
 			    (uintmax_t)ino, nlink, reqlink);
 		ino_reclaim(&ip, ino, mode);
 		irelse(&ip);
 		return;
 	}
 	DIP_SET(dp, di_nlink, nlink);
 	inodirty(&ip);
 	irelse(&ip);
 }
 
 /*
  * Adjust the inode link count to 'nlink'.  If the count reaches zero
  * free it.
  */
 static void
 ino_adjust(struct suj_ino *sino)
 {
 	struct jrefrec *rrec;
 	struct suj_rec *srec;
 	struct suj_ino *stmp;
 	union dinode *dp;
 	struct inode ip;
 	nlink_t nlink;
 	nlink_t reqlink;
 	int recmode;
 	int isdot;
 	int mode;
 	ino_t ino;
 
 	nlink = sino->si_nlink;
 	ino = sino->si_ino;
 	mode = sino->si_mode & IFMT;
 	/*
 	 * If it's a directory with no dot links, it was truncated before
 	 * the name was cleared.  We need to clear the dirent that
 	 * points at it.
 	 */
 	if (mode == IFDIR && nlink == 1 && sino->si_dotlinks == 0) {
 		sino->si_nlink = nlink = 0;
 		TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
 			rrec = (struct jrefrec *)srec->sr_rec;
 			if (ino_isat(rrec->jr_parent, rrec->jr_diroff, ino,
 			    &recmode, &isdot) == 0)
 				continue;
 			ino_clrat(rrec->jr_parent, rrec->jr_diroff, ino);
 			break;
 		}
 		if (srec == NULL)
 			errx(1, "Directory %ju name not found", (uintmax_t)ino);
 	}
 	/*
 	 * If it's a directory with no real names pointing to it go ahead
 	 * and truncate it.  This will free any children.
 	 */
 	if (mode == IFDIR && nlink - sino->si_dotlinks == 0) {
 		sino->si_nlink = nlink = 0;
 		/*
 		 * Mark any .. links so they know not to free this inode
 		 * when they are removed.
 		 */
 		TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
 			rrec = (struct jrefrec *)srec->sr_rec;
 			if (rrec->jr_diroff == DOTDOT_OFFSET) {
 				stmp = ino_lookup(rrec->jr_parent, 0);
 				if (stmp)
 					ino_setskip(stmp, ino);
 			}
 		}
 	}
 	ginode(ino, &ip);
 	dp = ip.i_dp;
 	mode = DIP(dp, di_mode) & IFMT;
 	if (nlink > UFS_LINK_MAX)
 		err_suj("ino %ju nlink manipulation error, new %ju, old %d\n",
 		    (uintmax_t)ino, (uintmax_t)nlink, DIP(dp, di_nlink));
 	if (debug)
 	       printf("Adjusting ino %ju, nlink %ju, old link %d lastmode %o\n",
 		    (uintmax_t)ino, (uintmax_t)nlink, DIP(dp, di_nlink),
 		    sino->si_mode);
 	if (mode == 0) {
 		if (debug)
 			printf("ino %ju, zero inode freeing bitmap\n",
 			    (uintmax_t)ino);
 		ino_free(ino, sino->si_mode);
 		irelse(&ip);
 		return;
 	}
 	/* XXX Should be an assert? */
 	if (mode != sino->si_mode && debug)
 		printf("ino %ju, mode %o != %o\n",
 		    (uintmax_t)ino, mode, sino->si_mode);
 	if ((mode & IFMT) == IFDIR)
 		reqlink = 2;
 	else
 		reqlink = 1;
 	/* If the inode doesn't have enough links to live, free it. */
 	if (nlink < reqlink) {
 		if (debug)
 			printf("ino %ju not enough links to live %ju < %ju\n",
 			    (uintmax_t)ino, (uintmax_t)nlink,
 			    (uintmax_t)reqlink);
 		ino_reclaim(&ip, ino, mode);
 		irelse(&ip);
 		return;
 	}
 	/* If required write the updated link count. */
 	if (DIP(dp, di_nlink) == nlink) {
 		if (debug)
 			printf("ino %ju, link matches, skipping.\n",
 			    (uintmax_t)ino);
 		irelse(&ip);
 		return;
 	}
 	DIP_SET(dp, di_nlink, nlink);
 	inodirty(&ip);
 	irelse(&ip);
 }
 
 /*
  * Truncate some or all blocks in an indirect, freeing any that are required
  * and zeroing the indirect.
  */
 static void
 indir_trunc(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, ufs_lbn_t lastlbn,
 	union dinode *dp)
 {
 	struct bufarea *bp;
 	ufs_lbn_t lbnadd;
 	ufs2_daddr_t nblk;
 	ufs_lbn_t next;
 	ufs_lbn_t nlbn;
 	int isdirty;
 	int level;
 	int i;
 
 	if (blk == 0)
 		return;
 	isdirty = 0;
 	level = lbn_level(lbn);
 	if (level == -1)
 		err_suj("Invalid level for lbn %jd\n", lbn);
 	lbnadd = 1;
 	for (i = level; i > 0; i--)
 		lbnadd *= NINDIR(fs);
 	bp = getdatablk(blk, fs->fs_bsize, BT_LEVEL1 + level);
 	if (bp->b_errs != 0)
 		err_suj("indir_trunc: UNRECOVERABLE I/O ERROR");
 	for (i = 0; i < NINDIR(fs); i++) {
 		if ((nblk = IBLK(bp, i)) == 0)
 			continue;
 		if (level != 0) {
 			nlbn = (lbn + 1) - (i * lbnadd);
 			/*
 			 * Calculate the lbn of the next indirect to
 			 * determine if any of this indirect must be
 			 * reclaimed.
 			 */
 			next = -(lbn + level) + ((i+1) * lbnadd);
 			if (next <= lastlbn)
 				continue;
 			indir_trunc(ino, nlbn, nblk, lastlbn, dp);
 			/* If all of this indirect was reclaimed, free it. */
 			nlbn = next - lbnadd;
 			if (nlbn < lastlbn)
 				continue;
 		} else {
 			nlbn = -lbn + i * lbnadd;
 			if (nlbn < lastlbn)
 				continue;
 		}
 		isdirty = 1;
 		blk_free(nblk, 0, fs->fs_frag);
 		IBLK_SET(bp, i, 0);
 	}
 	if (isdirty)
 		dirty(bp);
 	brelse(bp);
 }
 
 /*
  * Truncate an inode to the minimum of the given size or the last populated
  * block after any over size have been discarded.  The kernel would allocate
  * the last block in the file but fsck does not and neither do we.  This
  * code never extends files, only shrinks them.
  */
 static void
 ino_trunc(ino_t ino, off_t size)
 {
 	struct inode ip;
 	union dinode *dp;
 	struct bufarea *bp;
 	ufs2_daddr_t bn;
 	uint64_t totalfrags;
 	ufs_lbn_t nextlbn;
 	ufs_lbn_t lastlbn;
 	ufs_lbn_t tmpval;
 	ufs_lbn_t lbn;
 	ufs_lbn_t i;
 	int blksize, frags;
 	off_t cursize;
 	off_t off;
 	int mode;
 
 	ginode(ino, &ip);
 	dp = ip.i_dp;
 	mode = DIP(dp, di_mode) & IFMT;
 	cursize = DIP(dp, di_size);
 	if (debug)
 		printf("Truncating ino %ju, mode %o to size %jd from size %jd\n",
 		    (uintmax_t)ino, mode, size, cursize);
 
 	/* Skip datablocks for short links and devices. */
 	if (mode == 0 || mode == IFBLK || mode == IFCHR ||
 	    (mode == IFLNK && cursize < fs->fs_maxsymlinklen)) {
 		irelse(&ip);
 		return;
 	}
 	/* Don't extend. */
 	if (size > cursize) {
 		irelse(&ip);
 		return;
 	}
 	if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) {
 		if (size > 0)
 			err_suj("Partial truncation of ino %ju snapshot file\n",
 			    (uintmax_t)ino);
 	}
 	lastlbn = lblkno(fs, blkroundup(fs, size));
 	for (i = lastlbn; i < UFS_NDADDR; i++) {
 		if ((bn = DIP(dp, di_db[i])) == 0)
 			continue;
 		blksize = sblksize(fs, cursize, i);
 		blk_free(bn, 0, numfrags(fs, blksize));
 		DIP_SET(dp, di_db[i], 0);
 	}
 	/*
 	 * Follow indirect blocks, freeing anything required.
 	 */
 	for (i = 0, tmpval = NINDIR(fs), lbn = UFS_NDADDR; i < UFS_NIADDR; i++,
 	    lbn = nextlbn) {
 		nextlbn = lbn + tmpval;
 		tmpval *= NINDIR(fs);
 		/* If we're not freeing any in this indirect range skip it. */
 		if (lastlbn >= nextlbn)
 			continue;
 		if (DIP(dp, di_ib[i]) == 0)
 			continue;
 		indir_trunc(ino, -lbn - i, DIP(dp, di_ib[i]), lastlbn, dp);
 		/* If we freed everything in this indirect free the indir. */
 		if (lastlbn > lbn)
 			continue;
 		blk_free(DIP(dp, di_ib[i]), 0, fs->fs_frag);
 		DIP_SET(dp, di_ib[i], 0);
 	}
 	/*
 	 * Now that we've freed any whole blocks that exceed the desired
 	 * truncation size, figure out how many blocks remain and what the
 	 * last populated lbn is.  We will set the size to this last lbn
 	 * rather than worrying about allocating the final lbn as the kernel
 	 * would've done.  This is consistent with normal fsck behavior.
 	 */
 	visitlbn = 0;
 	totalfrags = ino_visit(dp, ino, null_visit, VISIT_INDIR | VISIT_EXT);
 	if (size > lblktosize(fs, visitlbn + 1))
 		size = lblktosize(fs, visitlbn + 1);
 	/*
 	 * If we're truncating direct blocks we have to adjust frags
 	 * accordingly.
 	 */
 	if (visitlbn < UFS_NDADDR && totalfrags) {
 		long oldspace, newspace;
 
 		bn = DIP(dp, di_db[visitlbn]);
 		if (bn == 0)
 			err_suj("Bad blk at ino %ju lbn %jd\n",
 			    (uintmax_t)ino, visitlbn);
 		oldspace = sblksize(fs, cursize, visitlbn);
 		newspace = sblksize(fs, size, visitlbn);
 		if (oldspace != newspace) {
 			bn += numfrags(fs, newspace);
 			frags = numfrags(fs, oldspace - newspace);
 			blk_free(bn, 0, frags);
 			totalfrags -= frags;
 		}
 	}
 	DIP_SET(dp, di_blocks, fsbtodb(fs, totalfrags));
 	DIP_SET(dp, di_size, size);
 	inodirty(&ip);
 	/*
 	 * If we've truncated into the middle of a block or frag we have
 	 * to zero it here.  Otherwise the file could extend into
 	 * uninitialized space later.
 	 */
 	off = blkoff(fs, size);
 	if (off && DIP(dp, di_mode) != IFDIR) {
 		long clrsize;
 
 		bn = ino_blkatoff(dp, ino, visitlbn, &frags, NULL);
 		if (bn == 0)
 			err_suj("Block missing from ino %ju at lbn %jd\n",
 			    (uintmax_t)ino, visitlbn);
 		clrsize = frags * fs->fs_fsize;
 		bp = getdatablk(bn, clrsize, BT_DATA);
 		if (bp->b_errs != 0)
 			err_suj("ino_trunc: UNRECOVERABLE I/O ERROR");
 		clrsize -= off;
 		bzero(&bp->b_un.b_buf[off], clrsize);
 		dirty(bp);
 		brelse(bp);
 	}
 	irelse(&ip);
 	return;
 }
 
 /*
  * Process records available for one inode and determine whether the
  * link count is correct or needs adjusting.
  */
 static void
 ino_check(struct suj_ino *sino)
 {
 	struct suj_rec *srec;
 	struct jrefrec *rrec;
 	nlink_t dotlinks;
 	nlink_t newlinks;
 	nlink_t removes;
 	nlink_t nlink;
 	ino_t ino;
 	int isdot;
 	int isat;
 	int mode;
 
 	if (sino->si_hasrecs == 0)
 		return;
 	ino = sino->si_ino;
 	rrec = (struct jrefrec *)TAILQ_FIRST(&sino->si_recs)->sr_rec;
 	nlink = rrec->jr_nlink;
 	newlinks = 0;
 	dotlinks = 0;
 	removes = sino->si_nlinkadj;
 	TAILQ_FOREACH(srec, &sino->si_recs, sr_next) {
 		rrec = (struct jrefrec *)srec->sr_rec;
 		isat = ino_isat(rrec->jr_parent, rrec->jr_diroff,
 		    rrec->jr_ino, &mode, &isdot);
 		if (isat && (mode & IFMT) != (rrec->jr_mode & IFMT))
 			err_suj("Inode mode/directory type mismatch %o != %o\n",
 			    mode, rrec->jr_mode);
 		if (debug)
 			printf("jrefrec: op %d ino %ju, nlink %ju, parent %ju, "
 			    "diroff %jd, mode %o, isat %d, isdot %d\n",
 			    rrec->jr_op, (uintmax_t)rrec->jr_ino,
 			    (uintmax_t)rrec->jr_nlink,
 			    (uintmax_t)rrec->jr_parent,
 			    (uintmax_t)rrec->jr_diroff,
 			    rrec->jr_mode, isat, isdot);
 		mode = rrec->jr_mode & IFMT;
 		if (rrec->jr_op == JOP_REMREF)
 			removes++;
 		newlinks += isat;
 		if (isdot)
 			dotlinks += isat;
 	}
 	/*
 	 * The number of links that remain are the starting link count
 	 * subtracted by the total number of removes with the total
 	 * links discovered back in.  An incomplete remove thus
 	 * makes no change to the link count but an add increases
 	 * by one.
 	 */
 	if (debug)
 		printf(
 		    "ino %ju nlink %ju newlinks %ju removes %ju dotlinks %ju\n",
 		    (uintmax_t)ino, (uintmax_t)nlink, (uintmax_t)newlinks,
 		    (uintmax_t)removes, (uintmax_t)dotlinks);
 	nlink += newlinks;
 	nlink -= removes;
 	sino->si_linkadj = 1;
 	sino->si_nlink = nlink;
 	sino->si_dotlinks = dotlinks;
 	sino->si_mode = mode;
 	ino_adjust(sino);
 }
 
 /*
  * Process records available for one block and determine whether it is
  * still allocated and whether the owning inode needs to be updated or
  * a free completed.
  */
 static void
 blk_check(struct suj_blk *sblk)
 {
 	struct suj_rec *srec;
 	struct jblkrec *brec;
 	struct suj_ino *sino;
 	ufs2_daddr_t blk;
 	int mask;
 	int frags;
 	int isat;
 
 	/*
 	 * Each suj_blk actually contains records for any fragments in that
 	 * block.  As a result we must evaluate each record individually.
 	 */
 	sino = NULL;
 	TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) {
 		brec = (struct jblkrec *)srec->sr_rec;
 		frags = brec->jb_frags;
 		blk = brec->jb_blkno + brec->jb_oldfrags;
 		isat = blk_isat(brec->jb_ino, brec->jb_lbn, blk, &frags);
 		if (sino == NULL || sino->si_ino != brec->jb_ino) {
 			sino = ino_lookup(brec->jb_ino, 1);
 			sino->si_blkadj = 1;
 		}
 		if (debug)
 			printf("op %d blk %jd ino %ju lbn %jd frags %d isat %d (%d)\n",
 			    brec->jb_op, blk, (uintmax_t)brec->jb_ino,
 			    brec->jb_lbn, brec->jb_frags, isat, frags);
 		/*
 		 * If we found the block at this address we still have to
 		 * determine if we need to free the tail end that was
 		 * added by adding contiguous fragments from the same block.
 		 */
 		if (isat == 1) {
 			if (frags == brec->jb_frags)
 				continue;
 			mask = blk_freemask(blk, brec->jb_ino, brec->jb_lbn,
 			    brec->jb_frags);
 			mask >>= frags;
 			blk += frags;
 			frags = brec->jb_frags - frags;
 			blk_free(blk, mask, frags);
 			continue;
 		}
 		/*
 	 	 * The block wasn't found, attempt to free it.  It won't be
 		 * freed if it was actually reallocated.  If this was an
 		 * allocation we don't want to follow indirects as they
 		 * may not be written yet.  Any children of the indirect will
 		 * have their own records.  If it's a free we need to
 		 * recursively free children.
 		 */
 		blk_free_lbn(blk, brec->jb_ino, brec->jb_lbn, brec->jb_frags,
 		    brec->jb_op == JOP_FREEBLK);
 	}
 }
 
 /*
  * Walk the list of inode records for this cg and resolve moved and duplicate
  * inode references now that we have a complete picture.
  */
 static void
 cg_build(struct suj_cg *sc)
 {
 	struct suj_ino *sino;
 	int i;
 
 	for (i = 0; i < HASHSIZE; i++)
 		LIST_FOREACH(sino, &sc->sc_inohash[i], si_next)
 			ino_build(sino);
 }
 
 /*
  * Handle inodes requiring truncation.  This must be done prior to
  * looking up any inodes in directories.
  */
 static void
 cg_trunc(struct suj_cg *sc)
 {
 	struct suj_ino *sino;
 	int i;
 
 	for (i = 0; i < HASHSIZE; i++) {
 		LIST_FOREACH(sino, &sc->sc_inohash[i], si_next) {
 			if (sino->si_trunc) {
 				ino_trunc(sino->si_ino,
 				    sino->si_trunc->jt_size);
 				sino->si_blkadj = 0;
 				sino->si_trunc = NULL;
 			}
 			if (sino->si_blkadj)
 				ino_adjblks(sino);
 		}
 	}
 }
 
 static void
 cg_adj_blk(struct suj_cg *sc)
 {
 	struct suj_ino *sino;
 	int i;
 
 	for (i = 0; i < HASHSIZE; i++) {
 		LIST_FOREACH(sino, &sc->sc_inohash[i], si_next) {
 			if (sino->si_blkadj)
 				ino_adjblks(sino);
 		}
 	}
 }
 
 /*
  * Free any partially allocated blocks and then resolve inode block
  * counts.
  */
 static void
 cg_check_blk(struct suj_cg *sc)
 {
 	struct suj_blk *sblk;
 	int i;
 
 
 	for (i = 0; i < HASHSIZE; i++)
 		LIST_FOREACH(sblk, &sc->sc_blkhash[i], sb_next)
 			blk_check(sblk);
 }
 
 /*
  * Walk the list of inode records for this cg, recovering any
  * changes which were not complete at the time of crash.
  */
 static void
 cg_check_ino(struct suj_cg *sc)
 {
 	struct suj_ino *sino;
 	int i;
 
 	for (i = 0; i < HASHSIZE; i++)
 		LIST_FOREACH(sino, &sc->sc_inohash[i], si_next)
 			ino_check(sino);
 }
 
 static void
 cg_apply(void (*apply)(struct suj_cg *))
 {
 	struct suj_cg *scg;
 	int i;
 
 	for (i = 0; i < HASHSIZE; i++)
 		LIST_FOREACH(scg, &cghash[i], sc_next)
 			apply(scg);
 }
 
 /*
  * Process the unlinked but referenced file list.  Freeing all inodes.
  */
 static void
 ino_unlinked(void)
 {
 	struct inode ip;
 	union dinode *dp;
 	uint16_t mode;
 	ino_t inon;
 	ino_t ino;
 
 	ino = fs->fs_sujfree;
 	fs->fs_sujfree = 0;
 	while (ino != 0) {
 		ginode(ino, &ip);
 		dp = ip.i_dp;
 		mode = DIP(dp, di_mode) & IFMT;
 		inon = DIP(dp, di_freelink);
 		DIP_SET(dp, di_freelink, 0);
 		inodirty(&ip);
 		/*
 		 * XXX Should this be an errx?
 		 */
 		if (DIP(dp, di_nlink) == 0) {
 			if (debug)
 				printf("Freeing unlinked ino %ju mode %o\n",
 				    (uintmax_t)ino, mode);
 			ino_reclaim(&ip, ino, mode);
 		} else if (debug)
 			printf("Skipping ino %ju mode %o with link %d\n",
 			    (uintmax_t)ino, mode, DIP(dp, di_nlink));
 		ino = inon;
 		irelse(&ip);
 	}
 }
 
 /*
  * Append a new record to the list of records requiring processing.
  */
 static void
 ino_append(union jrec *rec)
 {
 	struct jrefrec *refrec;
 	struct jmvrec *mvrec;
 	struct suj_ino *sino;
 	struct suj_rec *srec;
 
 	mvrec = &rec->rec_jmvrec;
 	refrec = &rec->rec_jrefrec;
 	if (debug && mvrec->jm_op == JOP_MVREF)
 		printf("ino move: ino %ju, parent %ju, "
 		    "diroff %jd, oldoff %jd\n",
 		    (uintmax_t)mvrec->jm_ino, (uintmax_t)mvrec->jm_parent,
 		    (uintmax_t)mvrec->jm_newoff, (uintmax_t)mvrec->jm_oldoff);
 	else if (debug &&
 	    (refrec->jr_op == JOP_ADDREF || refrec->jr_op == JOP_REMREF))
 		printf("ino ref: op %d, ino %ju, nlink %ju, "
 		    "parent %ju, diroff %jd\n",
 		    refrec->jr_op, (uintmax_t)refrec->jr_ino,
 		    (uintmax_t)refrec->jr_nlink,
 		    (uintmax_t)refrec->jr_parent, (uintmax_t)refrec->jr_diroff);
 	sino = ino_lookup(((struct jrefrec *)rec)->jr_ino, 1);
 	sino->si_hasrecs = 1;
 	srec = errmalloc(sizeof(*srec));
 	srec->sr_rec = rec;
 	TAILQ_INSERT_TAIL(&sino->si_newrecs, srec, sr_next);
 }
 
 /*
  * Add a reference adjustment to the sino list and eliminate dups.  The
  * primary loop in ino_build_ref() checks for dups but new ones may be
  * created as a result of offset adjustments.
  */
 static void
 ino_add_ref(struct suj_ino *sino, struct suj_rec *srec)
 {
 	struct jrefrec *refrec;
 	struct suj_rec *srn;
 	struct jrefrec *rrn;
 
 	refrec = (struct jrefrec *)srec->sr_rec;
 	/*
 	 * We walk backwards so that the oldest link count is preserved.  If
 	 * an add record conflicts with a remove keep the remove.  Redundant
 	 * removes are eliminated in ino_build_ref.  Otherwise we keep the
 	 * oldest record at a given location.
 	 */
 	for (srn = TAILQ_LAST(&sino->si_recs, srechd); srn;
 	    srn = TAILQ_PREV(srn, srechd, sr_next)) {
 		rrn = (struct jrefrec *)srn->sr_rec;
 		if (rrn->jr_parent != refrec->jr_parent ||
 		    rrn->jr_diroff != refrec->jr_diroff)
 			continue;
 		if (rrn->jr_op == JOP_REMREF || refrec->jr_op == JOP_ADDREF) {
 			rrn->jr_mode = refrec->jr_mode;
 			return;
 		}
 		/*
 		 * Adding a remove.
 		 *
 		 * Replace the record in place with the old nlink in case
 		 * we replace the head of the list.  Abandon srec as a dup.
 		 */
 		refrec->jr_nlink = rrn->jr_nlink;
 		srn->sr_rec = srec->sr_rec;
 		return;
 	}
 	TAILQ_INSERT_TAIL(&sino->si_recs, srec, sr_next);
 }
 
 /*
  * Create a duplicate of a reference at a previous location.
  */
 static void
 ino_dup_ref(struct suj_ino *sino, struct jrefrec *refrec, off_t diroff)
 {
 	struct jrefrec *rrn;
 	struct suj_rec *srn;
 
 	rrn = errmalloc(sizeof(*refrec));
 	*rrn = *refrec;
 	rrn->jr_op = JOP_ADDREF;
 	rrn->jr_diroff = diroff;
 	srn = errmalloc(sizeof(*srn));
 	srn->sr_rec = (union jrec *)rrn;
 	ino_add_ref(sino, srn);
 }
 
 /*
  * Add a reference to the list at all known locations.  We follow the offset
  * changes for a single instance and create duplicate add refs at each so
  * that we can tolerate any version of the directory block.  Eliminate
  * removes which collide with adds that are seen in the journal.  They should
  * not adjust the link count down.
  */
 static void
 ino_build_ref(struct suj_ino *sino, struct suj_rec *srec)
 {
 	struct jrefrec *refrec;
 	struct jmvrec *mvrec;
 	struct suj_rec *srp;
 	struct suj_rec *srn;
 	struct jrefrec *rrn;
 	off_t diroff;
 
 	refrec = (struct jrefrec *)srec->sr_rec;
 	/*
 	 * Search for a mvrec that matches this offset.  Whether it's an add
 	 * or a remove we can delete the mvref after creating a dup record in
 	 * the old location.
 	 */
 	if (!TAILQ_EMPTY(&sino->si_movs)) {
 		diroff = refrec->jr_diroff;
 		for (srn = TAILQ_LAST(&sino->si_movs, srechd); srn; srn = srp) {
 			srp = TAILQ_PREV(srn, srechd, sr_next);
 			mvrec = (struct jmvrec *)srn->sr_rec;
 			if (mvrec->jm_parent != refrec->jr_parent ||
 			    mvrec->jm_newoff != diroff)
 				continue;
 			diroff = mvrec->jm_oldoff;
 			TAILQ_REMOVE(&sino->si_movs, srn, sr_next);
 			free(srn);
 			ino_dup_ref(sino, refrec, diroff);
 		}
 	}
 	/*
 	 * If a remove wasn't eliminated by an earlier add just append it to
 	 * the list.
 	 */
 	if (refrec->jr_op == JOP_REMREF) {
 		ino_add_ref(sino, srec);
 		return;
 	}
 	/*
 	 * Walk the list of records waiting to be added to the list.  We
 	 * must check for moves that apply to our current offset and remove
 	 * them from the list.  Remove any duplicates to eliminate removes
 	 * with corresponding adds.
 	 */
 	TAILQ_FOREACH_SAFE(srn, &sino->si_newrecs, sr_next, srp) {
 		switch (srn->sr_rec->rec_jrefrec.jr_op) {
 		case JOP_ADDREF:
 			/*
 			 * This should actually be an error we should
 			 * have a remove for every add journaled.
 			 */
 			rrn = (struct jrefrec *)srn->sr_rec;
 			if (rrn->jr_parent != refrec->jr_parent ||
 			    rrn->jr_diroff != refrec->jr_diroff)
 				break;
 			TAILQ_REMOVE(&sino->si_newrecs, srn, sr_next);
 			break;
 		case JOP_REMREF:
 			/*
 			 * Once we remove the current iteration of the
 			 * record at this address we're done.
 			 */
 			rrn = (struct jrefrec *)srn->sr_rec;
 			if (rrn->jr_parent != refrec->jr_parent ||
 			    rrn->jr_diroff != refrec->jr_diroff)
 				break;
 			TAILQ_REMOVE(&sino->si_newrecs, srn, sr_next);
 			ino_add_ref(sino, srec);
 			return;
 		case JOP_MVREF:
 			/*
 			 * Update our diroff based on any moves that match
 			 * and remove the move.
 			 */
 			mvrec = (struct jmvrec *)srn->sr_rec;
 			if (mvrec->jm_parent != refrec->jr_parent ||
 			    mvrec->jm_oldoff != refrec->jr_diroff)
 				break;
 			ino_dup_ref(sino, refrec, mvrec->jm_oldoff);
 			refrec->jr_diroff = mvrec->jm_newoff;
 			TAILQ_REMOVE(&sino->si_newrecs, srn, sr_next);
 			break;
 		default:
 			err_suj("ino_build_ref: Unknown op %d\n",
 			    srn->sr_rec->rec_jrefrec.jr_op);
 		}
 	}
 	ino_add_ref(sino, srec);
 }
 
 /*
  * Walk the list of new records and add them in-order resolving any
  * dups and adjusted offsets.
  */
 static void
 ino_build(struct suj_ino *sino)
 {
 	struct suj_rec *srec;
 
 	while ((srec = TAILQ_FIRST(&sino->si_newrecs)) != NULL) {
 		TAILQ_REMOVE(&sino->si_newrecs, srec, sr_next);
 		switch (srec->sr_rec->rec_jrefrec.jr_op) {
 		case JOP_ADDREF:
 		case JOP_REMREF:
 			ino_build_ref(sino, srec);
 			break;
 		case JOP_MVREF:
 			/*
 			 * Add this mvrec to the queue of pending mvs.
 			 */
 			TAILQ_INSERT_TAIL(&sino->si_movs, srec, sr_next);
 			break;
 		default:
 			err_suj("ino_build: Unknown op %d\n",
 			    srec->sr_rec->rec_jrefrec.jr_op);
 		}
 	}
 	if (TAILQ_EMPTY(&sino->si_recs))
 		sino->si_hasrecs = 0;
 }
 
 /*
  * Modify journal records so they refer to the base block number
  * and a start and end frag range.  This is to facilitate the discovery
  * of overlapping fragment allocations.
  */
 static void
 blk_build(struct jblkrec *blkrec)
 {
 	struct suj_rec *srec;
 	struct suj_blk *sblk;
 	struct jblkrec *blkrn;
 	ufs2_daddr_t blk;
 	int frag;
 
 	if (debug)
 		printf("blk_build: op %d blkno %jd frags %d oldfrags %d "
 		    "ino %ju lbn %jd\n",
 		    blkrec->jb_op, (uintmax_t)blkrec->jb_blkno,
 		    blkrec->jb_frags, blkrec->jb_oldfrags,
 		    (uintmax_t)blkrec->jb_ino, (uintmax_t)blkrec->jb_lbn);
 
 	blk = blknum(fs, blkrec->jb_blkno);
 	frag = fragnum(fs, blkrec->jb_blkno);
 	sblk = blk_lookup(blk, 1);
 	/*
 	 * Rewrite the record using oldfrags to indicate the offset into
 	 * the block.  Leave jb_frags as the actual allocated count.
 	 */
 	blkrec->jb_blkno -= frag;
 	blkrec->jb_oldfrags = frag;
 	if (blkrec->jb_oldfrags + blkrec->jb_frags > fs->fs_frag)
 		err_suj("Invalid fragment count %d oldfrags %d\n",
 		    blkrec->jb_frags, frag);
 	/*
 	 * Detect dups.  If we detect a dup we always discard the oldest
 	 * record as it is superseded by the new record.  This speeds up
 	 * later stages but also eliminates free records which are used
 	 * to indicate that the contents of indirects can be trusted.
 	 */
 	TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) {
 		blkrn = (struct jblkrec *)srec->sr_rec;
 		if (blkrn->jb_ino != blkrec->jb_ino ||
 		    blkrn->jb_lbn != blkrec->jb_lbn ||
 		    blkrn->jb_blkno != blkrec->jb_blkno ||
 		    blkrn->jb_frags != blkrec->jb_frags ||
 		    blkrn->jb_oldfrags != blkrec->jb_oldfrags)
 			continue;
 		if (debug)
 			printf("Removed dup.\n");
 		/* Discard the free which is a dup with an alloc. */
 		if (blkrec->jb_op == JOP_FREEBLK)
 			return;
 		TAILQ_REMOVE(&sblk->sb_recs, srec, sr_next);
 		free(srec);
 		break;
 	}
 	srec = errmalloc(sizeof(*srec));
 	srec->sr_rec = (union jrec *)blkrec;
 	TAILQ_INSERT_TAIL(&sblk->sb_recs, srec, sr_next);
 }
 
 static void
 ino_build_trunc(struct jtrncrec *rec)
 {
 	struct suj_ino *sino;
 
 	if (debug)
 		printf("ino_build_trunc: op %d ino %ju, size %jd\n",
 		    rec->jt_op, (uintmax_t)rec->jt_ino,
 		    (uintmax_t)rec->jt_size);
 	sino = ino_lookup(rec->jt_ino, 1);
 	if (rec->jt_op == JOP_SYNC) {
 		sino->si_trunc = NULL;
 		return;
 	}
 	if (sino->si_trunc == NULL || sino->si_trunc->jt_size > rec->jt_size)
 		sino->si_trunc = rec;
 }
 
 /*
  * Build up tables of the operations we need to recover.
  */
 static void
 suj_build(void)
 {
 	struct suj_seg *seg;
 	union jrec *rec;
 	int off;
 	int i;
 
 	TAILQ_FOREACH(seg, &allsegs, ss_next) {
 		if (debug)
 			printf("seg %jd has %d records, oldseq %jd.\n",
 			    seg->ss_rec.jsr_seq, seg->ss_rec.jsr_cnt,
 			    seg->ss_rec.jsr_oldest);
 		off = 0;
 		rec = (union jrec *)seg->ss_blk;
 		for (i = 0; i < seg->ss_rec.jsr_cnt; off += JREC_SIZE, rec++) {
 			/* skip the segrec. */
 			if ((off % real_dev_bsize) == 0)
 				continue;
 			switch (rec->rec_jrefrec.jr_op) {
 			case JOP_ADDREF:
 			case JOP_REMREF:
 			case JOP_MVREF:
 				ino_append(rec);
 				break;
 			case JOP_NEWBLK:
 			case JOP_FREEBLK:
 				blk_build((struct jblkrec *)rec);
 				break;
 			case JOP_TRUNC:
 			case JOP_SYNC:
 				ino_build_trunc((struct jtrncrec *)rec);
 				break;
 			default:
 				err_suj("Unknown journal operation %d (%d)\n",
 				    rec->rec_jrefrec.jr_op, off);
 			}
 			i++;
 		}
 	}
 }
 
 /*
  * Prune the journal segments to those we care about based on the
  * oldest sequence in the newest segment.  Order the segment list
  * based on sequence number.
  */
 static void
 suj_prune(void)
 {
 	struct suj_seg *seg;
 	struct suj_seg *segn;
 	uint64_t newseq;
 	int discard;
 
 	if (debug)
 		printf("Pruning up to %jd\n", oldseq);
 	/* First free the expired segments. */
 	TAILQ_FOREACH_SAFE(seg, &allsegs, ss_next, segn) {
 		if (seg->ss_rec.jsr_seq >= oldseq)
 			continue;
 		TAILQ_REMOVE(&allsegs, seg, ss_next);
 		free(seg->ss_blk);
 		free(seg);
 	}
 	/* Next ensure that segments are ordered properly. */
 	seg = TAILQ_FIRST(&allsegs);
 	if (seg == NULL) {
 		if (debug)
 			printf("Empty journal\n");
 		return;
 	}
 	newseq = seg->ss_rec.jsr_seq;
 	for (;;) {
 		seg = TAILQ_LAST(&allsegs, seghd);
 		if (seg->ss_rec.jsr_seq >= newseq)
 			break;
 		TAILQ_REMOVE(&allsegs, seg, ss_next);
 		TAILQ_INSERT_HEAD(&allsegs, seg, ss_next);
 		newseq = seg->ss_rec.jsr_seq;
 
 	}
 	if (newseq != oldseq) {
 		TAILQ_FOREACH(seg, &allsegs, ss_next) {
 			printf("%jd, ", seg->ss_rec.jsr_seq);
 		}
 		printf("\n");
 		err_suj("Journal file sequence mismatch %jd != %jd\n",
 		    newseq, oldseq);
 	}
 	/*
 	 * The kernel may asynchronously write segments which can create
 	 * gaps in the sequence space.  Throw away any segments after the
 	 * gap as the kernel guarantees only those that are contiguously
 	 * reachable are marked as completed.
 	 */
 	discard = 0;
 	TAILQ_FOREACH_SAFE(seg, &allsegs, ss_next, segn) {
 		if (!discard && newseq++ == seg->ss_rec.jsr_seq) {
 			jrecs += seg->ss_rec.jsr_cnt;
 			jbytes += seg->ss_rec.jsr_blocks * real_dev_bsize;
 			continue;
 		}
 		discard = 1;
 		if (debug)
 			printf("Journal order mismatch %jd != %jd pruning\n",
 			    newseq-1, seg->ss_rec.jsr_seq);
 		TAILQ_REMOVE(&allsegs, seg, ss_next);
 		free(seg->ss_blk);
 		free(seg);
 	}
 	if (debug)
 		printf("Processing journal segments from %jd to %jd\n",
 		    oldseq, newseq-1);
 }
 
 /*
  * Verify the journal inode before attempting to read records.
  */
 static int
 suj_verifyino(union dinode *dp)
 {
 
 	if (DIP(dp, di_nlink) != 1) {
 		printf("Invalid link count %d for journal inode %ju\n",
 		    DIP(dp, di_nlink), (uintmax_t)sujino);
 		return (-1);
 	}
 
 	if ((DIP(dp, di_flags) & (SF_IMMUTABLE | SF_NOUNLINK)) !=
 	    (SF_IMMUTABLE | SF_NOUNLINK)) {
 		printf("Invalid flags 0x%X for journal inode %ju\n",
 		    DIP(dp, di_flags), (uintmax_t)sujino);
 		return (-1);
 	}
 
 	if (DIP(dp, di_mode) != (IFREG | IREAD)) {
 		printf("Invalid mode %o for journal inode %ju\n",
 		    DIP(dp, di_mode), (uintmax_t)sujino);
 		return (-1);
 	}
 
 	if (DIP(dp, di_size) < SUJ_MIN) {
 		printf("Invalid size %jd for journal inode %ju\n",
 		    DIP(dp, di_size), (uintmax_t)sujino);
 		return (-1);
 	}
 
 	if (DIP(dp, di_modrev) != fs->fs_mtime) {
 		printf("Journal timestamp does not match fs mount time\n");
 		return (-1);
 	}
 
 	return (0);
 }
 
 struct jblocks {
 	struct jextent *jb_extent;	/* Extent array. */
 	int		jb_avail;	/* Available extents. */
 	int		jb_used;	/* Last used extent. */
 	int		jb_head;	/* Allocator head. */
 	int		jb_off;		/* Allocator extent offset. */
 };
 struct jextent {
 	ufs2_daddr_t	je_daddr;	/* Disk block address. */
 	int		je_blocks;	/* Disk block count. */
 };
 
 static struct jblocks *suj_jblocks;
 
 static struct jblocks *
 jblocks_create(void)
 {
 	struct jblocks *jblocks;
 	int size;
 
 	jblocks = errmalloc(sizeof(*jblocks));
 	jblocks->jb_avail = 10;
 	jblocks->jb_used = 0;
 	jblocks->jb_head = 0;
 	jblocks->jb_off = 0;
 	size = sizeof(struct jextent) * jblocks->jb_avail;
 	jblocks->jb_extent = errmalloc(size);
 	bzero(jblocks->jb_extent, size);
 
 	return (jblocks);
 }
 
 /*
  * Return the next available disk block and the amount of contiguous
  * free space it contains.
  */
 static ufs2_daddr_t
 jblocks_next(struct jblocks *jblocks, int bytes, int *actual)
 {
 	struct jextent *jext;
 	ufs2_daddr_t daddr;
 	int freecnt;
 	int blocks;
 
 	blocks = btodb(bytes);
 	jext = &jblocks->jb_extent[jblocks->jb_head];
 	freecnt = jext->je_blocks - jblocks->jb_off;
 	if (freecnt == 0) {
 		jblocks->jb_off = 0;
 		if (++jblocks->jb_head > jblocks->jb_used)
 			return (0);
 		jext = &jblocks->jb_extent[jblocks->jb_head];
 		freecnt = jext->je_blocks;
 	}
 	if (freecnt > blocks)
 		freecnt = blocks;
 	*actual = dbtob(freecnt);
 	daddr = jext->je_daddr + jblocks->jb_off;
 
 	return (daddr);
 }
 
 /*
  * Advance the allocation head by a specified number of bytes, consuming
  * one journal segment.
  */
 static void
 jblocks_advance(struct jblocks *jblocks, int bytes)
 {
 
 	jblocks->jb_off += btodb(bytes);
 }
 
 static void
 jblocks_destroy(struct jblocks *jblocks)
 {
 
 	free(jblocks->jb_extent);
 	free(jblocks);
 }
 
 static void
 jblocks_add(struct jblocks *jblocks, ufs2_daddr_t daddr, int blocks)
 {
 	struct jextent *jext;
 	int size;
 
 	jext = &jblocks->jb_extent[jblocks->jb_used];
 	/* Adding the first block. */
 	if (jext->je_daddr == 0) {
 		jext->je_daddr = daddr;
 		jext->je_blocks = blocks;
 		return;
 	}
 	/* Extending the last extent. */
 	if (jext->je_daddr + jext->je_blocks == daddr) {
 		jext->je_blocks += blocks;
 		return;
 	}
 	/* Adding a new extent. */
 	if (++jblocks->jb_used == jblocks->jb_avail) {
 		jblocks->jb_avail *= 2;
 		size = sizeof(struct jextent) * jblocks->jb_avail;
 		jext = errmalloc(size);
 		bzero(jext, size);
 		bcopy(jblocks->jb_extent, jext,
 		    sizeof(struct jextent) * jblocks->jb_used);
 		free(jblocks->jb_extent);
 		jblocks->jb_extent = jext;
 	}
 	jext = &jblocks->jb_extent[jblocks->jb_used];
 	jext->je_daddr = daddr;
 	jext->je_blocks = blocks;
 
 	return;
 }
 
 /*
  * Add a file block from the journal to the extent map.  We can't read
  * each file block individually because the kernel treats it as a circular
  * buffer and segments may span mutliple contiguous blocks.
  */
 static void
 suj_add_block(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
 {
 
 	jblocks_add(suj_jblocks, fsbtodb(fs, blk), fsbtodb(fs, frags));
 }
 
 static void
 suj_read(void)
 {
 	uint8_t block[1 * 1024 * 1024];
 	struct suj_seg *seg;
 	struct jsegrec *recn;
 	struct jsegrec *rec;
 	ufs2_daddr_t blk;
 	int readsize;
 	int blocks;
 	int recsize;
 	int size;
 	int i;
 
 	/*
 	 * Read records until we exhaust the journal space.  If we find
 	 * an invalid record we start searching for a valid segment header
 	 * at the next block.  This is because we don't have a head/tail
 	 * pointer and must recover the information indirectly.  At the gap
 	 * between the head and tail we won't necessarily have a valid
 	 * segment.
 	 */
 restart:
 	for (;;) {
 		size = sizeof(block);
 		blk = jblocks_next(suj_jblocks, size, &readsize);
 		if (blk == 0)
 			return;
 		size = readsize;
 		/*
 		 * Read 1MB at a time and scan for records within this block.
 		 */
 		if (pread(fsreadfd, &block, size, dbtob(blk)) != size) {
 			err_suj("Error reading journal block %jd\n",
 			    (intmax_t)blk);
 		}
 		for (rec = (void *)block; size; size -= recsize,
 		    rec = (struct jsegrec *)((uintptr_t)rec + recsize)) {
 			recsize = real_dev_bsize;
 			if (rec->jsr_time != fs->fs_mtime) {
 #ifdef notdef
 				if (debug)
 					printf("Rec time %jd != fs mtime %jd\n",
 					    rec->jsr_time, fs->fs_mtime);
 #endif
 				jblocks_advance(suj_jblocks, recsize);
 				continue;
 			}
 			if (rec->jsr_cnt == 0) {
 				if (debug)
 					printf("Found illegal count %d\n",
 					    rec->jsr_cnt);
 				jblocks_advance(suj_jblocks, recsize);
 				continue;
 			}
 			blocks = rec->jsr_blocks;
 			recsize = blocks * real_dev_bsize;
 			if (recsize > size) {
 				/*
 				 * We may just have run out of buffer, restart
 				 * the loop to re-read from this spot.
 				 */
 				if (size < fs->fs_bsize &&
 				    size != readsize &&
 				    recsize <= fs->fs_bsize)
 					goto restart;
 				if (debug)
 					printf("Found invalid segsize %d > %d\n",
 					    recsize, size);
 				recsize = real_dev_bsize;
 				jblocks_advance(suj_jblocks, recsize);
 				continue;
 			}
 			/*
 			 * Verify that all blocks in the segment are present.
 			 */
 			for (i = 1; i < blocks; i++) {
 				recn = (void *)((uintptr_t)rec) + i *
 				    real_dev_bsize;
 				if (recn->jsr_seq == rec->jsr_seq &&
 				    recn->jsr_time == rec->jsr_time)
 					continue;
 				if (debug)
 					printf("Incomplete record %jd (%d)\n",
 					    rec->jsr_seq, i);
 				recsize = i * real_dev_bsize;
 				jblocks_advance(suj_jblocks, recsize);
 				goto restart;
 			}
 			seg = errmalloc(sizeof(*seg));
 			seg->ss_blk = errmalloc(recsize);
 			seg->ss_rec = *rec;
 			bcopy((void *)rec, seg->ss_blk, recsize);
 			if (rec->jsr_oldest > oldseq)
 				oldseq = rec->jsr_oldest;
 			TAILQ_INSERT_TAIL(&allsegs, seg, ss_next);
 			jblocks_advance(suj_jblocks, recsize);
 		}
 	}
 }
 
 /*
  * Orchestrate the verification of a filesystem via the softupdates journal.
  */
 int
 suj_check(const char *filesys)
 {
 	struct inodesc idesc;
 	struct csum *cgsum;
 	union dinode *jip;
 	struct inode ip;
 	uint64_t blocks;
 	int i, retval;
 	struct suj_seg *seg;
 	struct suj_seg *segn;
 
 	initsuj();
 	fs = &sblock;
 	if (real_dev_bsize == 0 && ioctl(fsreadfd, DIOCGSECTORSIZE,
 	    &real_dev_bsize) == -1)
 		real_dev_bsize = secsize;
 	if (debug)
 		printf("dev_bsize %u\n", real_dev_bsize);
 
 	/*
 	 * Set an exit point when SUJ check failed
 	 */
 	retval = setjmp(jmpbuf);
 	if (retval != 0) {
 		pwarn("UNEXPECTED SU+J INCONSISTENCY\n");
 		TAILQ_FOREACH_SAFE(seg, &allsegs, ss_next, segn) {
 			TAILQ_REMOVE(&allsegs, seg, ss_next);
 				free(seg->ss_blk);
 				free(seg);
 		}
 		if (reply("FALLBACK TO FULL FSCK") == 0) {
 			ckfini(0);
 			exit(EEXIT);
 		} else
 			return (-1);
 	}
 
 	/*
 	 * Search the root directory for the SUJ_FILE.
 	 */
 	idesc.id_type = DATA;
 	idesc.id_fix = IGNORE;
 	idesc.id_number = UFS_ROOTINO;
 	idesc.id_func = findino;
 	idesc.id_name = SUJ_FILE;
 	ginode(UFS_ROOTINO, &ip);
 	if ((ckinode(ip.i_dp, &idesc) & FOUND) == FOUND) {
 		sujino = idesc.id_parent;
 		irelse(&ip);
 	} else {
 		printf("Journal inode removed.  Use tunefs to re-create.\n");
 		sblock.fs_flags &= ~FS_SUJ;
 		sblock.fs_sujfree = 0;
 		irelse(&ip);
 		return (-1);
 	}
 	/*
 	 * Fetch the journal inode and verify it.
 	 */
 	ginode(sujino, &ip);
 	jip = ip.i_dp;
 	printf("** SU+J Recovering %s\n", filesys);
 	if (suj_verifyino(jip) != 0 || (!preen && !reply("USE JOURNAL"))) {
 		irelse(&ip);
 		return (-1);
 	}
 	/*
 	 * Build a list of journal blocks in jblocks before parsing the
 	 * available journal blocks in with suj_read().
 	 */
 	printf("** Reading %jd byte journal from inode %ju.\n",
 	    DIP(jip, di_size), (uintmax_t)sujino);
 	suj_jblocks = jblocks_create();
 	blocks = ino_visit(jip, sujino, suj_add_block, 0);
 	if (blocks != numfrags(fs, DIP(jip, di_size))) {
 		printf("Sparse journal inode %ju.\n", (uintmax_t)sujino);
 		irelse(&ip);
 		return (-1);
 	}
 	irelse(&ip);
 	suj_read();
 	jblocks_destroy(suj_jblocks);
 	suj_jblocks = NULL;
 	if (preen || reply("RECOVER")) {
 		printf("** Building recovery table.\n");
 		suj_prune();
 		suj_build();
 		cg_apply(cg_build);
 		printf("** Resolving unreferenced inode list.\n");
 		ino_unlinked();
 		printf("** Processing journal entries.\n");
 		cg_apply(cg_trunc);
 		cg_apply(cg_check_blk);
 		cg_apply(cg_adj_blk);
 		cg_apply(cg_check_ino);
 	}
 	if (preen == 0 && (jrecs > 0 || jbytes > 0) && reply("WRITE CHANGES") == 0)
 		return (0);
 	/*
 	 * Recompute the fs summary info from correct cs summaries.
 	 */
 	bzero(&fs->fs_cstotal, sizeof(struct csum_total));
 	for (i = 0; i < fs->fs_ncg; i++) {
 		cgsum = &fs->fs_cs(fs, i);
 		fs->fs_cstotal.cs_nffree += cgsum->cs_nffree;
 		fs->fs_cstotal.cs_nbfree += cgsum->cs_nbfree;
 		fs->fs_cstotal.cs_nifree += cgsum->cs_nifree;
 		fs->fs_cstotal.cs_ndir += cgsum->cs_ndir;
 	}
 	fs->fs_pendinginodes = 0;
 	fs->fs_pendingblocks = 0;
 	fs->fs_clean = 1;
 	fs->fs_time = time(NULL);
 	fs->fs_mtime = time(NULL);
 	sbdirty();
 	ckfini(1);
 	if (jrecs > 0 || jbytes > 0) {
 		printf("** %jd journal records in %jd bytes for %.2f%% utilization\n",
 		    jrecs, jbytes, ((float)jrecs / (float)(jbytes / JREC_SIZE)) * 100);
 		printf("** Freed %jd inodes (%jd dirs) %jd blocks, and %jd frags.\n",
 		    freeinos, freedir, freeblocks, freefrags);
 	}
 
 	return (0);
 }
 
 static void
 initsuj(void)
 {
 	int i;
 
 	for (i = 0; i < HASHSIZE; i++)
 		LIST_INIT(&cghash[i]);
 	lastcg = NULL;
 	TAILQ_INIT(&allsegs);
 	oldseq = 0;
 	fs = NULL;
 	sujino = 0;
 	freefrags = 0;
 	freeblocks = 0;
 	freeinos = 0;
 	freedir = 0;
 	jbytes = 0;
 	jrecs = 0;
 	suj_jblocks = NULL;
 }
diff --git a/sbin/mksnap_ffs/mksnap_ffs.c b/sbin/mksnap_ffs/mksnap_ffs.c
index 5d230701de85..0e3586fcb2e2 100644
--- a/sbin/mksnap_ffs/mksnap_ffs.c
+++ b/sbin/mksnap_ffs/mksnap_ffs.c
@@ -1,187 +1,191 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 2003 Networks Associates Technology, Inc.
  * All rights reserved.
  *
  * This software was developed for the FreeBSD Project by Marshall
  * Kirk McKusick and Network Associates Laboratories, the Security
  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
  * research program.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. The names of the authors may not be used to endorse or promote
  *    products derived from this software without specific prior written
  *    permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
+
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <grp.h>
 #include <limits.h>
 #include <mntopts.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
 
 static void
 usage(void)
 {
 
 	errx(EX_USAGE, "usage: mksnap_ffs snapshot_name");
 }
 
 static int
 isdir(const char *path, struct stat *stbufp)
 {
 
 	if (stat(path, stbufp) < 0)
 		return (-1);
         if (!S_ISDIR(stbufp->st_mode))
 		return (0);
 	return (1);
 }
 
 static int
 issamefs(const char *path, struct statfs *stfsp)
 {
 	struct statfs stfsbuf;
 	struct stat stbuf;
 
 	if (isdir(path, &stbuf) != 1)
 		return (-1);
 	if (statfs(path, &stfsbuf) < 0)
 		return (-1);
 	if (fsidcmp(&stfsbuf.f_fsid, &stfsp->f_fsid) != 0)
 		return (0);
 	return (1);
 }
 
 int
 main(int argc, char **argv)
 {
 	char errmsg[255], path[PATH_MAX];
 	char *cp, *snapname;
 	struct statfs stfsbuf;
 	struct group *grp;
 	struct stat stbuf;
 	struct iovec *iov;
 	int fd, iovlen;
 
 	if (argc == 2)
 		snapname = argv[1];
 	else if (argc == 3)
 		snapname = argv[2];	/* Old usage. */
 	else
 		usage();
 
 	/*
 	 * Check that the user running this program has permission
 	 * to create and remove a snapshot file from the directory
 	 * in which they have requested to have it made. If the 
 	 * directory is sticky and not owned by the user, then they
 	 * will not be able to remove the snapshot when they are
 	 * done with it.
 	 */
 	if (strlen(snapname) >= PATH_MAX)
 		errx(1, "pathname too long %s", snapname);
 	cp = strrchr(snapname, '/');
 	if (cp == NULL) {
 		strlcpy(path, ".", PATH_MAX);
 	} else if (cp == snapname) {
 		strlcpy(path, "/", PATH_MAX);
 	} else {
 		strlcpy(path, snapname, cp - snapname + 1);
 	}
 	if (statfs(path, &stfsbuf) < 0)
 		err(1, "%s", path);
 	switch (isdir(path, &stbuf)) {
 	case -1:
 		err(1, "%s", path);
 	case 0:
 		errx(1, "%s: Not a directory", path);
 	default:
 		break;
 	}
 	if (access(path, W_OK) < 0)
 		err(1, "Lack write permission in %s", path);
 	if ((stbuf.st_mode & S_ISTXT) && stbuf.st_uid != getuid())
 		errx(1, "Lack write permission in %s: Sticky bit set", path);
 
 	/*
 	 * Work around an issue when mksnap_ffs is started in chroot'ed
 	 * environment and f_mntonname contains absolute path within
 	 * real root.
 	 */
 	for (cp = stfsbuf.f_mntonname; issamefs(cp, &stfsbuf) != 1;
 	    cp = strchrnul(cp + 1, '/')) {
 		if (cp[0] == '\0')
 			errx(1, "%s: Not a mount point", stfsbuf.f_mntonname);
 	}
 	if (cp != stfsbuf.f_mntonname)
 		strlcpy(stfsbuf.f_mntonname, cp, sizeof(stfsbuf.f_mntonname));
 
 	/*
 	 * Having verified access to the directory in which the
 	 * snapshot is to be built, proceed with creating it.
 	 */
 	if ((grp = getgrnam("operator")) == NULL)
 		errx(1, "Cannot retrieve operator gid");
 
 	iov = NULL;
 	iovlen = 0;
 	build_iovec(&iov, &iovlen, "fstype", "ffs", 4);
 	build_iovec(&iov, &iovlen, "from", snapname, (size_t)-1);
 	build_iovec(&iov, &iovlen, "fspath", stfsbuf.f_mntonname, (size_t)-1);
 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
 	build_iovec(&iov, &iovlen, "update", NULL, 0);
 	build_iovec(&iov, &iovlen, "snapshot", NULL, 0);
 
 	*errmsg = '\0';
 	if (nmount(iov, iovlen, stfsbuf.f_flags) < 0) {
 		errmsg[sizeof(errmsg) - 1] = '\0';
 		err(1, "Cannot create snapshot %s%s%s", snapname,
 		    *errmsg != '\0' ? ": " : "", errmsg);
 	}
 	if ((fd = open(snapname, O_RDONLY)) < 0)
 		err(1, "Cannot open %s", snapname);
 	if (fstat(fd, &stbuf) != 0)
 		err(1, "Cannot stat %s", snapname);
 	if ((stbuf.st_flags & SF_SNAPSHOT) == 0)
 		errx(1, "File %s is not a snapshot", snapname);
 	if (fchown(fd, -1, grp->gr_gid) != 0)
 		err(1, "Cannot chown %s", snapname);
 	if (fchmod(fd, S_IRUSR | S_IRGRP) != 0)
 		err(1, "Cannot chmod %s", snapname);
 
 	exit(EXIT_SUCCESS);
 }
diff --git a/sbin/newfs/newfs.c b/sbin/newfs/newfs.c
index 232436c0aa7f..a2d97131d3a7 100644
--- a/sbin/newfs/newfs.c
+++ b/sbin/newfs/newfs.c
@@ -1,512 +1,514 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 2002 Networks Associates Technology, Inc.
  * All rights reserved.
  *
  * This software was developed for the FreeBSD Project by Marshall
  * Kirk McKusick and Network Associates Laboratories, the Security
  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
  * research program.
  *
  * Copyright (c) 1983, 1989, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #if 0
 #ifndef lint
 static const char copyright[] =
 "@(#) Copyright (c) 1983, 1989, 1993, 1994\n\
 	The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 static char sccsid[] = "@(#)newfs.c	8.13 (Berkeley) 5/1/95";
 #endif /* not lint */
 #endif
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 /*
  * newfs: friendly front end to mkfs
  */
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/disk.h>
 #include <sys/disklabel.h>
 #include <sys/file.h>
 #include <sys/mount.h>
 
 #include <ufs/ufs/dir.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <paths.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>
 
 #include <libutil.h>
 
 #include "newfs.h"
 
 int	Eflag;			/* Erase previous disk contents */
 int	Lflag;			/* add a volume label */
 int	Nflag;			/* run without writing file system */
 int	Oflag = 2;		/* file system format (1 => UFS1, 2 => UFS2) */
 int	Rflag;			/* regression test */
 int	Uflag;			/* enable soft updates for file system */
 int	jflag;			/* enable soft updates journaling for filesys */
 int	Xflag = 0;		/* exit in middle of newfs for testing */
 int	Jflag;			/* enable gjournal for file system */
 int	lflag;			/* enable multilabel for file system */
 int	nflag;			/* do not create .snap directory */
 int	tflag;			/* enable TRIM */
 intmax_t fssize;		/* file system size */
 off_t	mediasize;		/* device size */
 int	sectorsize;		/* bytes/sector */
 int	realsectorsize;		/* bytes/sector in hardware */
 int	fsize = 0;		/* fragment size */
 int	bsize = 0;		/* block size */
 int	maxbsize = 0;		/* maximum clustering */
 int	maxblkspercg = MAXBLKSPERCG; /* maximum blocks per cylinder group */
 int	minfree = MINFREE;	/* free space threshold */
 int	metaspace;		/* space held for metadata blocks */
 int	opt = DEFAULTOPT;	/* optimization preference (space or time) */
 int	density;		/* number of bytes per inode */
 int	maxcontig = 0;		/* max contiguous blocks to allocate */
 int	maxbpg;			/* maximum blocks per file in a cyl group */
 int	avgfilesize = AVFILESIZ;/* expected average file size */
 int	avgfilesperdir = AFPDIR;/* expected number of files per directory */
 u_char	*volumelabel = NULL;	/* volume label for filesystem */
 struct uufsd disk;		/* libufs disk structure */
 
 static char	device[MAXPATHLEN];
 static u_char   bootarea[BBSIZE];
 static int	is_file;		/* work on a file, not a device */
 static char	*dkname;
 static char	*disktype;
 
 static void getfssize(intmax_t *, const char *p, intmax_t, intmax_t);
 static struct disklabel *getdisklabel(void);
 static void usage(void);
 static int expand_number_int(const char *buf, int *num);
 
 ufs2_daddr_t part_ofs; /* partition offset in blocks, used with files */
 
 int
 main(int argc, char *argv[])
 {
 	struct partition *pp;
 	struct disklabel *lp;
 	struct stat st;
 	char *cp, *special;
 	intmax_t reserved;
 	int ch, i, rval;
 	char part_name;		/* partition name, default to full disk */
 
 	part_name = 'c';
 	reserved = 0;
 	while ((ch = getopt(argc, argv,
 	    "EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:jk:lm:no:p:r:s:t")) != -1)
 		switch (ch) {
 		case 'E':
 			Eflag = 1;
 			break;
 		case 'J':
 			Jflag = 1;
 			break;
 		case 'L':
 			volumelabel = optarg;
 			i = -1;
 			while (isalnum(volumelabel[++i]) ||
 			    volumelabel[i] == '_' || volumelabel[i] == '-');
 			if (volumelabel[i] != '\0') {
 				errx(1, "bad volume label. Valid characters "
 				    "are alphanumerics, dashes, and underscores.");
 			}
 			if (strlen(volumelabel) >= MAXVOLLEN) {
 				errx(1, "bad volume label. Length is longer than %d.",
 				    MAXVOLLEN);
 			}
 			Lflag = 1;
 			break;
 		case 'N':
 			Nflag = 1;
 			break;
 		case 'O':
 			if ((Oflag = atoi(optarg)) < 1 || Oflag > 2)
 				errx(1, "%s: bad file system format value",
 				    optarg);
 			break;
 		case 'R':
 			Rflag = 1;
 			break;
 		case 'S':
 			rval = expand_number_int(optarg, &sectorsize);
 			if (rval < 0 || sectorsize <= 0)
 				errx(1, "%s: bad sector size", optarg);
 			break;
 		case 'T':
 			disktype = optarg;
 			break;
 		case 'j':
 			jflag = 1;
 			/* fall through to enable soft updates */
 			/* FALLTHROUGH */
 		case 'U':
 			Uflag = 1;
 			break;
 		case 'X':
 			Xflag++;
 			break;
 		case 'a':
 			rval = expand_number_int(optarg, &maxcontig);
 			if (rval < 0 || maxcontig <= 0)
 				errx(1, "%s: bad maximum contiguous blocks",
 				    optarg);
 			break;
 		case 'b':
 			rval = expand_number_int(optarg, &bsize);
 			if (rval < 0)
 				 errx(1, "%s: bad block size",
                                     optarg);
 			if (bsize < MINBSIZE)
 				errx(1, "%s: block size too small, min is %d",
 				    optarg, MINBSIZE);
 			if (bsize > MAXBSIZE)
 				errx(1, "%s: block size too large, max is %d",
 				    optarg, MAXBSIZE);
 			break;
 		case 'c':
 			rval = expand_number_int(optarg, &maxblkspercg);
 			if (rval < 0 || maxblkspercg <= 0)
 				errx(1, "%s: bad blocks per cylinder group",
 				    optarg);
 			break;
 		case 'd':
 			rval = expand_number_int(optarg, &maxbsize);
 			if (rval < 0 || maxbsize < MINBSIZE)
 				errx(1, "%s: bad extent block size", optarg);
 			break;
 		case 'e':
 			rval = expand_number_int(optarg, &maxbpg);
 			if (rval < 0 || maxbpg <= 0)
 			  errx(1, "%s: bad blocks per file in a cylinder group",
 				    optarg);
 			break;
 		case 'f':
 			rval = expand_number_int(optarg, &fsize);
 			if (rval < 0 || fsize <= 0)
 				errx(1, "%s: bad fragment size", optarg);
 			break;
 		case 'g':
 			rval = expand_number_int(optarg, &avgfilesize);
 			if (rval < 0 || avgfilesize <= 0)
 				errx(1, "%s: bad average file size", optarg);
 			break;
 		case 'h':
 			rval = expand_number_int(optarg, &avgfilesperdir);
 			if (rval < 0 || avgfilesperdir <= 0)
 			       errx(1, "%s: bad average files per dir", optarg);
 			break;
 		case 'i':
 			rval = expand_number_int(optarg, &density);
 			if (rval < 0 || density <= 0)
 				errx(1, "%s: bad bytes per inode", optarg);
 			break;
 		case 'l':
 			lflag = 1;
 			break;
 		case 'k':
 			if ((metaspace = atoi(optarg)) < 0)
 				errx(1, "%s: bad metadata space %%", optarg);
 			if (metaspace == 0)
 				/* force to stay zero in mkfs */
 				metaspace = -1;
 			break;
 		case 'm':
 			if ((minfree = atoi(optarg)) < 0 || minfree > 99)
 				errx(1, "%s: bad free space %%", optarg);
 			break;
 		case 'n':
 			nflag = 1;
 			break;
 		case 'o':
 			if (strcmp(optarg, "space") == 0)
 				opt = FS_OPTSPACE;
 			else if (strcmp(optarg, "time") == 0)
 				opt = FS_OPTTIME;
 			else
 				errx(1, 
 		"%s: unknown optimization preference: use `space' or `time'",
 				    optarg);
 			break;
 		case 'r':
 			errno = 0;
 			reserved = strtoimax(optarg, &cp, 0);
 			if (errno != 0 || cp == optarg ||
 			    *cp != '\0' || reserved < 0)
 				errx(1, "%s: bad reserved size", optarg);
 			break;
 		case 'p':
 			is_file = 1;
 			part_name = optarg[0];
 			break;
 
 		case 's':
 			errno = 0;
 			fssize = strtoimax(optarg, &cp, 0);
 			if (errno != 0 || cp == optarg ||
 			    *cp != '\0' || fssize < 0)
 				errx(1, "%s: bad file system size", optarg);
 			break;
 		case 't':
 			tflag = 1;
 			break;
 		case '?':
 		default:
 			usage();
 		}
 	argc -= optind;
 	argv += optind;
 
 	if (argc != 1)
 		usage();
 
 	special = argv[0];
 	if (!special[0])
 		err(1, "empty file/special name");
 	cp = strrchr(special, '/');
 	if (cp == NULL) {
 		/*
 		 * No path prefix; try prefixing _PATH_DEV.
 		 */
 		snprintf(device, sizeof(device), "%s%s", _PATH_DEV, special);
 		special = device;
 	}
 
 	if (is_file) {
 		/* bypass ufs_disk_fillout_blank */
 		bzero( &disk, sizeof(disk));
 		disk.d_bsize = 1;
 		disk.d_name = special;
 		disk.d_fd = open(special, O_RDONLY);
 		if (disk.d_fd < 0 ||
 		    (!Nflag && ufs_disk_write(&disk) == -1))
 			errx(1, "%s: ", special);
 	} else if (ufs_disk_fillout_blank(&disk, special) == -1 ||
 	    (!Nflag && ufs_disk_write(&disk) == -1)) {
 		if (disk.d_error != NULL)
 			errx(1, "%s: %s", special, disk.d_error);
 		else
 			err(1, "%s", special);
 	}
 	if (fstat(disk.d_fd, &st) < 0)
 		err(1, "%s", special);
 	if ((st.st_mode & S_IFMT) != S_IFCHR) {
 		warn("%s: not a character-special device", special);
 		is_file = 1;	/* assume it is a file */
 		dkname = special;
 		if (sectorsize == 0)
 			sectorsize = 512;
 		mediasize = st.st_size;
 		/* set fssize from the partition */
 	} else {
 	    if (sectorsize == 0)
 		if (ioctl(disk.d_fd, DIOCGSECTORSIZE, &sectorsize) == -1)
 		    sectorsize = 0;	/* back out on error for safety */
 	    if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1)
 		getfssize(&fssize, special, mediasize / sectorsize, reserved);
 	}
 	pp = NULL;
 	lp = getdisklabel();
 	if (lp != NULL) {
 		if (!is_file) /* already set for files */
 			part_name = special[strlen(special) - 1];
 		if ((part_name < 'a' || part_name - 'a' >= MAXPARTITIONS) &&
 				!isdigit(part_name))
 			errx(1, "%s: can't figure out file system partition",
 					special);
 		cp = &part_name;
 		if (isdigit(*cp))
 			pp = &lp->d_partitions[RAW_PART];
 		else
 			pp = &lp->d_partitions[*cp - 'a'];
 		if (pp->p_size == 0)
 			errx(1, "%s: `%c' partition is unavailable",
 			    special, *cp);
 		if (pp->p_fstype == FS_BOOT)
 			errx(1, "%s: `%c' partition overlaps boot program",
 			    special, *cp);
 		getfssize(&fssize, special, pp->p_size, reserved);
 		if (sectorsize == 0)
 			sectorsize = lp->d_secsize;
 		if (fsize == 0)
 			fsize = pp->p_fsize;
 		if (bsize == 0)
 			bsize = pp->p_frag * pp->p_fsize;
 		if (is_file)
 			part_ofs = pp->p_offset;
 	}
 	if (sectorsize <= 0)
 		errx(1, "%s: no default sector size", special);
 	if (fsize <= 0)
 		fsize = MAX(DFL_FRAGSIZE, sectorsize);
 	if (bsize <= 0)
 		bsize = MIN(DFL_BLKSIZE, 8 * fsize);
 	if (minfree < MINFREE && opt != FS_OPTSPACE) {
 		fprintf(stderr, "Warning: changing optimization to space ");
 		fprintf(stderr, "because minfree is less than %d%%\n", MINFREE);
 		opt = FS_OPTSPACE;
 	}
 	realsectorsize = sectorsize;
 	if (sectorsize != DEV_BSIZE) {		/* XXX */
 		int secperblk = sectorsize / DEV_BSIZE;
 
 		sectorsize = DEV_BSIZE;
 		fssize *= secperblk;
 		if (pp != NULL)
 			pp->p_size *= secperblk;
 	}
 	mkfs(pp, special);
 	ufs_disk_close(&disk);
 	if (!jflag)
 		exit(0);
 	if (execlp("tunefs", "newfs", "-j", "enable", special, NULL) < 0)
 		err(1, "Cannot enable soft updates journaling, tunefs");
 	/* NOT REACHED */
 }
 
 void
 getfssize(intmax_t *fsz, const char *s, intmax_t disksize, intmax_t reserved)
 {
 	intmax_t available;
 
 	available = disksize - reserved;
 	if (available <= 0)
 		errx(1, "%s: reserved not less than device size %jd",
 		    s, disksize);
 	if (*fsz == 0)
 		*fsz = available;
 	else if (*fsz > available)
 		errx(1, "%s: maximum file system size is %jd",
 		    s, available);
 }
 
 struct disklabel *
 getdisklabel(void)
 {
 	static struct disklabel lab;
 	struct disklabel *lp;
 
 	if (is_file) {
 		if (read(disk.d_fd, bootarea, BBSIZE) != BBSIZE)
 			err(4, "cannot read bootarea");
 		if (bsd_disklabel_le_dec(
 		    bootarea + (0 /* labeloffset */ +
 				1 /* labelsoffset */ * sectorsize),
 		    &lab, MAXPARTITIONS))
 			errx(1, "no valid label found");
 
 		lp = &lab;
 		return &lab;
 	}
 
 	if (disktype) {
 		lp = getdiskbyname(disktype);
 		if (lp != NULL)
 			return (lp);
 	}
 	return (NULL);
 }
 
 static void
 usage(void)
 {
 	fprintf(stderr,
 	    "usage: %s [ -fsoptions ] special-device%s\n",
 	    getprogname(),
 	    " [device-type]");
 	fprintf(stderr, "where fsoptions are:\n");
 	fprintf(stderr, "\t-E Erase previous disk content\n");
 	fprintf(stderr, "\t-J Enable journaling via gjournal\n");
 	fprintf(stderr, "\t-L volume label to add to superblock\n");
 	fprintf(stderr,
 	    "\t-N do not create file system, just print out parameters\n");
 	fprintf(stderr, "\t-O file system format: 1 => UFS1, 2 => UFS2\n");
 	fprintf(stderr, "\t-R regression test, suppress random factors\n");
 	fprintf(stderr, "\t-S sector size\n");
 	fprintf(stderr, "\t-T disktype\n");
 	fprintf(stderr, "\t-U enable soft updates\n");
 	fprintf(stderr, "\t-a maximum contiguous blocks\n");
 	fprintf(stderr, "\t-b block size\n");
 	fprintf(stderr, "\t-c blocks per cylinders group\n");
 	fprintf(stderr, "\t-d maximum extent size\n");
 	fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
 	fprintf(stderr, "\t-f frag size\n");
 	fprintf(stderr, "\t-g average file size\n");
 	fprintf(stderr, "\t-h average files per directory\n");
 	fprintf(stderr, "\t-i number of bytes per inode\n");
 	fprintf(stderr, "\t-j enable soft updates journaling\n");
 	fprintf(stderr, "\t-k space to hold for metadata blocks\n");
 	fprintf(stderr, "\t-l enable multilabel MAC\n");
 	fprintf(stderr, "\t-n do not create .snap directory\n");
 	fprintf(stderr, "\t-m minimum free space %%\n");
 	fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
 	fprintf(stderr, "\t-p partition name (a..h)\n");
 	fprintf(stderr, "\t-r reserved sectors at the end of device\n");
 	fprintf(stderr, "\t-s file system size (sectors)\n");
 	fprintf(stderr, "\t-t enable TRIM\n");
 	exit(1);
 }
 
 static int
 expand_number_int(const char *buf, int *num)
 {
 	int64_t num64;
 	int rval;
 
 	rval = expand_number(buf, &num64);
 	if (rval < 0)
 		return (rval);
 	if (num64 > INT_MAX || num64 < INT_MIN) {
 		errno = ERANGE;
 		return (-1);
 	}
 	*num = (int)num64;
 	return (0);
 }
diff --git a/sbin/tunefs/tunefs.c b/sbin/tunefs/tunefs.c
index 2eca8e0a3e36..e59b583ea58b 100644
--- a/sbin/tunefs/tunefs.c
+++ b/sbin/tunefs/tunefs.c
@@ -1,1140 +1,1142 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1983, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #if 0
 #ifndef lint
 static const char copyright[] =
 "@(#) Copyright (c) 1983, 1993\n\
 	The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 static char sccsid[] = "@(#)tunefs.c	8.2 (Berkeley) 4/19/94";
 #endif /* not lint */
 #endif
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 /*
  * tunefs: change layout parameters to an existing file system.
  */
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/disklabel.h>
 #include <sys/stat.h>
 
+#include <ufs/ufs/extattr.h>
+#include <ufs/ufs/quota.h>
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 #include <ufs/ufs/dir.h>
 
 #include <ctype.h>
 #include <err.h>
 #include <fcntl.h>
 #include <fstab.h>
 #include <libufs.h>
 #include <mntopts.h>
 #include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
 /* the optimization warning string template */
 #define	OPTWARN	"should optimize for %s with minfree %s %d%%"
 
 static int blocks;
 static char clrbuf[MAXBSIZE];
 static struct uufsd disk;
 #define	sblock disk.d_fs
 
 static void usage(void);
 static void printfs(void);
 static int journal_alloc(int64_t size);
 static void journal_clear(void);
 static void sbdirty(void);
 
 int
 main(int argc, char *argv[])
 {
 	const char *avalue, *jvalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue;
 	const char *tvalue;
 	const char *special, *on;
 	const char *name;
 	int active;
 	int Aflag, aflag, eflag, evalue, fflag, fvalue, jflag, Jflag, kflag;
 	int kvalue, Lflag, lflag, mflag, mvalue, Nflag, nflag, oflag, ovalue;
 	int pflag, sflag, svalue, Svalue, tflag;
 	int ch, found_arg, i;
 	int iovlen = 0;
 	const char *chg[2];
 	struct statfs stfs;
 	struct iovec *iov = NULL;
 	char errmsg[255] = {0};
 
 	if (argc < 3)
 		usage();
 	Aflag = aflag = eflag = fflag = jflag = Jflag = kflag = Lflag = 0;
 	lflag = mflag = Nflag = nflag = oflag = pflag = sflag = tflag = 0;
 	avalue = jvalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL;
 	evalue = fvalue = mvalue = ovalue = svalue = Svalue = 0;
 	active = 0;
 	found_arg = 0;		/* At least one arg is required. */
 	while ((ch = getopt(argc, argv, "Aa:e:f:j:J:k:L:l:m:N:n:o:ps:S:t:"))
 	    != -1)
 		switch (ch) {
 
 		case 'A':
 			found_arg++;
 			Aflag++;
 			break;
 
 		case 'a':
 			found_arg++;
 			name = "POSIX.1e ACLs";
 			avalue = optarg;
 			if (strcmp(avalue, "enable") &&
 			    strcmp(avalue, "disable")) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			aflag = 1;
 			break;
 
 		case 'e':
 			found_arg++;
 			name = "maximum blocks per file in a cylinder group";
 			evalue = atoi(optarg);
 			if (evalue < 1)
 				errx(10, "%s must be >= 1 (was %s)",
 				    name, optarg);
 			eflag = 1;
 			break;
 
 		case 'f':
 			found_arg++;
 			name = "average file size";
 			fvalue = atoi(optarg);
 			if (fvalue < 1)
 				errx(10, "%s must be >= 1 (was %s)",
 				    name, optarg);
 			fflag = 1;
 			break;
 
 		case 'j':
 			found_arg++;
 			name = "softdep journaled file system";
 			jvalue = optarg;
 			if (strcmp(jvalue, "enable") &&
 			    strcmp(jvalue, "disable")) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			jflag = 1;
 			break;
 
 		case 'J':
 			found_arg++;
 			name = "gjournaled file system";
 			Jvalue = optarg;
 			if (strcmp(Jvalue, "enable") &&
 			    strcmp(Jvalue, "disable")) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			Jflag = 1;
 			break;
 
 		case 'k':
 			found_arg++;
 			name = "space to hold for metadata blocks";
 			kvalue = atoi(optarg);
 			if (kvalue < 0)
 				errx(10, "bad %s (%s)", name, optarg);
 			kflag = 1;
 			break;
 
 		case 'L':
 			found_arg++;
 			name = "volume label";
 			Lvalue = optarg;
 			i = -1;
 			while (isalnum(Lvalue[++i]) || Lvalue[i] == '_' ||
 			    Lvalue[i] == '-')
 				;
 			if (Lvalue[i] != '\0') {
 				errx(10, "bad %s. Valid characters are "
 				    "alphanumerics, dashes, and underscores.",
 				    name);
 			}
 			if (strlen(Lvalue) >= MAXVOLLEN) {
 				errx(10, "bad %s. Length is longer than %d.",
 				    name, MAXVOLLEN - 1);
 			}
 			Lflag = 1;
 			break;
 
 		case 'l':
 			found_arg++;
 			name = "multilabel MAC file system";
 			lvalue = optarg;
 			if (strcmp(lvalue, "enable") &&
 			    strcmp(lvalue, "disable")) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			lflag = 1;
 			break;
 
 		case 'm':
 			found_arg++;
 			name = "minimum percentage of free space";
 			mvalue = atoi(optarg);
 			if (mvalue < 0 || mvalue > 99)
 				errx(10, "bad %s (%s)", name, optarg);
 			mflag = 1;
 			break;
 
 		case 'N':
 			found_arg++;
 			name = "NFSv4 ACLs";
 			Nvalue = optarg;
 			if (strcmp(Nvalue, "enable") &&
 			    strcmp(Nvalue, "disable")) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			Nflag = 1;
 			break;
 
 		case 'n':
 			found_arg++;
 			name = "soft updates";
 			nvalue = optarg;
 			if (strcmp(nvalue, "enable") != 0 &&
 			    strcmp(nvalue, "disable") != 0) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			nflag = 1;
 			break;
 
 		case 'o':
 			found_arg++;
 			name = "optimization preference";
 			if (strcmp(optarg, "space") == 0)
 				ovalue = FS_OPTSPACE;
 			else if (strcmp(optarg, "time") == 0)
 				ovalue = FS_OPTTIME;
 			else
 				errx(10,
 				    "bad %s (options are `space' or `time')",
 				    name);
 			oflag = 1;
 			break;
 
 		case 'p':
 			found_arg++;
 			pflag = 1;
 			break;
 
 		case 's':
 			found_arg++;
 			name = "expected number of files per directory";
 			svalue = atoi(optarg);
 			if (svalue < 1)
 				errx(10, "%s must be >= 1 (was %s)",
 				    name, optarg);
 			sflag = 1;
 			break;
 
 		case 'S':
 			found_arg++;
 			name = "Softdep Journal Size";
 			Svalue = atoi(optarg);
 			if (Svalue < SUJ_MIN)
 				errx(10, "%s must be >= %d (was %s)",
 				    name, SUJ_MIN, optarg);
 			break;
 
 		case 't':
 			found_arg++;
 			name = "trim";
 			tvalue = optarg;
 			if (strcmp(tvalue, "enable") != 0 &&
 			    strcmp(tvalue, "disable") != 0) {
 				errx(10, "bad %s (options are %s)",
 				    name, "`enable' or `disable'");
 			}
 			tflag = 1;
 			break;
 
 		default:
 			usage();
 		}
 	argc -= optind;
 	argv += optind;
 	if (found_arg == 0 || argc != 1)
 		usage();
 
 	on = special = argv[0];
 	if (ufs_disk_fillout(&disk, special) == -1)
 		goto err;
 	/*
 	 * Check for unclean filesystem.
 	 */
 	if ((sblock.fs_clean == 0 ||
 	    (sblock.fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) != 0) &&
 	    (found_arg > 1 || !pflag))
 		errx(1, "%s is not clean - run fsck.\n", special);
 	if (disk.d_name != special) {
 		if (statfs(special, &stfs) != 0)
 			warn("Can't stat %s", special);
 		if (strcmp(special, stfs.f_mntonname) == 0)
 			active = 1;
 	}
 
 	if (pflag) {
 		printfs();
 		exit(0);
 	}
 	if (Lflag) {
 		name = "volume label";
 		strncpy(sblock.fs_volname, Lvalue, MAXVOLLEN);
 	}
 	if (aflag) {
 		name = "POSIX.1e ACLs";
 		if (strcmp(avalue, "enable") == 0) {
 			if (sblock.fs_flags & FS_ACLS) {
 				warnx("%s remains unchanged as enabled", name);
 			} else if (sblock.fs_flags & FS_NFS4ACLS) {
 				warnx("%s and NFSv4 ACLs are mutually "
 				    "exclusive", name);
 			} else {
 				sblock.fs_flags |= FS_ACLS;
 				warnx("%s set", name);
 			}
 		} else if (strcmp(avalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_ACLS) ==
 			    FS_ACLS) {
 				warnx("%s remains unchanged as disabled",
 				    name);
 			} else {
 				sblock.fs_flags &= ~FS_ACLS;
 				warnx("%s cleared", name);
 			}
 		}
 	}
 	if (eflag) {
 		name = "maximum blocks per file in a cylinder group";
 		if (sblock.fs_maxbpg == evalue)
 			warnx("%s remains unchanged as %d", name, evalue);
 		else {
 			warnx("%s changes from %d to %d",
 			    name, sblock.fs_maxbpg, evalue);
 			sblock.fs_maxbpg = evalue;
 		}
 	}
 	if (fflag) {
 		name = "average file size";
 		if (sblock.fs_avgfilesize == (unsigned)fvalue) {
 			warnx("%s remains unchanged as %d", name, fvalue);
 		}
 		else {
 			warnx("%s changes from %d to %d",
 					name, sblock.fs_avgfilesize, fvalue);
 			sblock.fs_avgfilesize = fvalue;
 		}
 	}
 	if (jflag) {
  		name = "soft updates journaling";
  		if (strcmp(jvalue, "enable") == 0) {
 			if ((sblock.fs_flags & (FS_DOSOFTDEP | FS_SUJ)) ==
 			    (FS_DOSOFTDEP | FS_SUJ)) {
 				warnx("%s remains unchanged as enabled", name);
 			} else if (sblock.fs_clean == 0) {
 				warnx("%s cannot be enabled until fsck is run",
 				    name);
 			} else if (journal_alloc(Svalue) != 0) {
 				warnx("%s cannot be enabled", name);
 			} else {
  				sblock.fs_flags |= FS_DOSOFTDEP | FS_SUJ;
  				warnx("%s set", name);
 			}
  		} else if (strcmp(jvalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_SUJ) == FS_SUJ) {
 				warnx("%s remains unchanged as disabled", name);
 			} else {
 				journal_clear();
  				sblock.fs_flags &= ~FS_SUJ;
 				sblock.fs_sujfree = 0;
  				warnx("%s cleared but soft updates still set.",
 				    name);
 
 				warnx("remove .sujournal to reclaim space");
 			}
  		}
 	}
 	if (Jflag) {
 		name = "gjournal";
 		if (strcmp(Jvalue, "enable") == 0) {
 			if (sblock.fs_flags & FS_GJOURNAL) {
 				warnx("%s remains unchanged as enabled", name);
 			} else {
 				sblock.fs_flags |= FS_GJOURNAL;
 				warnx("%s set", name);
 			}
 		} else if (strcmp(Jvalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_GJOURNAL) ==
 			    FS_GJOURNAL) {
 				warnx("%s remains unchanged as disabled",
 				    name);
 			} else {
 				sblock.fs_flags &= ~FS_GJOURNAL;
 				warnx("%s cleared", name);
 			}
 		}
 	}
 	if (kflag) {
 		name = "space to hold for metadata blocks";
 		if (sblock.fs_metaspace == kvalue)
 			warnx("%s remains unchanged as %d", name, kvalue);
 		else {
 			kvalue = blknum(&sblock, kvalue);
 			if (kvalue > sblock.fs_fpg / 2) {
 				kvalue = blknum(&sblock, sblock.fs_fpg / 2);
 				warnx("%s cannot exceed half the file system "
 				    "space", name);
 			}
 			warnx("%s changes from %jd to %d",
 				    name, sblock.fs_metaspace, kvalue);
 			sblock.fs_metaspace = kvalue;
 		}
 	}
 	if (lflag) {
 		name = "multilabel";
 		if (strcmp(lvalue, "enable") == 0) {
 			if (sblock.fs_flags & FS_MULTILABEL) {
 				warnx("%s remains unchanged as enabled", name);
 			} else {
 				sblock.fs_flags |= FS_MULTILABEL;
 				warnx("%s set", name);
 			}
 		} else if (strcmp(lvalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_MULTILABEL) ==
 			    FS_MULTILABEL) {
 				warnx("%s remains unchanged as disabled",
 				    name);
 			} else {
 				sblock.fs_flags &= ~FS_MULTILABEL;
 				warnx("%s cleared", name);
 			}
 		}
 	}
 	if (mflag) {
 		name = "minimum percentage of free space";
 		if (sblock.fs_minfree == mvalue)
 			warnx("%s remains unchanged as %d%%", name, mvalue);
 		else {
 			warnx("%s changes from %d%% to %d%%",
 				    name, sblock.fs_minfree, mvalue);
 			sblock.fs_minfree = mvalue;
 			if (mvalue >= MINFREE && sblock.fs_optim == FS_OPTSPACE)
 				warnx(OPTWARN, "time", ">=", MINFREE);
 			if (mvalue < MINFREE && sblock.fs_optim == FS_OPTTIME)
 				warnx(OPTWARN, "space", "<", MINFREE);
 		}
 	}
 	if (Nflag) {
 		name = "NFSv4 ACLs";
 		if (strcmp(Nvalue, "enable") == 0) {
 			if (sblock.fs_flags & FS_NFS4ACLS) {
 				warnx("%s remains unchanged as enabled", name);
 			} else if (sblock.fs_flags & FS_ACLS) {
 				warnx("%s and POSIX.1e ACLs are mutually "
 				    "exclusive", name);
 			} else {
 				sblock.fs_flags |= FS_NFS4ACLS;
 				warnx("%s set", name);
 			}
 		} else if (strcmp(Nvalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_NFS4ACLS) ==
 			    FS_NFS4ACLS) {
 				warnx("%s remains unchanged as disabled",
 				    name);
 			} else {
 				sblock.fs_flags &= ~FS_NFS4ACLS;
 				warnx("%s cleared", name);
 			}
 		}
 	}
 	if (nflag) {
  		name = "soft updates";
  		if (strcmp(nvalue, "enable") == 0) {
 			if (sblock.fs_flags & FS_DOSOFTDEP)
 				warnx("%s remains unchanged as enabled", name);
 			else if (sblock.fs_clean == 0) {
 				warnx("%s cannot be enabled until fsck is run",
 				    name);
 			} else {
  				sblock.fs_flags |= FS_DOSOFTDEP;
  				warnx("%s set", name);
 			}
  		} else if (strcmp(nvalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_DOSOFTDEP) == FS_DOSOFTDEP)
 				warnx("%s remains unchanged as disabled", name);
 			else {
  				sblock.fs_flags &= ~FS_DOSOFTDEP;
  				warnx("%s cleared", name);
 			}
  		}
 	}
 	if (oflag) {
 		name = "optimization preference";
 		chg[FS_OPTSPACE] = "space";
 		chg[FS_OPTTIME] = "time";
 		if (sblock.fs_optim == ovalue)
 			warnx("%s remains unchanged as %s", name, chg[ovalue]);
 		else {
 			warnx("%s changes from %s to %s",
 				    name, chg[sblock.fs_optim], chg[ovalue]);
 			sblock.fs_optim = ovalue;
 			if (sblock.fs_minfree >= MINFREE &&
 			    ovalue == FS_OPTSPACE)
 				warnx(OPTWARN, "time", ">=", MINFREE);
 			if (sblock.fs_minfree < MINFREE && ovalue == FS_OPTTIME)
 				warnx(OPTWARN, "space", "<", MINFREE);
 		}
 	}
 	if (sflag) {
 		name = "expected number of files per directory";
 		if (sblock.fs_avgfpdir == (unsigned)svalue) {
 			warnx("%s remains unchanged as %d", name, svalue);
 		}
 		else {
 			warnx("%s changes from %d to %d",
 					name, sblock.fs_avgfpdir, svalue);
 			sblock.fs_avgfpdir = svalue;
 		}
 	}
 	if (tflag) {
 		name = "issue TRIM to the disk";
  		if (strcmp(tvalue, "enable") == 0) {
 			if (sblock.fs_flags & FS_TRIM)
 				warnx("%s remains unchanged as enabled", name);
 			else {
  				sblock.fs_flags |= FS_TRIM;
  				warnx("%s set", name);
 			}
  		} else if (strcmp(tvalue, "disable") == 0) {
 			if ((~sblock.fs_flags & FS_TRIM) == FS_TRIM)
 				warnx("%s remains unchanged as disabled", name);
 			else {
  				sblock.fs_flags &= ~FS_TRIM;
  				warnx("%s cleared", name);
 			}
  		}
 	}
 
 	if (sbwrite(&disk, Aflag) == -1)
 		goto err;
 	ufs_disk_close(&disk);
 	if (active) {
 		build_iovec_argf(&iov, &iovlen, "fstype", "ufs");
 		build_iovec_argf(&iov, &iovlen, "fspath", "%s", on);
 		build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
 		if (nmount(iov, iovlen,
 		    stfs.f_flags | MNT_UPDATE | MNT_RELOAD) < 0) {
 			if (errmsg[0])
 				err(9, "%s: reload: %s", special, errmsg);
 			else
 				err(9, "%s: reload", special);
 		}
 		warnx("file system reloaded");
 	}
 	exit(0);
 err:
 	if (disk.d_error != NULL)
 		errx(11, "%s: %s", special, disk.d_error);
 	else
 		err(12, "%s", special);
 }
 
 static void
 sbdirty(void)
 {
 	disk.d_fs.fs_flags |= FS_UNCLEAN | FS_NEEDSFSCK;
 	disk.d_fs.fs_clean = 0;
 }
 
 static ufs2_daddr_t
 journal_balloc(void)
 {
 	ufs2_daddr_t blk;
 	struct cg *cgp;
 	int valid;
 	static int contig = 1;
 
 	cgp = &disk.d_cg;
 	for (;;) {
 		blk = cgballoc(&disk);
 		if (blk > 0)
 			break;
 		/*
 		 * If we failed to allocate a block from this cg, move to
 		 * the next.
 		 */
 		if (cgwrite(&disk) < 0) {
 			warn("Failed to write updated cg");
 			return (-1);
 		}
 		while ((valid = cgread(&disk)) == 1) {
 			/*
 			 * Try to minimize fragmentation by requiring a minimum
 			 * number of blocks present.
 			 */
 			if (cgp->cg_cs.cs_nbfree > 256 * 1024)
 				break;
 			if (contig == 0 && cgp->cg_cs.cs_nbfree)
 				break;
 		}
 		if (valid)
 			continue;
 		/*
 		 * Try once through looking only for large contiguous regions
 		 * and again taking any space we can find.
 		 */
 		if (contig) {
 			contig = 0;
 			disk.d_ccg = 0;
 			warnx("Journal file fragmented.");
 			continue;
 		}
 		warnx("Failed to find sufficient free blocks for the journal");
 		return -1;
 	}
 	if (bwrite(&disk, fsbtodb(&sblock, blk), clrbuf,
 	    sblock.fs_bsize) <= 0) {
 		warn("Failed to initialize new block");
 		return -1;
 	}
 	return (blk);
 }
 
 /*
  * Search a directory block for the SUJ_FILE.
  */
 static ino_t
 dir_search(ufs2_daddr_t blk, int bytes)
 {
 	char block[MAXBSIZE];
 	struct direct *dp;
 	int off;
 
 	if (bread(&disk, fsbtodb(&sblock, blk), block, bytes) <= 0) {
 		warn("Failed to read dir block");
 		return (-1);
 	}
 	for (off = 0; off < bytes; off += dp->d_reclen) {
 		dp = (struct direct *)&block[off];
 		if (dp->d_reclen == 0)
 			break;
 		if (dp->d_ino == 0)
 			continue;
 		if (dp->d_namlen != strlen(SUJ_FILE))
 			continue;
 		if (bcmp(dp->d_name, SUJ_FILE, dp->d_namlen) != 0)
 			continue;
 		return (dp->d_ino);
 	}
 
 	return (0);
 }
 
 /*
  * Search in the UFS_ROOTINO for the SUJ_FILE.  If it exists we can not enable
  * journaling.
  */
 static ino_t
 journal_findfile(void)
 {
 	union dinodep dp;
 	ino_t ino;
 	int i;
 
 	if (getinode(&disk, &dp, UFS_ROOTINO) != 0) {
 		warn("Failed to get root inode: %s", disk.d_error);
 		return (-1);
 	}
 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
 		if ((off_t)dp.dp1->di_size >= lblktosize(&sblock, UFS_NDADDR)) {
 			warnx("UFS_ROOTINO extends beyond direct blocks.");
 			return (-1);
 		}
 		for (i = 0; i < UFS_NDADDR; i++) {
 			if (dp.dp1->di_db[i] == 0)
 				break;
 			if ((ino = dir_search(dp.dp1->di_db[i],
 			    sblksize(&sblock, (off_t)dp.dp1->di_size, i))) != 0)
 				return (ino);
 		}
 	} else {
 		if ((off_t)dp.dp2->di_size >= lblktosize(&sblock, UFS_NDADDR)) {
 			warnx("UFS_ROOTINO extends beyond direct blocks.");
 			return (-1);
 		}
 		for (i = 0; i < UFS_NDADDR; i++) {
 			if (dp.dp2->di_db[i] == 0)
 				break;
 			if ((ino = dir_search(dp.dp2->di_db[i],
 			    sblksize(&sblock, (off_t)dp.dp2->di_size, i))) != 0)
 				return (ino);
 		}
 	}
 
 	return (0);
 }
 
 static void
 dir_clear_block(const char *block, off_t off)
 {
 	struct direct *dp;
 
 	for (; off < sblock.fs_bsize; off += DIRBLKSIZ) {
 		dp = (struct direct *)&block[off];
 		dp->d_ino = 0;
 		dp->d_reclen = DIRBLKSIZ;
 		dp->d_type = DT_UNKNOWN;
 	}
 }
 
 /*
  * Insert the journal at inode 'ino' into directory blk 'blk' at the first
  * free offset of 'off'.  DIRBLKSIZ blocks after off are initialized as
  * empty.
  */
 static int
 dir_insert(ufs2_daddr_t blk, off_t off, ino_t ino)
 {
 	struct direct *dp;
 	char block[MAXBSIZE];
 
 	if (bread(&disk, fsbtodb(&sblock, blk), block, sblock.fs_bsize) <= 0) {
 		warn("Failed to read dir block");
 		return (-1);
 	}
 	bzero(&block[off], sblock.fs_bsize - off);
 	dp = (struct direct *)&block[off];
 	dp->d_ino = ino;
 	dp->d_reclen = DIRBLKSIZ;
 	dp->d_type = DT_REG;
 	dp->d_namlen = strlen(SUJ_FILE);
 	bcopy(SUJ_FILE, &dp->d_name, strlen(SUJ_FILE));
 	dir_clear_block(block, off + DIRBLKSIZ);
 	if (bwrite(&disk, fsbtodb(&sblock, blk), block, sblock.fs_bsize) <= 0) {
 		warn("Failed to write dir block");
 		return (-1);
 	}
 	return (0);
 }
 
 /*
  * Extend a directory block in 'blk' by copying it to a full size block
  * and inserting the new journal inode into .sujournal.
  */
 static int
 dir_extend(ufs2_daddr_t blk, ufs2_daddr_t nblk, off_t size, ino_t ino)
 {
 	char block[MAXBSIZE];
 
 	if (bread(&disk, fsbtodb(&sblock, blk), block,
 	    roundup(size, sblock.fs_fsize)) <= 0) {
 		warn("Failed to read dir block");
 		return (-1);
 	}
 	dir_clear_block(block, size);
 	if (bwrite(&disk, fsbtodb(&sblock, nblk), block, sblock.fs_bsize)
 	    <= 0) {
 		warn("Failed to write dir block");
 		return (-1);
 	}
 
 	return (dir_insert(nblk, size, ino));
 }
 
 /*
  * Insert the journal file into the UFS_ROOTINO directory.  We always extend the
  * last frag
  */
 static int
 journal_insertfile(ino_t ino)
 {
 	union dinodep dp;
 	ufs2_daddr_t nblk;
 	ufs2_daddr_t blk;
 	ufs_lbn_t lbn;
 	int size;
 	int off;
 
 	if (getinode(&disk, &dp, UFS_ROOTINO) != 0) {
 		warn("Failed to get root inode: %s", disk.d_error);
 		sbdirty();
 		return (-1);
 	}
 	blk = 0;
 	size = 0;
 	nblk = journal_balloc();
 	if (nblk <= 0)
 		return (-1);
 	/*
 	 * For simplicity sake we aways extend the UFS_ROOTINO into a new
 	 * directory block rather than searching for space and inserting
 	 * into an existing block.  However, if the rootino has frags
 	 * have to free them and extend the block.
 	 */
 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
 		lbn = lblkno(&sblock, dp.dp1->di_size);
 		off = blkoff(&sblock, dp.dp1->di_size);
 		blk = dp.dp1->di_db[lbn];
 		size = sblksize(&sblock, (off_t)dp.dp1->di_size, lbn);
 	} else {
 		lbn = lblkno(&sblock, dp.dp2->di_size);
 		off = blkoff(&sblock, dp.dp2->di_size);
 		blk = dp.dp2->di_db[lbn];
 		size = sblksize(&sblock, (off_t)dp.dp2->di_size, lbn);
 	}
 	if (off != 0) {
 		if (dir_extend(blk, nblk, off, ino) == -1)
 			return (-1);
 	} else {
 		blk = 0;
 		if (dir_insert(nblk, 0, ino) == -1)
 			return (-1);
 	}
 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
 		dp.dp1->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE;
 		dp.dp1->di_db[lbn] = nblk;
 		dp.dp1->di_size = lblktosize(&sblock, lbn+1);
 	} else {
 		dp.dp2->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE;
 		dp.dp2->di_db[lbn] = nblk;
 		dp.dp2->di_size = lblktosize(&sblock, lbn+1);
 	}
 	if (putinode(&disk) < 0) {
 		warn("Failed to write root inode: %s", disk.d_error);
 		return (-1);
 	}
 	if (cgwrite(&disk) < 0) {
 		warn("Failed to write updated cg");
 		sbdirty();
 		return (-1);
 	}
 	if (blk) {
 		if (cgbfree(&disk, blk, size) < 0) {
 			warn("Failed to write cg");
 			return (-1);
 		}
 	}
 
 	return (0);
 }
 
 static int
 indir_fill(ufs2_daddr_t blk, int level, int *resid)
 {
 	char indirbuf[MAXBSIZE];
 	ufs1_daddr_t *bap1;
 	ufs2_daddr_t *bap2;
 	ufs2_daddr_t nblk;
 	int ncnt;
 	int cnt;
 	int i;
 
 	bzero(indirbuf, sizeof(indirbuf));
 	bap1 = (ufs1_daddr_t *)indirbuf;
 	bap2 = (void *)bap1;
 	cnt = 0;
 	for (i = 0; i < NINDIR(&sblock) && *resid != 0; i++) {
 		nblk = journal_balloc();
 		if (nblk <= 0)
 			return (-1);
 		cnt++;
 		if (sblock.fs_magic == FS_UFS1_MAGIC)
 			*bap1++ = nblk;
 		else
 			*bap2++ = nblk;
 		if (level != 0) {
 			ncnt = indir_fill(nblk, level - 1, resid);
 			if (ncnt <= 0)
 				return (-1);
 			cnt += ncnt;
 		} else 
 			(*resid)--;
 	}
 	if (bwrite(&disk, fsbtodb(&sblock, blk), indirbuf,
 	    sblock.fs_bsize) <= 0) {
 		warn("Failed to write indirect");
 		return (-1);
 	}
 	return (cnt);
 }
 
 /*
  * Clear the flag bits so the journal can be removed.
  */
 static void
 journal_clear(void)
 {
 	union dinodep dp;
 	ino_t ino;
 
 	ino = journal_findfile();
 	if (ino == (ino_t)-1 || ino == 0) {
 		warnx("Journal file does not exist");
 		return;
 	}
 	printf("Clearing journal flags from inode %ju\n", (uintmax_t)ino);
 	if (getinode(&disk, &dp, ino) != 0) {
 		warn("Failed to get journal inode: %s", disk.d_error);
 		return;
 	}
 	if (sblock.fs_magic == FS_UFS1_MAGIC)
 		dp.dp1->di_flags = 0;
 	else
 		dp.dp2->di_flags = 0;
 	if (putinode(&disk) < 0) {
 		warn("Failed to write journal inode: %s", disk.d_error);
 		return;
 	}
 }
 
 static int
 journal_alloc(int64_t size)
 {
 	union dinodep dp;
 	ufs2_daddr_t blk;
 	struct cg *cgp;
 	int resid;
 	ino_t ino;
 	int blks;
 	time_t utime;
 	int i;
 
 	cgp = &disk.d_cg;
 	ino = 0;
 
 	/*
 	 * If the journal file exists we can't allocate it.
 	 */
 	ino = journal_findfile();
 	if (ino == (ino_t)-1) {
 		warnx("journal_findfile() failed.");
 		return (-1);
 	}
 	if (ino > 0) {
 		warnx("Journal file %s already exists, please remove.",
 		    SUJ_FILE);
 		return (-1);
 	}
 	/*
 	 * If the user didn't supply a size pick one based on the filesystem
 	 * size constrained with hardcoded MIN and MAX values.  We opt for
 	 * 1/1024th of the filesystem up to MAX but not exceeding one CG and
 	 * not less than the MIN.
 	 */
 	if (size == 0) {
 		size = (sblock.fs_size * sblock.fs_bsize) / 1024;
 		size = MIN(SUJ_MAX, size);
 		if (size / sblock.fs_fsize > sblock.fs_fpg)
 			size = sblock.fs_fpg * sblock.fs_fsize;
 		size = MAX(SUJ_MIN, size);
 	}
 	/* fsck does not support fragments in journal files. */
 	size = roundup(size, sblock.fs_bsize);
 	resid = blocks = size / sblock.fs_bsize;
 	if (sblock.fs_cstotal.cs_nbfree < blocks) {
 		warn("Insufficient free space for %jd byte journal", size);
 		return (-1);
 	}
 	/*
 	 * Find a cg with enough blocks to satisfy the journal
 	 * size.  Presently the journal does not span cgs.
 	 */
 	while (cgread(&disk) == 1) {
 		if (cgp->cg_cs.cs_nifree == 0)
 			continue;
 		ino = cgialloc(&disk);
 		if (ino <= 0)
 			break;
 		printf("Using inode %ju in cg %d for %jd byte journal\n",
 		    (uintmax_t)ino, cgp->cg_cgx, size);
 		if (getinode(&disk, &dp, ino) != 0) {
 			warn("Failed to get allocated inode: %s", disk.d_error);
 			sbdirty();
 			goto out;
 		}
 		/*
 		 * We leave fields unrelated to the number of allocated
 		 * blocks and size uninitialized.  This causes legacy
 		 * fsck implementations to clear the inode.
 		 */
 		time(&utime);
 		if (sblock.fs_magic == FS_UFS1_MAGIC) {
 			bzero(dp.dp1, sizeof(*dp.dp1));
 			dp.dp1->di_size = size;
 			dp.dp1->di_mode = IFREG | IREAD;
 			dp.dp1->di_nlink = 1;
 			dp.dp1->di_flags =
 			    SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
 			dp.dp1->di_atime = utime;
 			dp.dp1->di_mtime = utime;
 			dp.dp1->di_ctime = utime;
 		} else {
 			bzero(dp.dp2, sizeof(*dp.dp2));
 			dp.dp2->di_size = size;
 			dp.dp2->di_mode = IFREG | IREAD;
 			dp.dp2->di_nlink = 1;
 			dp.dp2->di_flags =
 			    SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
 			dp.dp2->di_atime = utime;
 			dp.dp2->di_mtime = utime;
 			dp.dp2->di_ctime = utime;
 			dp.dp2->di_birthtime = utime;
 		}
 		for (i = 0; i < UFS_NDADDR && resid; i++, resid--) {
 			blk = journal_balloc();
 			if (blk <= 0)
 				goto out;
 			if (sblock.fs_magic == FS_UFS1_MAGIC) {
 				dp.dp1->di_db[i] = blk;
 				dp.dp1->di_blocks++;
 			} else {
 				dp.dp2->di_db[i] = blk;
 				dp.dp2->di_blocks++;
 			}
 		}
 		for (i = 0; i < UFS_NIADDR && resid; i++) {
 			blk = journal_balloc();
 			if (blk <= 0)
 				goto out;
 			blks = indir_fill(blk, i, &resid) + 1;
 			if (blks <= 0) {
 				sbdirty();
 				goto out;
 			}
 			if (sblock.fs_magic == FS_UFS1_MAGIC) {
 				dp.dp1->di_ib[i] = blk;
 				dp.dp1->di_blocks += blks;
 			} else {
 				dp.dp2->di_ib[i] = blk;
 				dp.dp2->di_blocks += blks;
 			}
 		}
 		if (sblock.fs_magic == FS_UFS1_MAGIC)
 			dp.dp1->di_blocks *= sblock.fs_bsize / disk.d_bsize;
 		else
 			dp.dp2->di_blocks *= sblock.fs_bsize / disk.d_bsize;
 		if (putinode(&disk) < 0) {
 			warn("Failed to write allocated inode: %s",
 			    disk.d_error);
 			sbdirty();
 			return (-1);
 		}
 		if (cgwrite(&disk) < 0) {
 			warn("Failed to write updated cg");
 			sbdirty();
 			return (-1);
 		}
 		if (journal_insertfile(ino) < 0) {
 			sbdirty();
 			return (-1);
 		}
 		sblock.fs_sujfree = 0;
 		return (0);
 	}
 	warnx("Insufficient free space for the journal.");
 out:
 	return (-1);
 }
 
 static void
 usage(void)
 {
 	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
 "usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]",
 "              [-J enable | disable] [-j enable | disable] [-k metaspace]",
 "              [-L volname] [-l enable | disable] [-m minfree]",
 "              [-N enable | disable] [-n enable | disable]",
 "              [-o space | time] [-p] [-s avgfpdir] [-t enable | disable]",
 "              special | filesystem");
 	exit(2);
 }
 
 static void
 printfs(void)
 {
 	warnx("POSIX.1e ACLs: (-a)                                %s",
 		(sblock.fs_flags & FS_ACLS)? "enabled" : "disabled");
 	warnx("NFSv4 ACLs: (-N)                                   %s",
 		(sblock.fs_flags & FS_NFS4ACLS)? "enabled" : "disabled");
 	warnx("MAC multilabel: (-l)                               %s",
 		(sblock.fs_flags & FS_MULTILABEL)? "enabled" : "disabled");
 	warnx("soft updates: (-n)                                 %s", 
 		(sblock.fs_flags & FS_DOSOFTDEP)? "enabled" : "disabled");
 	warnx("soft update journaling: (-j)                       %s", 
 		(sblock.fs_flags & FS_SUJ)? "enabled" : "disabled");
 	warnx("gjournal: (-J)                                     %s",
 		(sblock.fs_flags & FS_GJOURNAL)? "enabled" : "disabled");
 	warnx("trim: (-t)                                         %s", 
 		(sblock.fs_flags & FS_TRIM)? "enabled" : "disabled");
 	warnx("maximum blocks per file in a cylinder group: (-e)  %d",
 	      sblock.fs_maxbpg);
 	warnx("average file size: (-f)                            %d",
 	      sblock.fs_avgfilesize);
 	warnx("average number of files in a directory: (-s)       %d",
 	      sblock.fs_avgfpdir);
 	warnx("minimum percentage of free space: (-m)             %d%%",
 	      sblock.fs_minfree);
 	warnx("space to hold for metadata blocks: (-k)            %jd",
 	      sblock.fs_metaspace);
 	warnx("optimization preference: (-o)                      %s",
 	      sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
 	if (sblock.fs_minfree >= MINFREE &&
 	    sblock.fs_optim == FS_OPTSPACE)
 		warnx(OPTWARN, "time", ">=", MINFREE);
 	if (sblock.fs_minfree < MINFREE &&
 	    sblock.fs_optim == FS_OPTTIME)
 		warnx(OPTWARN, "space", "<", MINFREE);
 	warnx("volume label: (-L)                                 %s",
 		sblock.fs_volname);
 }
diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h
index aef291601289..b62438ff6730 100644
--- a/sys/fs/devfs/devfs.h
+++ b/sys/fs/devfs/devfs.h
@@ -1,213 +1,220 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 1992, 1993
  *	The Regents of the University of California.  All rights reserved.
  * Copyright (c) 2000
  *	Poul-Henning Kamp.  All rights reserved.
  * Copyright (c) 2002
  *	Dima Dorfman.  All rights reserved.
  *
  * This code is derived from software donated to Berkeley by
  * Jan-Simon Pendry.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)kernfs.h	8.6 (Berkeley) 3/29/95
  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs.h 1.14
  *
  * $FreeBSD$
  */
 
 #ifndef _FS_DEVFS_DEVFS_H_
 #define	_FS_DEVFS_DEVFS_H_
 
 #define	DEVFS_MAGIC	0xdb0a087a
 
 /*
  * Identifiers.  The ruleset and rule numbers are 16-bit values.  The
  * "rule ID" is a combination of the ruleset and rule number; it
  * should be able to univocally describe a rule in the system.  In
  * this implementation, the upper 16 bits of the rule ID is the
  * ruleset number; the lower 16 bits, the rule number within the
  * aforementioned ruleset.
  */
 typedef uint16_t devfs_rnum;
 typedef uint16_t devfs_rsnum;
 typedef uint32_t devfs_rid;
 
 /*
  * Identifier manipulators.
  */
 #define	rid2rsn(rid)	((rid) >> 16)
 #define	rid2rn(rid)	((rid) & 0xffff)
 #define	mkrid(rsn, rn)	((rn) | ((rsn) << 16))
 
 /*
  * Plain DEVFS rule.  This gets shared between kernel and userland
  * verbatim, so it shouldn't contain any pointers or other kernel- or
  * userland-specific values.
  */
 struct devfs_rule {
 	uint32_t dr_magic;			/* Magic number. */
 	devfs_rid dr_id;			/* Identifier. */
 
 	/*
 	 * Conditions under which this rule should be applied.  These
 	 * are ANDed together since OR can be simulated by using
 	 * multiple rules.  dr_icond determines which of the other
 	 * variables we should process.
 	 */
 	int	dr_icond;
 #define	DRC_DSWFLAGS	0x001
 #define	DRC_PATHPTRN	0x002
 	int	dr_dswflags;			/* cdevsw flags to match. */
 #define	DEVFS_MAXPTRNLEN	200
 	char	dr_pathptrn[DEVFS_MAXPTRNLEN];	/* Pattern to match path. */
 
 	/*
 	 * Things to change.  dr_iacts determines which of the other
 	 * variables we should process.
 	 */
 	int	dr_iacts;
 #define	DRA_BACTS	0x001
 #define	DRA_UID		0x002
 #define	DRA_GID		0x004
 #define	DRA_MODE	0x008
 #define	DRA_INCSET	0x010
 	int	dr_bacts;			/* Boolean (on/off) action. */
 #define	DRB_HIDE	0x001			/* Hide entry (DE_WHITEOUT). */
 #define	DRB_UNHIDE	0x002			/* Unhide entry. */
 	uid_t	dr_uid;
 	gid_t	dr_gid;
 	mode_t	dr_mode;
 	devfs_rsnum dr_incset;			/* Included ruleset. */
 };
 
 /*
  * Rule-related ioctls.
  */
 #define	DEVFSIO_RADD		_IOWR('D', 0, struct devfs_rule)
 #define	DEVFSIO_RDEL		_IOW('D', 1, devfs_rid)
 #define	DEVFSIO_RAPPLY		_IOW('D', 2, struct devfs_rule)
 #define	DEVFSIO_RAPPLYID	_IOW('D', 3, devfs_rid)
 #define	DEVFSIO_RGETNEXT       	_IOWR('D', 4, struct devfs_rule)
 
 #define	DEVFSIO_SUSE		_IOW('D', 10, devfs_rsnum)
 #define	DEVFSIO_SAPPLY		_IOW('D', 11, devfs_rsnum)
 #define	DEVFSIO_SGETNEXT	_IOWR('D', 12, devfs_rsnum)
 
 /* XXX: DEVFSIO_RS_GET_INFO for refcount, active if any, etc. */
 
 #ifdef _KERNEL
 
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_DEVFS);
 #endif
 
+#endif /* _KERNEL */
+
 struct componentname;
 
 TAILQ_HEAD(devfs_dlist_head, devfs_dirent);
 
 struct devfs_dirent {
 	struct cdev_priv	*de_cdp;
 	int			de_inode;
 	int			de_flags;
 #define	DE_WHITEOUT	0x01
 #define	DE_DOT		0x02
 #define	DE_DOTDOT	0x04
 #define	DE_DOOMED	0x08
 #define	DE_COVERED	0x10
 #define	DE_USER		0x20
 	int			de_holdcnt;
 	struct dirent 		*de_dirent;
 	TAILQ_ENTRY(devfs_dirent) de_list;
 	struct devfs_dlist_head	de_dlist;
 	struct devfs_dirent	*de_dir;
 	int			de_links;
 	mode_t			de_mode;
 	uid_t			de_uid;
 	gid_t			de_gid;
 	struct label		*de_label;
 	struct timespec 	de_atime;
 	struct timespec 	de_mtime;
 	struct timespec 	de_ctime;
 	struct vnode 		*de_vnode;
 	char 			*de_symlink;
 	int			de_usecount;
 };
 
+#include <sys/_lock.h>
+#include <sys/_sx.h>
+
 struct devfs_mount {
 	u_int			dm_idx;
 	struct mount		*dm_mount;
 	struct devfs_dirent	*dm_rootdir;
 	unsigned		dm_generation;
 	int			dm_holdcnt;
 	struct sx		dm_lock;
 	devfs_rsnum		dm_ruleset;
 };
 
 #define DEVFS_ROOTINO 2
 
+#ifdef _KERNEL
+
 extern unsigned devfs_rule_depth;
 
 #define VFSTODEVFS(mp)	((struct devfs_mount *)((mp)->mnt_data))
 
 #define DEVFS_DE_HOLD(de)	((de)->de_holdcnt++)
 #define DEVFS_DE_DROP(de)	(--(de)->de_holdcnt == 0)
 
 #define DEVFS_DMP_HOLD(dmp)	((dmp)->dm_holdcnt++)
 #define DEVFS_DMP_DROP(dmp)	(--(dmp)->dm_holdcnt == 0)
 
 #define	DEVFS_DEL_VNLOCKED	0x01
 #define	DEVFS_DEL_NORECURSE	0x02
 
 void	devfs_rules_apply(struct devfs_mount *, struct devfs_dirent *);
 void	devfs_rules_cleanup(struct devfs_mount *);
 int	devfs_rules_ioctl(struct devfs_mount *, u_long, caddr_t,
 	    struct thread *);
 void	devfs_ruleset_set(devfs_rsnum rsnum, struct devfs_mount *dm);
 void	devfs_ruleset_apply(struct devfs_mount *dm);
 int	devfs_allocv(struct devfs_dirent *, struct mount *, int,
 	    struct vnode **);
 char	*devfs_fqpn(char *, struct devfs_mount *, struct devfs_dirent *,
 	    struct componentname *);
 void	devfs_delete(struct devfs_mount *, struct devfs_dirent *, int);
 void	devfs_dirent_free(struct devfs_dirent *);
 int	devfs_populate_needed(struct devfs_mount *dm);
 void	devfs_populate(struct devfs_mount *);
 void	devfs_cleanup(struct devfs_mount *);
 void	devfs_unmount_final(struct devfs_mount *);
 struct devfs_dirent	*devfs_newdirent(char *, int);
 struct devfs_dirent	*devfs_parent_dirent(struct devfs_dirent *);
 struct devfs_dirent	*devfs_vmkdir(struct devfs_mount *, char *, int,
 			    struct devfs_dirent *, u_int);
 struct devfs_dirent	*devfs_find(struct devfs_dirent *, const char *, int,
 			    int);
 
 void	devfs_ctty_ref(struct vnode *);
 void	devfs_ctty_unref(struct vnode *);
 int	devfs_usecount(struct vnode *);
 
 #endif /* _KERNEL */
 
 #endif /* !_FS_DEVFS_DEVFS_H_ */
diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
index 5c3cb17eca61..e5afa311cbfd 100644
--- a/sys/fs/devfs/devfs_int.h
+++ b/sys/fs/devfs/devfs_int.h
@@ -1,103 +1,103 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2005 Poul-Henning Kamp.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 /*
  * This file documents a private interface and it SHALL only be used
  * by kern/kern_conf.c and fs/devfs/...
  */
 
 #ifndef _FS_DEVFS_DEVFS_INT_H_
 #define	_FS_DEVFS_DEVFS_INT_H_
 
 #include <sys/queue.h>
 
-#ifdef _KERNEL
-
 struct devfs_dirent;
 struct devfs_mount;
 
 struct cdev_privdata {
 	struct file		*cdpd_fp;
 	void			*cdpd_data;
 	void			(*cdpd_dtr)(void *);
 	LIST_ENTRY(cdev_privdata) cdpd_list;
 };
 
 struct cdev_priv {
 	struct cdev		cdp_c;
 	TAILQ_ENTRY(cdev_priv)	cdp_list;
 
 	u_int			cdp_inode;
 
 	u_int			cdp_flags;
 #define CDP_ACTIVE		(1 << 0)
 #define CDP_SCHED_DTR		(1 << 1)
 #define	CDP_UNREF_DTR		(1 << 2)
 
 	u_int			cdp_inuse;
 	u_int			cdp_maxdirent;
 	struct devfs_dirent	**cdp_dirents;
 	struct devfs_dirent	*cdp_dirent0;
 
 	TAILQ_ENTRY(cdev_priv)	cdp_dtr_list;
 	void			(*cdp_dtr_cb)(void *);
 	void			*cdp_dtr_cb_arg;
 
 	LIST_HEAD(, cdev_privdata) cdp_fdpriv;
 
 	struct mtx		cdp_threadlock;
 };
 
 #define	cdev2priv(c)	__containerof(c, struct cdev_priv, cdp_c)
 
+#ifdef _KERNEL
+
 struct cdev	*devfs_alloc(int);
 int	devfs_dev_exists(const char *);
 void	devfs_free(struct cdev *);
 void	devfs_create(struct cdev *);
 void	devfs_destroy(struct cdev *);
 void	devfs_destroy_cdevpriv(struct cdev_privdata *);
 
 int	devfs_dir_find(const char *);
 void	devfs_dir_ref_de(struct devfs_mount *, struct devfs_dirent *);
 void	devfs_dir_unref_de(struct devfs_mount *, struct devfs_dirent *);
 int	devfs_pathpath(const char *, const char *);
 
 extern struct unrhdr *devfs_inos;
 extern struct mtx devmtx;
 extern struct mtx devfs_de_interlock;
 extern struct sx clone_drain_lock;
 extern struct mtx cdevpriv_mtx;
 extern TAILQ_HEAD(cdev_priv_list, cdev_priv) cdevp_list;
 
 #define	dev_lock_assert_locked()	mtx_assert(&devmtx, MA_OWNED)
 #define	dev_lock_assert_unlocked()	mtx_assert(&devmtx, MA_NOTOWNED)
 
 #endif /* _KERNEL */
 
 #endif /* !_FS_DEVFS_DEVFS_INT_H_ */
diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h
index b198a6a39d81..9a4de4acbe2e 100644
--- a/sys/fs/msdosfs/denode.h
+++ b/sys/fs/msdosfs/denode.h
@@ -1,289 +1,290 @@
 /* $FreeBSD$ */
 /*	$NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
  * All rights reserved.
  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by TooLs GmbH.
  * 4. The name of TooLs GmbH may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*-
  * Written by Paul Popelka (paulp@uts.amdahl.com)
  *
  * You can do anything you want with this software, just don't say you wrote
  * it, and don't remove this notice.
  *
  * This software is provided "as is".
  *
  * The author supplies this software to be publicly redistributed on the
  * understanding that the author is not responsible for the correct
  * functioning of this software in any circumstances and is not liable for
  * any damages caused by this software.
  *
  * October 1992
  */
 #ifndef _FS_MSDOSFS_DENODE_H_
 #define	_FS_MSDOSFS_DENODE_H_
 
 /*
  * This is the pc filesystem specific portion of the vnode structure.
  *
  * To describe a file uniquely the de_dirclust, de_diroffset, and
  * de_StartCluster fields are used.
  *
  * de_dirclust contains the cluster number of the directory cluster
  *	containing the entry for a file or directory.
  * de_diroffset is the index into the cluster for the entry describing
  *	a file or directory.
  * de_StartCluster is the number of the first cluster of the file or directory.
  *
  * Now to describe the quirks of the pc filesystem.
  * - Clusters 0 and 1 are reserved.
  * - The first allocatable cluster is 2.
  * - The root directory is of fixed size and all blocks that make it up
  *   are contiguous.
  * - Cluster 0 refers to the root directory when it is found in the
  *   startcluster field of a directory entry that points to another directory.
  * - Cluster 0 implies a 0 length file when found in the start cluster field
  *   of a directory entry that points to a file.
  * - You can't use the cluster number 0 to derive the address of the root
  *   directory.
  * - Multiple directory entries can point to a directory. The entry in the
  *   parent directory points to a child directory.  Any directories in the
  *   child directory contain a ".." entry that points back to the parent.
  *   The child directory itself contains a "." entry that points to itself.
  * - The root directory does not contain a "." or ".." entry.
  * - Directory entries for directories are never changed once they are created
  *   (except when removed).  The size stays 0, and the last modification time
  *   is never changed.  This is because so many directory entries can point to
  *   the physical clusters that make up a directory.  It would lead to an
  *   update nightmare.
  * - The length field in a directory entry pointing to a directory contains 0
  *   (always).  The only way to find the end of a directory is to follow the
  *   cluster chain until the "last cluster" marker is found.
  *
  * My extensions to make this house of cards work.  These apply only to the in
  * memory copy of the directory entry.
  * - A reference count for each denode will be kept since dos doesn't keep such
  *   things.
  */
 
 /*
  * Internal pseudo-offset for (nonexistent) directory entry for the root
  * dir in the root dir
  */
 #define	MSDOSFSROOT_OFS	0x1fffffff
 
 /*
  * The FAT cache structure. fc_fsrcn is the filesystem relative cluster
  * number that corresponds to the file relative cluster number in this
  * structure (fc_frcn).
  */
 struct fatcache {
 	u_long fc_frcn;		/* file relative cluster number */
 	u_long fc_fsrcn;	/* filesystem relative cluster number */
 };
 
 /*
  * The FAT entry cache as it stands helps make extending files a "quick"
  * operation by avoiding having to scan the FAT to discover the last
  * cluster of the file. The cache also helps sequential reads by
  * remembering the last cluster read from the file.  This also prevents us
  * from having to rescan the FAT to find the next cluster to read.  This
  * cache is probably pretty worthless if a file is opened by multiple
  * processes.
  */
 #define	FC_SIZE		3	/* number of entries in the cache */
 #define	FC_LASTMAP	0	/* entry the last call to pcbmap() resolved
 				 * to */
 #define	FC_LASTFC	1	/* entry for the last cluster in the file */
 #define	FC_NEXTTOLASTFC	2	/* entry for a close to the last cluster in
 				 * the file */
 
 #define	FCE_EMPTY	0xffffffff	/* doesn't represent an actual cluster # */
 
 /*
  * Set a slot in the FAT cache.
  */
 #define	fc_setcache(dep, slot, frcn, fsrcn) \
 	(dep)->de_fc[(slot)].fc_frcn = (frcn); \
 	(dep)->de_fc[(slot)].fc_fsrcn = (fsrcn);
 
 /*
  * This is the in memory variant of a dos directory entry.  It is usually
  * contained within a vnode.
  */
 struct denode {
 	struct vnode *de_vnode;	/* addr of vnode we are part of */
 	u_long de_flag;		/* flag bits */
 	u_long de_dirclust;	/* cluster of the directory file containing this entry */
 	u_long de_diroffset;	/* offset of this entry in the directory cluster */
 	u_long de_fndoffset;	/* offset of found dir entry */
 	int de_fndcnt;		/* number of slots before de_fndoffset */
 	long de_refcnt;		/* reference count */
 	struct msdosfsmount *de_pmp;	/* addr of our mount struct */
 	u_char de_Name[12];	/* name, from DOS directory entry */
 	u_char de_Attributes;	/* attributes, from directory entry */
 	u_char de_LowerCase;	/* NT VFAT lower case flags */
 	u_char de_CHun;		/* Hundredth of second of CTime*/
 	u_short de_CTime;	/* creation time */
 	u_short de_CDate;	/* creation date */
 	u_short de_ADate;	/* access date */
 	u_short de_MTime;	/* modification time */
 	u_short de_MDate;	/* modification date */
 	u_long de_StartCluster; /* starting cluster of file */
 	u_long de_FileSize;	/* size of file in bytes */
 	struct fatcache de_fc[FC_SIZE];	/* FAT cache */
 	u_quad_t de_modrev;	/* Revision level for lease. */
 	uint64_t de_inode;	/* Inode number (really byte offset of direntry) */
 };
 
 /*
  * Values for the de_flag field of the denode.
  */
 #define	DE_UPDATE	0x0004	/* Modification time update request */
 #define	DE_CREATE	0x0008	/* Creation time update */
 #define	DE_ACCESS	0x0010	/* Access time update */
 #define	DE_MODIFIED	0x0020	/* Denode has been modified */
 #define	DE_RENAME	0x0040	/* Denode is in the process of being renamed */
 
 /* Maximum size of a file on a FAT filesystem */
 #define MSDOSFS_FILESIZE_MAX	0xFFFFFFFFLL
 
 /*
  * Transfer directory entries between internal and external form.
  * dep is a struct denode * (internal form),
  * dp is a struct direntry * (external form).
  */
 #define DE_INTERNALIZE32(dep, dp)			\
 	 ((dep)->de_StartCluster |= getushort((dp)->deHighClust) << 16)
 #define DE_INTERNALIZE(dep, dp)				\
 	(memcpy((dep)->de_Name, (dp)->deName, 11),	\
 	 (dep)->de_Attributes = (dp)->deAttributes,	\
 	 (dep)->de_LowerCase = (dp)->deLowerCase,	\
 	 (dep)->de_CHun = (dp)->deCHundredth,		\
 	 (dep)->de_CTime = getushort((dp)->deCTime),	\
 	 (dep)->de_CDate = getushort((dp)->deCDate),	\
 	 (dep)->de_ADate = getushort((dp)->deADate),	\
 	 (dep)->de_MTime = getushort((dp)->deMTime),	\
 	 (dep)->de_MDate = getushort((dp)->deMDate),	\
 	 (dep)->de_StartCluster = getushort((dp)->deStartCluster), \
 	 (dep)->de_FileSize = getulong((dp)->deFileSize), \
 	 (FAT32((dep)->de_pmp) ? DE_INTERNALIZE32((dep), (dp)) : 0))
 
 #define DE_EXTERNALIZE(dp, dep)				\
 	(memcpy((dp)->deName, (dep)->de_Name, 11),	\
 	 (dp)->deAttributes = (dep)->de_Attributes,	\
 	 (dp)->deLowerCase = (dep)->de_LowerCase,	\
 	 (dp)->deCHundredth = (dep)->de_CHun,		\
 	 putushort((dp)->deCTime, (dep)->de_CTime),	\
 	 putushort((dp)->deCDate, (dep)->de_CDate),	\
 	 putushort((dp)->deADate, (dep)->de_ADate),	\
 	 putushort((dp)->deMTime, (dep)->de_MTime),	\
 	 putushort((dp)->deMDate, (dep)->de_MDate),	\
 	 putushort((dp)->deStartCluster, (dep)->de_StartCluster), \
 	 putulong((dp)->deFileSize,			\
 	     ((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize), \
 	 putushort((dp)->deHighClust, (dep)->de_StartCluster >> 16))
 
 #if defined(_KERNEL) || defined(MAKEFS)
 
 #define	VTODE(vp)	((struct denode *)(vp)->v_data)
 #define	DETOV(de)	((de)->de_vnode)
 
 #define	DETIMES(dep, acc, mod, cre) do {				\
 	if ((dep)->de_flag & DE_UPDATE) {				\
 		(dep)->de_flag |= DE_MODIFIED;				\
 		timespec2fattime((mod), 0, &(dep)->de_MDate,		\
 		    &(dep)->de_MTime, NULL);				\
 		(dep)->de_Attributes |= ATTR_ARCHIVE;			\
 	}								\
 	if ((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95) {		\
 		(dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS);	\
 		break;							\
 	}								\
 	if ((dep)->de_flag & DE_ACCESS) {				\
 		uint16_t adate;						\
 									\
 		timespec2fattime((acc), 0, &adate, NULL, NULL);		\
 		if (adate != (dep)->de_ADate) {				\
 			(dep)->de_flag |= DE_MODIFIED;			\
 			(dep)->de_ADate = adate;			\
 		}							\
 	}								\
 	if ((dep)->de_flag & DE_CREATE) {				\
 		timespec2fattime((cre), 0, &(dep)->de_CDate,		\
 		    &(dep)->de_CTime, &(dep)->de_CHun);			\
 		(dep)->de_flag |= DE_MODIFIED;				\
 	}								\
 	(dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS);		\
 } while (0)
 
 /*
  * This overlays the fid structure (see mount.h)
  */
 struct defid {
 	u_short defid_len;	/* length of structure */
 	u_short defid_pad;	/* force long alignment */
 
 	uint32_t defid_dirclust; /* cluster this dir entry came from */
 	uint32_t defid_dirofs;	/* offset of entry within the cluster */
 #if 0
 	uint32_t defid_gen;	/* generation number */
 #endif
 };
 
 extern struct vop_vector msdosfs_vnodeops;
 
 #ifdef _KERNEL
 int msdosfs_lookup(struct vop_cachedlookup_args *);
 int msdosfs_inactive(struct vop_inactive_args *);
 int msdosfs_reclaim(struct vop_reclaim_args *);
 #endif
 
 /*
  * Internal service routine prototypes.
  */
+struct componentname;
 int deget(struct msdosfsmount *, u_long, u_long, struct denode **);
 int uniqdosname(struct denode *, struct componentname *, u_char *);
 
 int readep(struct msdosfsmount *pmp, u_long dirclu, u_long dirofs,  struct buf **bpp, struct direntry **epp);
 int readde(struct denode *dep, struct buf **bpp, struct direntry **epp);
 int deextend(struct denode *dep, u_long length, struct ucred *cred);
 int fillinusemap(struct msdosfsmount *pmp);
 void reinsert(struct denode *dep);
 int dosdirempty(struct denode *dep);
 int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp);
 int deupdat(struct denode *dep, int waitfor);
 int removede(struct denode *pdep, struct denode *dep);
 int detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred);
 int doscheckpath( struct denode *source, struct denode *target);
 #endif	/* _KERNEL || MAKEFS */
 #endif	/* !_FS_MSDOSFS_DENODE_H_ */
diff --git a/sys/sys/buf.h b/sys/sys/buf.h
index 2997560b9ab3..aacad3a057d2 100644
--- a/sys/sys/buf.h
+++ b/sys/sys/buf.h
@@ -1,605 +1,606 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  * (c) UNIX System Laboratories, Inc.
  * All or some portions of this file are derived from material licensed
  * to the University of California by American Telephone and Telegraph
  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  * the permission of UNIX System Laboratories, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)buf.h	8.9 (Berkeley) 3/30/95
  * $FreeBSD$
  */
 
 #ifndef _SYS_BUF_H_
 #define	_SYS_BUF_H_
 
 #include <sys/bufobj.h>
 #include <sys/queue.h>
 #include <sys/lock.h>
 #include <sys/lockmgr.h>
 #include <vm/uma.h>
 
 struct bio;
 struct buf;
 struct bufobj;
 struct mount;
 struct vnode;
 struct uio;
 
 /*
  * To avoid including <ufs/ffs/softdep.h> 
  */   
 LIST_HEAD(workhead, worklist);
 /*
  * These are currently used only by the soft dependency code, hence
  * are stored once in a global variable. If other subsystems wanted
  * to use these hooks, a pointer to a set of bio_ops could be added
  * to each buffer.
  */
 extern struct bio_ops {
 	void	(*io_start)(struct buf *);
 	void	(*io_complete)(struct buf *);
 	void	(*io_deallocate)(struct buf *);
 	int	(*io_countdeps)(struct buf *, int);
 } bioops;
 
 struct vm_object;
 struct vm_page;
 
 typedef uint32_t b_xflags_t;
 
 /*
  * The buffer header describes an I/O operation in the kernel.
  *
  * NOTES:
  *	b_bufsize, b_bcount.  b_bufsize is the allocation size of the
  *	buffer, either DEV_BSIZE or PAGE_SIZE aligned.  b_bcount is the
  *	originally requested buffer size and can serve as a bounds check
  *	against EOF.  For most, but not all uses, b_bcount == b_bufsize.
  *
  *	b_dirtyoff, b_dirtyend.  Buffers support piecemeal, unaligned
  *	ranges of dirty data that need to be written to backing store.
  *	The range is typically clipped at b_bcount ( not b_bufsize ).
  *
  *	b_resid.  Number of bytes remaining in I/O.  After an I/O operation
  *	completes, b_resid is usually 0 indicating 100% success.
  *
  *	All fields are protected by the buffer lock except those marked:
  *		V - Protected by owning bufobj lock
  *		Q - Protected by the buf queue lock
  *		D - Protected by an dependency implementation specific lock
  */
 struct buf {
 	struct bufobj	*b_bufobj;
 	long		b_bcount;
 	void		*b_caller1;
 	caddr_t		b_data;
 	int		b_error;
 	uint16_t	b_iocmd;	/* BIO_* bio_cmd from bio.h */
 	uint16_t	b_ioflags;	/* BIO_* bio_flags from bio.h */
 	off_t		b_iooffset;
 	long		b_resid;
 	void	(*b_iodone)(struct buf *);
 	void	(*b_ckhashcalc)(struct buf *);
 	uint64_t	b_ckhash;	/* B_CKHASH requested check-hash */
 	daddr_t b_blkno;		/* Underlying physical block number. */
 	off_t	b_offset;		/* Offset into file. */
 	TAILQ_ENTRY(buf) b_bobufs;	/* (V) Buffer's associated vnode. */
 	uint32_t	b_vflags;	/* (V) BV_* flags */
 	uint8_t		b_qindex;	/* (Q) buffer queue index */
 	uint8_t		b_domain;	/* (Q) buf domain this resides in */
 	uint16_t	b_subqueue;	/* (Q) per-cpu q if any */
 	uint32_t	b_flags;	/* B_* flags. */
 	b_xflags_t b_xflags;		/* extra flags */
 	struct lock b_lock;		/* Buffer lock */
 	long	b_bufsize;		/* Allocated buffer size. */
 	int	b_runningbufspace;	/* when I/O is running, pipelining */
 	int	b_kvasize;		/* size of kva for buffer */
 	int	b_dirtyoff;		/* Offset in buffer of dirty region. */
 	int	b_dirtyend;		/* Offset of end of dirty region. */
 	caddr_t	b_kvabase;		/* base kva for buffer */
 	daddr_t b_lblkno;		/* Logical block number. */
 	struct	vnode *b_vp;		/* Device vnode. */
 	struct	ucred *b_rcred;		/* Read credentials reference. */
 	struct	ucred *b_wcred;		/* Write credentials reference. */
 	union {
 		TAILQ_ENTRY(buf) b_freelist; /* (Q) */
 		struct {
-			void	(*b_pgiodone)(void *, vm_page_t *, int, int);
+			void	(*b_pgiodone)(void *, struct vm_page **,
+				    int, int);
 			int	b_pgbefore;
 			int	b_pgafter;
 		};
 	};
 	union	cluster_info {
 		TAILQ_HEAD(cluster_list_head, buf) cluster_head;
 		TAILQ_ENTRY(buf) cluster_entry;
 	} b_cluster;
 	int		b_npages;
 	struct	workhead b_dep;		/* (D) List of filesystem dependencies. */
 	void	*b_fsprivate1;
 	void	*b_fsprivate2;
 	void	*b_fsprivate3;
 
 #if defined(FULL_BUF_TRACKING)
 #define BUF_TRACKING_SIZE	32
 #define BUF_TRACKING_ENTRY(x)	((x) & (BUF_TRACKING_SIZE - 1))
 	const char	*b_io_tracking[BUF_TRACKING_SIZE];
 	uint32_t	b_io_tcnt;
 #elif defined(BUF_TRACKING)
 	const char	*b_io_tracking;
 #endif
 	struct	vm_page *b_pages[];
 };
 
 #define b_object	b_bufobj->bo_object
 
 /*
  * These flags are kept in b_flags.
  *
  * Notes:
  *
  *	B_ASYNC		VOP calls on bp's are usually async whether or not
  *			B_ASYNC is set, but some subsystems, such as NFS, like 
  *			to know what is best for the caller so they can
  *			optimize the I/O.
  *
  *	B_PAGING	Indicates that bp is being used by the paging system or
  *			some paging system and that the bp is not linked into
  *			the b_vp's clean/dirty linked lists or ref counts.
  *			Buffer vp reassignments are illegal in this case.
  *
  *	B_CACHE		This may only be set if the buffer is entirely valid.
  *			The situation where B_DELWRI is set and B_CACHE is
  *			clear MUST be committed to disk by getblk() so 
  *			B_DELWRI can also be cleared.  See the comments for
  *			getblk() in kern/vfs_bio.c.  If B_CACHE is clear,
  *			the caller is expected to clear BIO_ERROR and B_INVAL,
  *			set BIO_READ, and initiate an I/O.
  *
  *			The 'entire buffer' is defined to be the range from
  *			0 through b_bcount.
  *
  *	B_MALLOC	Request that the buffer be allocated from the malloc
  *			pool, DEV_BSIZE aligned instead of PAGE_SIZE aligned.
  *
  *	B_CLUSTEROK	This flag is typically set for B_DELWRI buffers
  *			by filesystems that allow clustering when the buffer
  *			is fully dirty and indicates that it may be clustered
  *			with other adjacent dirty buffers.  Note the clustering
  *			may not be used with the stage 1 data write under NFS
  *			but may be used for the commit rpc portion.
  *
  *	B_INVALONERR	This flag is set on dirty buffers.  It specifies that a
  *			write error should forcibly invalidate the buffer
  *			contents.  This flag should be used with caution, as it
  *			discards data.  It is incompatible with B_ASYNC.
  *
  *	B_VMIO		Indicates that the buffer is tied into an VM object.
  *			The buffer's data is always PAGE_SIZE aligned even
  *			if b_bufsize and b_bcount are not.  ( b_bufsize is 
  *			always at least DEV_BSIZE aligned, though ).
  *
  *	B_DIRECT	Hint that we should attempt to completely free
  *			the pages underlying the buffer.  B_DIRECT is
  *			sticky until the buffer is released and typically
  *			only has an effect when B_RELBUF is also set.
  *
  */
 
 #define	B_AGE		0x00000001	/* Move to age queue when I/O done. */
 #define	B_NEEDCOMMIT	0x00000002	/* Append-write in progress. */
 #define	B_ASYNC		0x00000004	/* Start I/O, do not wait. */
 #define	B_DIRECT	0x00000008	/* direct I/O flag (pls free vmio) */
 #define	B_DEFERRED	0x00000010	/* Skipped over for cleaning */
 #define	B_CACHE		0x00000020	/* Bread found us in the cache. */
 #define	B_VALIDSUSPWRT	0x00000040	/* Valid write during suspension. */
 #define	B_DELWRI	0x00000080	/* Delay I/O until buffer reused. */
 #define	B_CKHASH	0x00000100	/* checksum hash calculated on read */
 #define	B_DONE		0x00000200	/* I/O completed. */
 #define	B_EINTR		0x00000400	/* I/O was interrupted */
 #define	B_NOREUSE	0x00000800	/* Contents not reused once released. */
 #define	B_REUSE		0x00001000	/* Contents reused, second chance. */
 #define	B_INVAL		0x00002000	/* Does not contain valid info. */
 #define	B_BARRIER	0x00004000	/* Write this and all preceding first. */
 #define	B_NOCACHE	0x00008000	/* Do not cache block after use. */
 #define	B_MALLOC	0x00010000	/* malloced b_data */
 #define	B_CLUSTEROK	0x00020000	/* Pagein op, so swap() can count it. */
 #define	B_INVALONERR	0x00040000	/* Invalidate on write error. */
 #define	B_IOSTARTED	0x00080000	/* buf_start() called */
 #define	B_00100000	0x00100000	/* Available flag. */
 #define	B_MAXPHYS	0x00200000	/* nitems(b_pages[]) = atop(MAXPHYS). */
 #define	B_RELBUF	0x00400000	/* Release VMIO buffer. */
 #define	B_FS_FLAG1	0x00800000	/* Available flag for FS use. */
 #define	B_NOCOPY	0x01000000	/* Don't copy-on-write this buf. */
 #define	B_INFREECNT	0x02000000	/* buf is counted in numfreebufs */
 #define	B_PAGING	0x04000000	/* volatile paging I/O -- bypass VMIO */
 #define B_MANAGED	0x08000000	/* Managed by FS. */
 #define B_RAM		0x10000000	/* Read ahead mark (flag) */
 #define B_VMIO		0x20000000	/* VMIO flag */
 #define B_CLUSTER	0x40000000	/* pagein op, so swap() can count it */
 #define B_REMFREE	0x80000000	/* Delayed bremfree */
 
 #define PRINT_BUF_FLAGS "\20\40remfree\37cluster\36vmio\35ram\34managed" \
 	"\33paging\32infreecnt\31nocopy\30b23\27relbuf\26maxphys\25b20" \
 	"\24iostarted\23invalonerr\22clusterok\21malloc\20nocache\17b14" \
 	"\16inval\15reuse\14noreuse\13eintr\12done\11b8\10delwri" \
 	"\7validsuspwrt\6cache\5deferred\4direct\3async\2needcommit\1age"
 
 /*
  * These flags are kept in b_xflags.
  *
  * BX_FSPRIV reserves a set of eight flags that may be used by individual
  * filesystems for their own purpose. Their specific definitions are
  * found in the header files for each filesystem that uses them.
  */
 #define	BX_VNDIRTY	0x00000001	/* On vnode dirty list */
 #define	BX_VNCLEAN	0x00000002	/* On vnode clean list */
 #define	BX_CVTENXIO	0x00000004	/* Convert errors to ENXIO */
 #define	BX_BKGRDWRITE	0x00000010	/* Do writes in background */
 #define	BX_BKGRDMARKER	0x00000020	/* Mark buffer for splay tree */
 #define	BX_ALTDATA	0x00000040	/* Holds extended data */
 #define	BX_FSPRIV	0x00FF0000	/* Filesystem-specific flags mask */
 
 #define	PRINT_BUF_XFLAGS "\20\7altdata\6bkgrdmarker\5bkgrdwrite\3cvtenxio" \
 	"\2clean\1dirty"
 
 #define	NOOFFSET	(-1LL)		/* No buffer offset calculated yet */
 
 /*
  * These flags are kept in b_vflags.
  */
 #define	BV_SCANNED	0x00000001	/* VOP_FSYNC funcs mark written bufs */
 #define	BV_BKGRDINPROG	0x00000002	/* Background write in progress */
 #define	BV_BKGRDWAIT	0x00000004	/* Background write waiting */
 #define	BV_BKGRDERR	0x00000008	/* Error from background write */
 
 #define	PRINT_BUF_VFLAGS "\20\4bkgrderr\3bkgrdwait\2bkgrdinprog\1scanned"
 
 #ifdef _KERNEL
 
 #ifndef NSWBUF_MIN
 #define	NSWBUF_MIN	16
 #endif
 
 /*
  * Buffer locking
  */
 extern const char *buf_wmesg;		/* Default buffer lock message */
 #define BUF_WMESG "bufwait"
 #include <sys/proc.h>			/* XXX for curthread */
 #include <sys/mutex.h>
 
 /*
  * Initialize a lock.
  */
 #define BUF_LOCKINIT(bp)						\
 	lockinit(&(bp)->b_lock, PRIBIO + 4, buf_wmesg, 0, LK_NEW)
 /*
  *
  * Get a lock sleeping non-interruptably until it becomes available.
  */
 #define	BUF_LOCK(bp, locktype, interlock)				\
 	_lockmgr_args_rw(&(bp)->b_lock, (locktype), (interlock),	\
 	    LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT,		\
 	    LOCK_FILE, LOCK_LINE)
 
 /*
  * Get a lock sleeping with specified interruptably and timeout.
  */
 #define	BUF_TIMELOCK(bp, locktype, interlock, wmesg, catch, timo)	\
 	_lockmgr_args_rw(&(bp)->b_lock, (locktype) | LK_TIMELOCK,	\
 	    (interlock), (wmesg), (PRIBIO + 4) | (catch), (timo),	\
 	    LOCK_FILE, LOCK_LINE)
 
 /*
  * Release a lock. Only the acquiring process may free the lock unless
  * it has been handed off to biodone.
  */
 #define	BUF_UNLOCK(bp) do {						\
 	KASSERT(((bp)->b_flags & B_REMFREE) == 0,			\
 	    ("BUF_UNLOCK %p while B_REMFREE is still set.", (bp)));	\
 									\
 	BUF_UNLOCK_RAW((bp));						\
 } while (0)
 #define	BUF_UNLOCK_RAW(bp) do {						\
 	(void)_lockmgr_args(&(bp)->b_lock, LK_RELEASE, NULL,		\
 	    LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT,		\
 	    LOCK_FILE, LOCK_LINE);					\
 } while (0)
 
 /*
  * Check if a buffer lock is recursed.
  */
 #define	BUF_LOCKRECURSED(bp)						\
 	lockmgr_recursed(&(bp)->b_lock)
 
 /*
  * Check if a buffer lock is currently held.
  */
 #define	BUF_ISLOCKED(bp)						\
 	lockstatus(&(bp)->b_lock)
 /*
  * Free a buffer lock.
  */
 #define BUF_LOCKFREE(bp) 						\
 	lockdestroy(&(bp)->b_lock)
 
 /*
  * Print informations on a buffer lock.
  */
 #define BUF_LOCKPRINTINFO(bp) 						\
 	lockmgr_printinfo(&(bp)->b_lock)
 
 /*
  * Buffer lock assertions.
  */
 #if defined(INVARIANTS) && defined(INVARIANT_SUPPORT)
 #define	BUF_ASSERT_LOCKED(bp)						\
 	_lockmgr_assert(&(bp)->b_lock, KA_LOCKED, LOCK_FILE, LOCK_LINE)
 #define	BUF_ASSERT_SLOCKED(bp)						\
 	_lockmgr_assert(&(bp)->b_lock, KA_SLOCKED, LOCK_FILE, LOCK_LINE)
 #define	BUF_ASSERT_XLOCKED(bp)						\
 	_lockmgr_assert(&(bp)->b_lock, KA_XLOCKED, LOCK_FILE, LOCK_LINE)
 #define	BUF_ASSERT_UNLOCKED(bp)						\
 	_lockmgr_assert(&(bp)->b_lock, KA_UNLOCKED, LOCK_FILE, LOCK_LINE)
 #else
 #define	BUF_ASSERT_LOCKED(bp)
 #define	BUF_ASSERT_SLOCKED(bp)
 #define	BUF_ASSERT_XLOCKED(bp)
 #define	BUF_ASSERT_UNLOCKED(bp)
 #endif
 
 #ifdef _SYS_PROC_H_	/* Avoid #include <sys/proc.h> pollution */
 /*
  * When initiating asynchronous I/O, change ownership of the lock to the
  * kernel. Once done, the lock may legally released by biodone. The
  * original owning process can no longer acquire it recursively, but must
  * wait until the I/O is completed and the lock has been freed by biodone.
  */
 #define	BUF_KERNPROC(bp)						\
 	_lockmgr_disown(&(bp)->b_lock, LOCK_FILE, LOCK_LINE)
 #endif
 
 #endif /* _KERNEL */
 
 struct buf_queue_head {
 	TAILQ_HEAD(buf_queue, buf) queue;
 	daddr_t last_pblkno;
 	struct	buf *insert_point;
 	struct	buf *switch_point;
 };
 
 /*
  * This structure describes a clustered I/O. 
  */
 struct cluster_save {
 	long	bs_bcount;		/* Saved b_bcount. */
 	long	bs_bufsize;		/* Saved b_bufsize. */
 	int	bs_nchildren;		/* Number of associated buffers. */
 	struct buf **bs_children;	/* List of associated buffers. */
 };
 
 #ifdef _KERNEL
 
 static __inline int
 bwrite(struct buf *bp)
 {
 
 	KASSERT(bp->b_bufobj != NULL, ("bwrite: no bufobj bp=%p", bp));
 	KASSERT(bp->b_bufobj->bo_ops != NULL, ("bwrite: no bo_ops bp=%p", bp));
 	KASSERT(bp->b_bufobj->bo_ops->bop_write != NULL,
 	    ("bwrite: no bop_write bp=%p", bp));
 	return (BO_WRITE(bp->b_bufobj, bp));
 }
 
 static __inline void
 bstrategy(struct buf *bp)
 {
 
 	KASSERT(bp->b_bufobj != NULL, ("bstrategy: no bufobj bp=%p", bp));
 	KASSERT(bp->b_bufobj->bo_ops != NULL,
 	    ("bstrategy: no bo_ops bp=%p", bp));
 	KASSERT(bp->b_bufobj->bo_ops->bop_strategy != NULL,
 	    ("bstrategy: no bop_strategy bp=%p", bp));
 	BO_STRATEGY(bp->b_bufobj, bp);
 }
 
 static __inline void
 buf_start(struct buf *bp)
 {
 	KASSERT((bp->b_flags & B_IOSTARTED) == 0,
 	    ("recursed buf_start %p", bp));
 	bp->b_flags |= B_IOSTARTED;
 	if (bioops.io_start)
 		(*bioops.io_start)(bp);
 }
 
 static __inline void
 buf_complete(struct buf *bp)
 {
 	if ((bp->b_flags & B_IOSTARTED) != 0) {
 		bp->b_flags &= ~B_IOSTARTED;
 		if (bioops.io_complete)
 			(*bioops.io_complete)(bp);
 	}
 }
 
 static __inline void
 buf_deallocate(struct buf *bp)
 {
 	if (bioops.io_deallocate)
 		(*bioops.io_deallocate)(bp);
 }
 
 static __inline int
 buf_countdeps(struct buf *bp, int i)
 {
 	if (bioops.io_countdeps)
 		return ((*bioops.io_countdeps)(bp, i));
 	else
 		return (0);
 }
 
 static __inline void
 buf_track(struct buf *bp __unused, const char *location __unused)
 {
 
 #if defined(FULL_BUF_TRACKING)
 	bp->b_io_tracking[BUF_TRACKING_ENTRY(bp->b_io_tcnt++)] = location;
 #elif defined(BUF_TRACKING)
 	bp->b_io_tracking = location;
 #endif
 }
 
 #endif /* _KERNEL */
 
 /*
  * Zero out the buffer's data area.
  */
 #define	clrbuf(bp) {							\
 	bzero((bp)->b_data, (u_int)(bp)->b_bcount);			\
 	(bp)->b_resid = 0;						\
 }
 
 /*
  * Flags for getblk's last parameter.
  */
 #define	GB_LOCK_NOWAIT	0x0001		/* Fail if we block on a buf lock. */
 #define	GB_NOCREAT	0x0002		/* Don't create a buf if not found. */
 #define	GB_NOWAIT_BD	0x0004		/* Do not wait for bufdaemon. */
 #define	GB_UNMAPPED	0x0008		/* Do not mmap buffer pages. */
 #define	GB_KVAALLOC	0x0010		/* But allocate KVA. */
 #define	GB_CKHASH	0x0020		/* If reading, calc checksum hash */
 #define	GB_NOSPARSE	0x0040		/* Do not instantiate holes */
 #define	GB_CVTENXIO	0x0080		/* Convert errors to ENXIO */
 
 #ifdef _KERNEL
 extern int	nbuf;			/* The number of buffer headers */
 extern u_long	maxswzone;		/* Max KVA for swap structures */
 extern u_long	maxbcache;		/* Max KVA for buffer cache */
 extern int	maxbcachebuf;		/* Max buffer cache block size */
 extern long	runningbufspace;
 extern long	hibufspace;
 extern int	dirtybufthresh;
 extern int	bdwriteskip;
 extern int	dirtybufferflushes;
 extern int	altbufferflushes;
 extern int	nswbuf;			/* Number of swap I/O buffer headers. */
 extern caddr_t	unmapped_buf;	/* Data address for unmapped buffers. */
 
 static inline int
 buf_mapped(struct buf *bp)
 {
 
 	return (bp->b_data != unmapped_buf);
 }
 
 void	runningbufwakeup(struct buf *);
 void	waitrunningbufspace(void);
 caddr_t	kern_vfs_bio_buffer_alloc(caddr_t v, long physmem_est);
 void	bufinit(void);
 void	bufshutdown(int);
 void	bdata2bio(struct buf *bp, struct bio *bip);
 void	bwillwrite(void);
 int	buf_dirty_count_severe(void);
 void	bremfree(struct buf *);
 void	bremfreef(struct buf *);	/* XXX Force bremfree, only for nfs. */
 #define bread(vp, blkno, size, cred, bpp) \
 	    breadn_flags(vp, blkno, blkno, size, NULL, NULL, 0, cred, 0, \
 		NULL, bpp)
 #define bread_gb(vp, blkno, size, cred, gbflags, bpp) \
 	    breadn_flags(vp, blkno, blkno, size, NULL, NULL, 0, cred, \
 		gbflags, NULL, bpp)
 #define breadn(vp, blkno, size, rablkno, rabsize, cnt, cred, bpp) \
 	    breadn_flags(vp, blkno, blkno, size, rablkno, rabsize, cnt, cred, \
 		0, NULL, bpp)
 int	breadn_flags(struct vnode *, daddr_t, daddr_t, int, daddr_t *, int *, 
 	    int, struct ucred *, int, void (*)(struct buf *), struct buf **);
 void	bdwrite(struct buf *);
 void	bawrite(struct buf *);
 void	babarrierwrite(struct buf *);
 int	bbarrierwrite(struct buf *);
 void	bdirty(struct buf *);
 void	bundirty(struct buf *);
 void	bufstrategy(struct bufobj *, struct buf *);
 void	brelse(struct buf *);
 void	bqrelse(struct buf *);
 int	vfs_bio_awrite(struct buf *);
 void	vfs_busy_pages_acquire(struct buf *bp);
 void	vfs_busy_pages_release(struct buf *bp);
 struct buf *incore(struct bufobj *, daddr_t);
 bool	inmem(struct vnode *, daddr_t);
 struct buf *gbincore(struct bufobj *, daddr_t);
 struct buf *gbincore_unlocked(struct bufobj *, daddr_t);
 struct buf *getblk(struct vnode *, daddr_t, int, int, int, int);
 int	getblkx(struct vnode *vp, daddr_t blkno, daddr_t dblkno, int size,
 	    int slpflag, int slptimeo, int flags, struct buf **bpp);
 struct buf *geteblk(int, int);
 int	bufwait(struct buf *);
 int	bufwrite(struct buf *);
 void	bufdone(struct buf *);
 void	bd_speedup(void);
 
 extern uma_zone_t pbuf_zone;
 uma_zone_t pbuf_zsecond_create(const char *name, int max);
 
 int	cluster_read(struct vnode *, u_quad_t, daddr_t, long,
 	    struct ucred *, long, int, int, struct buf **);
 int	cluster_wbuild(struct vnode *, long, daddr_t, int, int);
 void	cluster_write(struct vnode *, struct buf *, u_quad_t, int, int);
 void	vfs_bio_brelse(struct buf *bp, int ioflags);
 void	vfs_bio_bzero_buf(struct buf *bp, int base, int size);
 void	vfs_bio_clrbuf(struct buf *);
 void	vfs_bio_set_flags(struct buf *bp, int ioflags);
 void	vfs_bio_set_valid(struct buf *, int base, int size);
 void	vfs_busy_pages(struct buf *, int clear_modify);
 void	vfs_unbusy_pages(struct buf *);
 int	vmapbuf(struct buf *, void *, size_t, int);
 void	vunmapbuf(struct buf *);
 void	brelvp(struct buf *);
 void	bgetvp(struct vnode *, struct buf *);
 void	pbgetbo(struct bufobj *bo, struct buf *bp);
 void	pbgetvp(struct vnode *, struct buf *);
 void	pbrelbo(struct buf *);
 void	pbrelvp(struct buf *);
 int	allocbuf(struct buf *bp, int size);
 void	reassignbuf(struct buf *);
 void	bwait(struct buf *, u_char, const char *);
 void	bdone(struct buf *);
 
 typedef daddr_t (vbg_get_lblkno_t)(struct vnode *, vm_ooffset_t);
 typedef int (vbg_get_blksize_t)(struct vnode *, daddr_t);
 int	vfs_bio_getpages(struct vnode *vp, struct vm_page **ma, int count,
 	    int *rbehind, int *rahead, vbg_get_lblkno_t get_lblkno,
 	    vbg_get_blksize_t get_blksize);
 
 #endif /* _KERNEL */
 
 #endif /* !_SYS_BUF_H_ */
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index 9ae5f58e5218..ca3261a22e62 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -1,1159 +1,1163 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1989, 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)mount.h	8.21 (Berkeley) 5/20/95
  * $FreeBSD$
  */
 
 #ifndef _SYS_MOUNT_H_
 #define _SYS_MOUNT_H_
 
 #include <sys/ucred.h>
 #include <sys/queue.h>
 #ifdef _KERNEL
 #include <sys/lock.h>
 #include <sys/lockmgr.h>
 #include <sys/tslog.h>
 #include <sys/_mutex.h>
 #include <sys/_sx.h>
 #endif
 
 /*
  * NOTE: When changing statfs structure, mount structure, MNT_* flags or
  * MNTK_* flags also update DDB show mount command in vfs_subr.c.
  */
 
 typedef struct fsid { int32_t val[2]; } fsid_t;	/* filesystem id type */
 
 #define fsidcmp(a, b) memcmp((a), (b), sizeof(fsid_t))
 
 /*
  * File identifier.
  * These are unique per filesystem on a single machine.
  *
  * Note that the offset of fid_data is 4 bytes, so care must be taken to avoid
  * undefined behavior accessing unaligned fields within an embedded struct.
  */
 #define	MAXFIDSZ	16
 
 struct fid {
 	u_short		fid_len;		/* length of data in bytes */
 	u_short		fid_data0;		/* force longword alignment */
 	char		fid_data[MAXFIDSZ];	/* data (variable length) */
 };
 
 /*
  * filesystem statistics
  */
 #define	MFSNAMELEN	16		/* length of type name including null */
 #define	MNAMELEN	1024		/* size of on/from name bufs */
 #define	STATFS_VERSION	0x20140518	/* current version number */
 struct statfs {
 	uint32_t f_version;		/* structure version number */
 	uint32_t f_type;		/* type of filesystem */
 	uint64_t f_flags;		/* copy of mount exported flags */
 	uint64_t f_bsize;		/* filesystem fragment size */
 	uint64_t f_iosize;		/* optimal transfer block size */
 	uint64_t f_blocks;		/* total data blocks in filesystem */
 	uint64_t f_bfree;		/* free blocks in filesystem */
 	int64_t	 f_bavail;		/* free blocks avail to non-superuser */
 	uint64_t f_files;		/* total file nodes in filesystem */
 	int64_t	 f_ffree;		/* free nodes avail to non-superuser */
 	uint64_t f_syncwrites;		/* count of sync writes since mount */
 	uint64_t f_asyncwrites;		/* count of async writes since mount */
 	uint64_t f_syncreads;		/* count of sync reads since mount */
 	uint64_t f_asyncreads;		/* count of async reads since mount */
 	uint64_t f_spare[10];		/* unused spare */
 	uint32_t f_namemax;		/* maximum filename length */
 	uid_t	  f_owner;		/* user that mounted the filesystem */
 	fsid_t	  f_fsid;		/* filesystem id */
 	char	  f_charspare[80];	    /* spare string space */
 	char	  f_fstypename[MFSNAMELEN]; /* filesystem type name */
 	char	  f_mntfromname[MNAMELEN];  /* mounted filesystem */
 	char	  f_mntonname[MNAMELEN];    /* directory on which mounted */
 };
 
 #if defined(_WANT_FREEBSD11_STATFS) || defined(_KERNEL)
 #define	FREEBSD11_STATFS_VERSION	0x20030518 /* current version number */
 struct freebsd11_statfs {
 	uint32_t f_version;		/* structure version number */
 	uint32_t f_type;		/* type of filesystem */
 	uint64_t f_flags;		/* copy of mount exported flags */
 	uint64_t f_bsize;		/* filesystem fragment size */
 	uint64_t f_iosize;		/* optimal transfer block size */
 	uint64_t f_blocks;		/* total data blocks in filesystem */
 	uint64_t f_bfree;		/* free blocks in filesystem */
 	int64_t	 f_bavail;		/* free blocks avail to non-superuser */
 	uint64_t f_files;		/* total file nodes in filesystem */
 	int64_t	 f_ffree;		/* free nodes avail to non-superuser */
 	uint64_t f_syncwrites;		/* count of sync writes since mount */
 	uint64_t f_asyncwrites;		/* count of async writes since mount */
 	uint64_t f_syncreads;		/* count of sync reads since mount */
 	uint64_t f_asyncreads;		/* count of async reads since mount */
 	uint64_t f_spare[10];		/* unused spare */
 	uint32_t f_namemax;		/* maximum filename length */
 	uid_t	  f_owner;		/* user that mounted the filesystem */
 	fsid_t	  f_fsid;		/* filesystem id */
 	char	  f_charspare[80];	/* spare string space */
 	char	  f_fstypename[16];	/* filesystem type name */
 	char	  f_mntfromname[88];	/* mounted filesystem */
 	char	  f_mntonname[88];	/* directory on which mounted */
 };
 #endif /* _WANT_FREEBSD11_STATFS || _KERNEL */
 
 #ifdef _KERNEL
 #define	OMFSNAMELEN	16	/* length of fs type name, including null */
 #define	OMNAMELEN	(88 - 2 * sizeof(long))	/* size of on/from name bufs */
 
 /* XXX getfsstat.2 is out of date with write and read counter changes here. */
 /* XXX statfs.2 is out of date with read counter changes here. */
 struct ostatfs {
 	long	f_spare2;		/* placeholder */
 	long	f_bsize;		/* fundamental filesystem block size */
 	long	f_iosize;		/* optimal transfer block size */
 	long	f_blocks;		/* total data blocks in filesystem */
 	long	f_bfree;		/* free blocks in fs */
 	long	f_bavail;		/* free blocks avail to non-superuser */
 	long	f_files;		/* total file nodes in filesystem */
 	long	f_ffree;		/* free file nodes in fs */
 	fsid_t	f_fsid;			/* filesystem id */
 	uid_t	f_owner;		/* user that mounted the filesystem */
 	int	f_type;			/* type of filesystem */
 	int	f_flags;		/* copy of mount exported flags */
 	long	f_syncwrites;		/* count of sync writes since mount */
 	long	f_asyncwrites;		/* count of async writes since mount */
 	char	f_fstypename[OMFSNAMELEN]; /* fs type name */
 	char	f_mntonname[OMNAMELEN];	/* directory on which mounted */
 	long	f_syncreads;		/* count of sync reads since mount */
 	long	f_asyncreads;		/* count of async reads since mount */
 	short	f_spares1;		/* unused spare */
 	char	f_mntfromname[OMNAMELEN];/* mounted filesystem */
 	short	f_spares2;		/* unused spare */
 	/*
 	 * XXX on machines where longs are aligned to 8-byte boundaries, there
 	 * is an unnamed int32_t here.  This spare was after the apparent end
 	 * of the struct until we bit off the read counters from f_mntonname.
 	 */
 	long	f_spare[2];		/* unused spare */
 };
+#endif	/* _KERNEL */
 
+#if defined(_WANT_MOUNT) || defined(_KERNEL)
 TAILQ_HEAD(vnodelst, vnode);
 
 /* Mount options list */
 TAILQ_HEAD(vfsoptlist, vfsopt);
 struct vfsopt {
 	TAILQ_ENTRY(vfsopt) link;
 	char	*name;
 	void	*value;
 	int	len;
 	int	pos;
 	int	seen;
 };
 
 struct mount_pcpu {
 	int		mntp_thread_in_ops;
 	int		mntp_ref;
 	int		mntp_lockref;
 	int		mntp_writeopcount;
 };
 
 _Static_assert(sizeof(struct mount_pcpu) == 16,
     "the struct is allocated from pcpu 16 zone");
 
 /*
  * Structure per mounted filesystem.  Each mounted filesystem has an
  * array of operations and an instance record.  The filesystems are
  * put on a doubly linked list.
  *
  * Lock reference:
  * 	l - mnt_listmtx
  *	m - mountlist_mtx
  *	i - interlock
  *	v - vnode freelist mutex
  *
  * Unmarked fields are considered stable as long as a ref is held.
  *
  */
 struct mount {
 	int 		mnt_vfs_ops;		/* (i) pending vfs ops */
 	int		mnt_kern_flag;		/* (i) kernel only flags */
 	uint64_t	mnt_flag;		/* (i) flags shared with user */
 	struct mount_pcpu *mnt_pcpu;		/* per-CPU data */
 	struct vnode	*mnt_rootvnode;
 	struct vnode	*mnt_vnodecovered;	/* vnode we mounted on */
 	struct vfsops	*mnt_op;		/* operations on fs */
 	struct vfsconf	*mnt_vfc;		/* configuration info */
 	struct mtx __aligned(CACHE_LINE_SIZE)	mnt_mtx; /* mount structure interlock */
 	int		mnt_gen;		/* struct mount generation */
 #define	mnt_startzero	mnt_list
 	TAILQ_ENTRY(mount) mnt_list;		/* (m) mount list */
 	struct vnode	*mnt_syncer;		/* syncer vnode */
 	int		mnt_ref;		/* (i) Reference count */
 	struct vnodelst	mnt_nvnodelist;		/* (i) list of vnodes */
 	int		mnt_nvnodelistsize;	/* (i) # of vnodes */
 	int		mnt_writeopcount;	/* (i) write syscalls pending */
 	struct vfsoptlist *mnt_opt;		/* current mount options */
 	struct vfsoptlist *mnt_optnew;		/* new options passed to fs */
 	int		mnt_maxsymlinklen;	/* max size of short symlink */
 	struct statfs	mnt_stat;		/* cache of filesystem stats */
 	struct ucred	*mnt_cred;		/* credentials of mounter */
 	void *		mnt_data;		/* private data */
 	time_t		mnt_time;		/* last time written*/
 	int		mnt_iosize_max;		/* max size for clusters, etc */
 	struct netexport *mnt_export;		/* export list */
 	struct label	*mnt_label;		/* MAC label for the fs */
 	u_int		mnt_hashseed;		/* Random seed for vfs_hash */
 	int		mnt_lockref;		/* (i) Lock reference count */
 	int		mnt_secondary_writes;   /* (i) # of secondary writes */
 	int		mnt_secondary_accwrites;/* (i) secondary wr. starts */
 	struct thread	*mnt_susp_owner;	/* (i) thread owning suspension */
 #define	mnt_endzero	mnt_gjprovider
 	char		*mnt_gjprovider;	/* gjournal provider name */
 	struct mtx	mnt_listmtx;
 	struct vnodelst	mnt_lazyvnodelist;	/* (l) list of lazy vnodes */
 	int		mnt_lazyvnodelistsize;	/* (l) # of lazy vnodes */
 	struct lock	mnt_explock;		/* vfs_export walkers lock */
 	TAILQ_ENTRY(mount) mnt_upper_link;	/* (m) we in the all uppers */
 	TAILQ_HEAD(, mount) mnt_uppers;		/* (m) upper mounts over us*/
 };
+#endif	/* _WANT_MOUNT || _KERNEL */
 
+#ifdef _KERNEL
 /*
  * Definitions for MNT_VNODE_FOREACH_ALL.
  */
 struct vnode *__mnt_vnode_next_all(struct vnode **mvp, struct mount *mp);
 struct vnode *__mnt_vnode_first_all(struct vnode **mvp, struct mount *mp);
 void          __mnt_vnode_markerfree_all(struct vnode **mvp, struct mount *mp);
 
 #define MNT_VNODE_FOREACH_ALL(vp, mp, mvp)				\
 	for (vp = __mnt_vnode_first_all(&(mvp), (mp));			\
 		(vp) != NULL; vp = __mnt_vnode_next_all(&(mvp), (mp)))
 
 #define MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp)				\
 	do {								\
 		MNT_ILOCK(mp);						\
 		__mnt_vnode_markerfree_all(&(mvp), (mp));		\
 		/* MNT_IUNLOCK(mp); -- done in above function */	\
 		mtx_assert(MNT_MTX(mp), MA_NOTOWNED);			\
 	} while (0)
 
 /*
  * Definitions for MNT_VNODE_FOREACH_LAZY.
  */
 typedef int mnt_lazy_cb_t(struct vnode *, void *);
 struct vnode *__mnt_vnode_next_lazy(struct vnode **mvp, struct mount *mp,
     mnt_lazy_cb_t *cb, void *cbarg);
 struct vnode *__mnt_vnode_first_lazy(struct vnode **mvp, struct mount *mp,
     mnt_lazy_cb_t *cb, void *cbarg);
 void          __mnt_vnode_markerfree_lazy(struct vnode **mvp, struct mount *mp);
 
 #define MNT_VNODE_FOREACH_LAZY(vp, mp, mvp, cb, cbarg)			\
 	for (vp = __mnt_vnode_first_lazy(&(mvp), (mp), (cb), (cbarg));	\
 		(vp) != NULL; 						\
 		vp = __mnt_vnode_next_lazy(&(mvp), (mp), (cb), (cbarg)))
 
 #define MNT_VNODE_FOREACH_LAZY_ABORT(mp, mvp)				\
 	__mnt_vnode_markerfree_lazy(&(mvp), (mp))
 
 #define	MNT_ILOCK(mp)	mtx_lock(&(mp)->mnt_mtx)
 #define	MNT_ITRYLOCK(mp) mtx_trylock(&(mp)->mnt_mtx)
 #define	MNT_IUNLOCK(mp)	mtx_unlock(&(mp)->mnt_mtx)
 #define	MNT_MTX(mp)	(&(mp)->mnt_mtx)
 
 #define	MNT_REF(mp)	do {						\
 	mtx_assert(MNT_MTX(mp), MA_OWNED);				\
 	mp->mnt_ref++;							\
 } while (0)
 #define	MNT_REL(mp)	do {						\
 	mtx_assert(MNT_MTX(mp), MA_OWNED);				\
 	(mp)->mnt_ref--;						\
 	if ((mp)->mnt_vfs_ops && (mp)->mnt_ref < 0)		\
 		vfs_dump_mount_counters(mp);				\
 	if ((mp)->mnt_ref == 0 && (mp)->mnt_vfs_ops)		\
 		wakeup((mp));						\
 } while (0)
 
 #endif /* _KERNEL */
 
 #if defined(_WANT_MNTOPTNAMES) || defined(_KERNEL)
 struct mntoptnames {
 	uint64_t o_opt;
 	const char *o_name;
 };
 #define MNTOPT_NAMES							\
 	{ MNT_ASYNC,		"asynchronous" },			\
 	{ MNT_EXPORTED,		"NFS exported" },			\
 	{ MNT_LOCAL,		"local" },				\
 	{ MNT_NOATIME,		"noatime" },				\
 	{ MNT_NOEXEC,		"noexec" },				\
 	{ MNT_NOSUID,		"nosuid" },				\
 	{ MNT_NOSYMFOLLOW,	"nosymfollow" },			\
 	{ MNT_QUOTA,		"with quotas" },			\
 	{ MNT_RDONLY,		"read-only" },				\
 	{ MNT_SYNCHRONOUS,	"synchronous" },			\
 	{ MNT_UNION,		"union" },				\
 	{ MNT_NOCLUSTERR,	"noclusterr" },				\
 	{ MNT_NOCLUSTERW,	"noclusterw" },				\
 	{ MNT_SUIDDIR,		"suiddir" },				\
 	{ MNT_SOFTDEP,		"soft-updates" },			\
 	{ MNT_SUJ,		"journaled soft-updates" },		\
 	{ MNT_MULTILABEL,	"multilabel" },				\
 	{ MNT_ACLS,		"acls" },				\
 	{ MNT_NFS4ACLS,		"nfsv4acls" },				\
 	{ MNT_GJOURNAL,		"gjournal" },				\
 	{ MNT_AUTOMOUNTED,	"automounted" },			\
 	{ MNT_VERIFIED,		"verified" },				\
 	{ MNT_UNTRUSTED,	"untrusted" },				\
 	{ MNT_NOCOVER,		"nocover" },				\
 	{ MNT_EMPTYDIR,		"emptydir" },				\
 	{ MNT_UPDATE,		"update" },				\
 	{ MNT_DELEXPORT,	"delexport" },				\
 	{ MNT_RELOAD,		"reload" },				\
 	{ MNT_FORCE,		"force" },				\
 	{ MNT_SNAPSHOT,		"snapshot" },				\
 	{ 0, NULL }
 #endif
 
 /*
  * User specifiable flags, stored in mnt_flag.
  */
 #define	MNT_RDONLY	0x0000000000000001ULL /* read only filesystem */
 #define	MNT_SYNCHRONOUS	0x0000000000000002ULL /* fs written synchronously */
 #define	MNT_NOEXEC	0x0000000000000004ULL /* can't exec from filesystem */
 #define	MNT_NOSUID	0x0000000000000008ULL /* don't honor setuid fs bits */
 #define	MNT_NFS4ACLS	0x0000000000000010ULL /* enable NFS version 4 ACLs */
 #define	MNT_UNION	0x0000000000000020ULL /* union with underlying fs */
 #define	MNT_ASYNC	0x0000000000000040ULL /* fs written asynchronously */
 #define	MNT_SUIDDIR	0x0000000000100000ULL /* special SUID dir handling */
 #define	MNT_SOFTDEP	0x0000000000200000ULL /* using soft updates */
 #define	MNT_NOSYMFOLLOW	0x0000000000400000ULL /* do not follow symlinks */
 #define	MNT_GJOURNAL	0x0000000002000000ULL /* GEOM journal support enabled */
 #define	MNT_MULTILABEL	0x0000000004000000ULL /* MAC support for objects */
 #define	MNT_ACLS	0x0000000008000000ULL /* ACL support enabled */
 #define	MNT_NOATIME	0x0000000010000000ULL /* dont update file access time */
 #define	MNT_NOCLUSTERR	0x0000000040000000ULL /* disable cluster read */
 #define	MNT_NOCLUSTERW	0x0000000080000000ULL /* disable cluster write */
 #define	MNT_SUJ		0x0000000100000000ULL /* using journaled soft updates */
 #define	MNT_AUTOMOUNTED	0x0000000200000000ULL /* mounted by automountd(8) */
 #define	MNT_UNTRUSTED	0x0000000800000000ULL /* filesys metadata untrusted */
 
 /*
  * NFS export related mount flags.
  */
 #define	MNT_EXRDONLY	0x0000000000000080ULL	/* exported read only */
 #define	MNT_EXPORTED	0x0000000000000100ULL	/* filesystem is exported */
 #define	MNT_DEFEXPORTED	0x0000000000000200ULL	/* exported to the world */
 #define	MNT_EXPORTANON	0x0000000000000400ULL	/* anon uid mapping for all */
 #define	MNT_EXKERB	0x0000000000000800ULL	/* exported with Kerberos */
 #define	MNT_EXPUBLIC	0x0000000020000000ULL	/* public export (WebNFS) */
 #define	MNT_EXTLS	0x0000004000000000ULL /* require TLS */
 #define	MNT_EXTLSCERT	0x0000008000000000ULL /* require TLS with client cert */
 #define	MNT_EXTLSCERTUSER 0x0000010000000000ULL /* require TLS with user cert */
 
 /*
  * Flags set by internal operations,
  * but visible to the user.
  * XXX some of these are not quite right.. (I've never seen the root flag set)
  */
 #define	MNT_LOCAL	0x0000000000001000ULL /* filesystem is stored locally */
 #define	MNT_QUOTA	0x0000000000002000ULL /* quotas are enabled on fs */
 #define	MNT_ROOTFS	0x0000000000004000ULL /* identifies the root fs */
 #define	MNT_USER	0x0000000000008000ULL /* mounted by a user */
 #define	MNT_IGNORE	0x0000000000800000ULL /* do not show entry in df */
 #define	MNT_VERIFIED	0x0000000400000000ULL /* filesystem is verified */
 
 /*
  * Mask of flags that are visible to statfs().
  * XXX I think that this could now become (~(MNT_CMDFLAGS))
  * but the 'mount' program may need changing to handle this.
  */
 #define	MNT_VISFLAGMASK	(MNT_RDONLY	| MNT_SYNCHRONOUS | MNT_NOEXEC	| \
 			MNT_NOSUID	| MNT_UNION	| MNT_SUJ	| \
 			MNT_ASYNC	| MNT_EXRDONLY	| MNT_EXPORTED	| \
 			MNT_DEFEXPORTED	| MNT_EXPORTANON| MNT_EXKERB	| \
 			MNT_LOCAL	| MNT_USER	| MNT_QUOTA	| \
 			MNT_ROOTFS	| MNT_NOATIME	| MNT_NOCLUSTERR| \
 			MNT_NOCLUSTERW	| MNT_SUIDDIR	| MNT_SOFTDEP	| \
 			MNT_IGNORE	| MNT_EXPUBLIC	| MNT_NOSYMFOLLOW | \
 			MNT_GJOURNAL	| MNT_MULTILABEL | MNT_ACLS	| \
 			MNT_NFS4ACLS	| MNT_AUTOMOUNTED | MNT_VERIFIED | \
 			MNT_UNTRUSTED)
 
 /* Mask of flags that can be updated. */
 #define	MNT_UPDATEMASK (MNT_NOSUID	| MNT_NOEXEC	| \
 			MNT_SYNCHRONOUS	| MNT_UNION	| MNT_ASYNC	| \
 			MNT_NOATIME | \
 			MNT_NOSYMFOLLOW	| MNT_IGNORE	| \
 			MNT_NOCLUSTERR	| MNT_NOCLUSTERW | MNT_SUIDDIR	| \
 			MNT_ACLS	| MNT_USER	| MNT_NFS4ACLS	| \
 			MNT_AUTOMOUNTED | MNT_UNTRUSTED)
 
 /*
  * External filesystem command modifier flags.
  * Unmount can use the MNT_FORCE flag.
  * XXX: These are not STATES and really should be somewhere else.
  * XXX: MNT_BYFSID and MNT_NONBUSY collide with MNT_ACLS and MNT_MULTILABEL,
  *      but because MNT_ACLS and MNT_MULTILABEL are only used for mount(2),
  *      and MNT_BYFSID and MNT_NONBUSY are only used for unmount(2),
  *      it's harmless.
  */
 #define	MNT_UPDATE	0x0000000000010000ULL /* not real mount, just update */
 #define	MNT_DELEXPORT	0x0000000000020000ULL /* delete export host lists */
 #define	MNT_RELOAD	0x0000000000040000ULL /* reload filesystem data */
 #define	MNT_FORCE	0x0000000000080000ULL /* force unmount or readonly */
 #define	MNT_SNAPSHOT	0x0000000001000000ULL /* snapshot the filesystem */
 #define	MNT_NONBUSY	0x0000000004000000ULL /* check vnode use counts. */
 #define	MNT_BYFSID	0x0000000008000000ULL /* specify filesystem by ID. */
 #define	MNT_NOCOVER	0x0000001000000000ULL /* Do not cover a mount point */
 #define	MNT_EMPTYDIR	0x0000002000000000ULL /* Only mount on empty dir */
 #define MNT_CMDFLAGS   (MNT_UPDATE	| MNT_DELEXPORT	| MNT_RELOAD	| \
 			MNT_FORCE	| MNT_SNAPSHOT	| MNT_NONBUSY	| \
 			MNT_BYFSID	| MNT_NOCOVER	| MNT_EMPTYDIR)
 /*
  * Internal filesystem control flags stored in mnt_kern_flag.
  *
  * MNTK_UNMOUNT locks the mount entry so that name lookup cannot
  * proceed past the mount point.  This keeps the subtree stable during
  * mounts and unmounts.  When non-forced unmount flushes all vnodes
  * from the mp queue, the MNTK_UNMOUNT flag prevents insmntque() from
  * queueing new vnodes.
  *
  * MNTK_UNMOUNTF permits filesystems to detect a forced unmount while
  * dounmount() is still waiting to lock the mountpoint. This allows
  * the filesystem to cancel operations that might otherwise deadlock
  * with the unmount attempt (used by NFS).
  */
 #define MNTK_UNMOUNTF	0x00000001	/* forced unmount in progress */
 #define MNTK_ASYNC	0x00000002	/* filtered async flag */
 #define MNTK_SOFTDEP	0x00000004	/* async disabled by softdep */
 #define MNTK_NOMSYNC	0x00000008	/* don't do msync */
 #define	MNTK_DRAINING	0x00000010	/* lock draining is happening */
 #define	MNTK_REFEXPIRE	0x00000020	/* refcount expiring is happening */
 #define MNTK_EXTENDED_SHARED	0x00000040 /* Allow shared locking for more ops */
 #define	MNTK_SHARED_WRITES	0x00000080 /* Allow shared locking for writes */
 #define	MNTK_NO_IOPF	0x00000100	/* Disallow page faults during reads
 					   and writes. Filesystem shall properly
 					   handle i/o state on EFAULT. */
 #define	MNTK_VGONE_UPPER	0x00000200
 #define	MNTK_VGONE_WAITER	0x00000400
 #define	MNTK_LOOKUP_EXCL_DOTDOT	0x00000800
 #define	MNTK_MARKER		0x00001000
 #define	MNTK_UNMAPPED_BUFS	0x00002000
 #define	MNTK_USES_BCACHE	0x00004000 /* FS uses the buffer cache. */
 #define	MNTK_TEXT_REFS		0x00008000 /* Keep use ref for text */
 #define	MNTK_VMSETSIZE_BUG	0x00010000
 #define	MNTK_UNIONFS	0x00020000	/* A hack for F_ISUNIONSTACK */
 #define	MNTK_FPLOOKUP	0x00040000	/* fast path lookup is supported */
 #define	MNTK_SUSPEND_ALL	0x00080000 /* Suspended by all-fs suspension */
 #define MNTK_NOASYNC	0x00800000	/* disable async */
 #define MNTK_UNMOUNT	0x01000000	/* unmount in progress */
 #define	MNTK_MWAIT	0x02000000	/* waiting for unmount to finish */
 #define	MNTK_SUSPEND	0x08000000	/* request write suspension */
 #define	MNTK_SUSPEND2	0x04000000	/* block secondary writes */
 #define	MNTK_SUSPENDED	0x10000000	/* write operations are suspended */
 #define	MNTK_NULL_NOCACHE	0x20000000 /* auto disable cache for nullfs
 					      mounts over this fs */
 #define MNTK_LOOKUP_SHARED	0x40000000 /* FS supports shared lock lookups */
 #define	MNTK_NOKNOTE	0x80000000	/* Don't send KNOTEs from VOP hooks */
 
 #ifdef _KERNEL
 static inline int
 MNT_SHARED_WRITES(struct mount *mp)
 {
 
 	return (mp != NULL && (mp->mnt_kern_flag & MNTK_SHARED_WRITES) != 0);
 }
 
 static inline int
 MNT_EXTENDED_SHARED(struct mount *mp)
 {
 
 	return (mp != NULL && (mp->mnt_kern_flag & MNTK_EXTENDED_SHARED) != 0);
 }
 #endif
 
 /*
  * Sysctl CTL_VFS definitions.
  *
  * Second level identifier specifies which filesystem. Second level
  * identifier VFS_VFSCONF returns information about all filesystems.
  * Second level identifier VFS_GENERIC is non-terminal.
  */
 #define	VFS_VFSCONF		0	/* get configured filesystems */
 #define	VFS_GENERIC		0	/* generic filesystem information */
 /*
  * Third level identifiers for VFS_GENERIC are given below; third
  * level identifiers for specific filesystems are given in their
  * mount specific header files.
  */
 #define VFS_MAXTYPENUM	1	/* int: highest defined filesystem type */
 #define VFS_CONF	2	/* struct: vfsconf for filesystem given
 				   as next argument */
 
 /*
  * Flags for various system call interfaces.
  *
  * waitfor flags to vfs_sync() and getfsstat()
  */
 #define MNT_WAIT	1	/* synchronously wait for I/O to complete */
 #define MNT_NOWAIT	2	/* start all I/O, but do not wait for it */
 #define MNT_LAZY	3	/* push data not written by filesystem syncer */
 #define MNT_SUSPEND	4	/* Suspend file system after sync */
 
 /*
  * Generic file handle
  */
 struct fhandle {
 	fsid_t	fh_fsid;	/* Filesystem id of mount point */
 	struct	fid fh_fid;	/* Filesys specific id */
 };
 typedef struct fhandle	fhandle_t;
 
 /*
  * Old export arguments without security flavor list
  */
 struct oexport_args {
 	int	ex_flags;		/* export related flags */
 	uid_t	ex_root;		/* mapping for root uid */
 	struct	xucred ex_anon;		/* mapping for anonymous user */
 	struct	sockaddr *ex_addr;	/* net address to which exported */
 	u_char	ex_addrlen;		/* and the net address length */
 	struct	sockaddr *ex_mask;	/* mask of valid bits in saddr */
 	u_char	ex_masklen;		/* and the smask length */
 	char	*ex_indexfile;		/* index file for WebNFS URLs */
 };
 
 /*
  * Not quite so old export arguments with 32bit ex_flags and xucred ex_anon.
  */
 #define	MAXSECFLAVORS	5
 struct o2export_args {
 	int	ex_flags;		/* export related flags */
 	uid_t	ex_root;		/* mapping for root uid */
 	struct	xucred ex_anon;		/* mapping for anonymous user */
 	struct	sockaddr *ex_addr;	/* net address to which exported */
 	u_char	ex_addrlen;		/* and the net address length */
 	struct	sockaddr *ex_mask;	/* mask of valid bits in saddr */
 	u_char	ex_masklen;		/* and the smask length */
 	char	*ex_indexfile;		/* index file for WebNFS URLs */
 	int	ex_numsecflavors;	/* security flavor count */
 	int	ex_secflavors[MAXSECFLAVORS]; /* list of security flavors */
 };
 
 /*
  * Export arguments for local filesystem mount calls.
  */
 struct export_args {
 	uint64_t ex_flags;		/* export related flags */
 	uid_t	ex_root;		/* mapping for root uid */
 	uid_t	ex_uid;			/* mapping for anonymous user */
 	int	ex_ngroups;
 	gid_t	*ex_groups;
 	struct	sockaddr *ex_addr;	/* net address to which exported */
 	u_char	ex_addrlen;		/* and the net address length */
 	struct	sockaddr *ex_mask;	/* mask of valid bits in saddr */
 	u_char	ex_masklen;		/* and the smask length */
 	char	*ex_indexfile;		/* index file for WebNFS URLs */
 	int	ex_numsecflavors;	/* security flavor count */
 	int	ex_secflavors[MAXSECFLAVORS]; /* list of security flavors */
 };
 
 /*
  * Structure holding information for a publicly exported filesystem
  * (WebNFS). Currently the specs allow just for one such filesystem.
  */
 struct nfs_public {
 	int		np_valid;	/* Do we hold valid information */
 	fhandle_t	np_handle;	/* Filehandle for pub fs (internal) */
 	struct mount	*np_mount;	/* Mountpoint of exported fs */
 	char		*np_index;	/* Index file */
 };
 
 /*
  * Filesystem configuration information. One of these exists for each
  * type of filesystem supported by the kernel. These are searched at
  * mount time to identify the requested filesystem.
  *
  * XXX: Never change the first two arguments!
  */
 struct vfsconf {
 	u_int	vfc_version;		/* ABI version number */
 	char	vfc_name[MFSNAMELEN];	/* filesystem type name */
 	struct	vfsops *vfc_vfsops;	/* filesystem operations vector */
 	struct	vfsops *vfc_vfsops_sd;	/* ... signal-deferred */
 	int	vfc_typenum;		/* historic filesystem type number */
 	int	vfc_refcount;		/* number mounted of this type */
 	int	vfc_flags;		/* permanent flags */
 	int	vfc_prison_flag;	/* prison allow.mount.* flag */
 	struct	vfsoptdecl *vfc_opts;	/* mount options */
 	TAILQ_ENTRY(vfsconf) vfc_list;	/* list of vfscons */
 };
 
 /* Userland version of the struct vfsconf. */
 struct xvfsconf {
 	struct	vfsops *vfc_vfsops;	/* filesystem operations vector */
 	char	vfc_name[MFSNAMELEN];	/* filesystem type name */
 	int	vfc_typenum;		/* historic filesystem type number */
 	int	vfc_refcount;		/* number mounted of this type */
 	int	vfc_flags;		/* permanent flags */
 	struct	vfsconf *vfc_next;	/* next in list */
 };
 
 #ifndef BURN_BRIDGES
 struct ovfsconf {
 	void	*vfc_vfsops;
 	char	vfc_name[32];
 	int	vfc_index;
 	int	vfc_refcount;
 	int	vfc_flags;
 };
 #endif
 
 /*
  * NB: these flags refer to IMPLEMENTATION properties, not properties of
  * any actual mounts; i.e., it does not make sense to change the flags.
  */
 #define	VFCF_STATIC	0x00010000	/* statically compiled into kernel */
 #define	VFCF_NETWORK	0x00020000	/* may get data over the network */
 #define	VFCF_READONLY	0x00040000	/* writes are not implemented */
 #define	VFCF_SYNTHETIC	0x00080000	/* data does not represent real files */
 #define	VFCF_LOOPBACK	0x00100000	/* aliases some other mounted FS */
 #define	VFCF_UNICODE	0x00200000	/* stores file names as Unicode */
 #define	VFCF_JAIL	0x00400000	/* can be mounted from within a jail */
 #define	VFCF_DELEGADMIN	0x00800000	/* supports delegated administration */
 #define	VFCF_SBDRY	0x01000000	/* Stop at Boundary: defer stop requests
 					   to kernel->user (AST) transition */
 
 typedef uint32_t fsctlop_t;
 
 struct vfsidctl {
 	int		vc_vers;	/* should be VFSIDCTL_VERS1 (below) */
 	fsid_t		vc_fsid;	/* fsid to operate on */
 	char		vc_fstypename[MFSNAMELEN];
 					/* type of fs 'nfs' or '*' */
 	fsctlop_t	vc_op;		/* operation VFS_CTL_* (below) */
 	void		*vc_ptr;	/* pointer to data structure */
 	size_t		vc_len;		/* sizeof said structure */
 	u_int32_t	vc_spare[12];	/* spare (must be zero) */
 };
 
 /* vfsidctl API version. */
 #define VFS_CTL_VERS1	0x01
 
 /*
  * New style VFS sysctls, do not reuse/conflict with the namespace for
  * private sysctls.
  * All "global" sysctl ops have the 33rd bit set:
  * 0x...1....
  * Private sysctl ops should have the 33rd bit unset.
  */
 #define VFS_CTL_QUERY	0x00010001	/* anything wrong? (vfsquery) */
 #define VFS_CTL_TIMEO	0x00010002	/* set timeout for vfs notification */
 #define VFS_CTL_NOLOCKS	0x00010003	/* disable file locking */
 
 struct vfsquery {
 	u_int32_t	vq_flags;
 	u_int32_t	vq_spare[31];
 };
 
 /* vfsquery flags */
 #define VQ_NOTRESP	0x0001	/* server down */
 #define VQ_NEEDAUTH	0x0002	/* server bad auth */
 #define VQ_LOWDISK	0x0004	/* we're low on space */
 #define VQ_MOUNT	0x0008	/* new filesystem arrived */
 #define VQ_UNMOUNT	0x0010	/* filesystem has left */
 #define VQ_DEAD		0x0020	/* filesystem is dead, needs force unmount */
 #define VQ_ASSIST	0x0040	/* filesystem needs assistance from external
 				   program */
 #define VQ_NOTRESPLOCK	0x0080	/* server lockd down */
 #define VQ_FLAG0100	0x0100	/* placeholder */
 #define VQ_FLAG0200	0x0200	/* placeholder */
 #define VQ_FLAG0400	0x0400	/* placeholder */
 #define VQ_FLAG0800	0x0800	/* placeholder */
 #define VQ_FLAG1000	0x1000	/* placeholder */
 #define VQ_FLAG2000	0x2000	/* placeholder */
 #define VQ_FLAG4000	0x4000	/* placeholder */
 #define VQ_FLAG8000	0x8000	/* placeholder */
 
 #ifdef _KERNEL
 /* Point a sysctl request at a vfsidctl's data. */
 #define VCTLTOREQ(vc, req)						\
 	do {								\
 		(req)->newptr = (vc)->vc_ptr;				\
 		(req)->newlen = (vc)->vc_len;				\
 		(req)->newidx = 0;					\
 	} while (0)
 #endif
 
 struct iovec;
 struct uio;
 
 #ifdef _KERNEL
 
 /*
  * vfs_busy specific flags and mask.
  */
 #define	MBF_NOWAIT	0x01
 #define	MBF_MNTLSTLOCK	0x02
 #define	MBF_MASK	(MBF_NOWAIT | MBF_MNTLSTLOCK)
 
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_MOUNT);
 MALLOC_DECLARE(M_STATFS);
 #endif
 extern int maxvfsconf;		/* highest defined filesystem type */
 
 TAILQ_HEAD(vfsconfhead, vfsconf);
 extern struct vfsconfhead vfsconf;
 
 /*
  * Operations supported on mounted filesystem.
  */
 struct mount_args;
 struct nameidata;
 struct sysctl_req;
 struct mntarg;
 
 /*
  * N.B., vfs_cmount is the ancient vfsop invoked by the old mount(2) syscall.
  * The new way is vfs_mount.
  *
  * vfs_cmount implementations typically translate arguments from their
  * respective old per-FS structures into the key-value list supported by
  * nmount(2), then use kernel_mount(9) to mimic nmount(2) from kernelspace.
  *
  * Filesystems with mounters that use nmount(2) do not need to and should not
  * implement vfs_cmount.  Hopefully a future cleanup can remove vfs_cmount and
  * mount(2) entirely.
  */
 typedef int vfs_cmount_t(struct mntarg *ma, void *data, uint64_t flags);
 typedef int vfs_unmount_t(struct mount *mp, int mntflags);
 typedef int vfs_root_t(struct mount *mp, int flags, struct vnode **vpp);
 typedef	int vfs_quotactl_t(struct mount *mp, int cmds, uid_t uid, void *arg);
 typedef	int vfs_statfs_t(struct mount *mp, struct statfs *sbp);
 typedef	int vfs_sync_t(struct mount *mp, int waitfor);
 typedef	int vfs_vget_t(struct mount *mp, ino_t ino, int flags,
 		    struct vnode **vpp);
 typedef	int vfs_fhtovp_t(struct mount *mp, struct fid *fhp,
 		    int flags, struct vnode **vpp);
 typedef	int vfs_checkexp_t(struct mount *mp, struct sockaddr *nam,
 		    uint64_t *extflagsp, struct ucred **credanonp,
 		    int *numsecflavors, int *secflavors);
 typedef	int vfs_init_t(struct vfsconf *);
 typedef	int vfs_uninit_t(struct vfsconf *);
 typedef	int vfs_extattrctl_t(struct mount *mp, int cmd,
 		    struct vnode *filename_vp, int attrnamespace,
 		    const char *attrname);
 typedef	int vfs_mount_t(struct mount *mp);
 typedef int vfs_sysctl_t(struct mount *mp, fsctlop_t op,
 		    struct sysctl_req *req);
 typedef void vfs_susp_clean_t(struct mount *mp);
 typedef void vfs_notify_lowervp_t(struct mount *mp, struct vnode *lowervp);
 typedef void vfs_purge_t(struct mount *mp);
 
 struct vfsops {
 	vfs_mount_t		*vfs_mount;
 	vfs_cmount_t		*vfs_cmount;
 	vfs_unmount_t		*vfs_unmount;
 	vfs_root_t		*vfs_root;
 	vfs_root_t		*vfs_cachedroot;
 	vfs_quotactl_t		*vfs_quotactl;
 	vfs_statfs_t		*vfs_statfs;
 	vfs_sync_t		*vfs_sync;
 	vfs_vget_t		*vfs_vget;
 	vfs_fhtovp_t		*vfs_fhtovp;
 	vfs_checkexp_t		*vfs_checkexp;
 	vfs_init_t		*vfs_init;
 	vfs_uninit_t		*vfs_uninit;
 	vfs_extattrctl_t	*vfs_extattrctl;
 	vfs_sysctl_t		*vfs_sysctl;
 	vfs_susp_clean_t	*vfs_susp_clean;
 	vfs_notify_lowervp_t	*vfs_reclaim_lowervp;
 	vfs_notify_lowervp_t	*vfs_unlink_lowervp;
 	vfs_purge_t		*vfs_purge;
 	vfs_mount_t		*vfs_spare[6];	/* spares for ABI compat */
 };
 
 vfs_statfs_t	__vfs_statfs;
 
 #define	VFS_MOUNT(MP) ({						\
 	int _rc;							\
 									\
 	TSRAW(curthread, TS_ENTER, "VFS_MOUNT", (MP)->mnt_vfc->vfc_name);\
 	_rc = (*(MP)->mnt_op->vfs_mount)(MP);				\
 	TSRAW(curthread, TS_EXIT, "VFS_MOUNT", (MP)->mnt_vfc->vfc_name);\
 	_rc; })
 
 #define	VFS_UNMOUNT(MP, FORCE) ({					\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_unmount)(MP, FORCE);			\
 	_rc; })
 
 #define	VFS_ROOT(MP, FLAGS, VPP) ({					\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_root)(MP, FLAGS, VPP);		\
 	_rc; })
 
 #define	VFS_CACHEDROOT(MP, FLAGS, VPP) ({				\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_cachedroot)(MP, FLAGS, VPP);		\
 	_rc; })
 
 #define	VFS_QUOTACTL(MP, C, U, A) ({					\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_quotactl)(MP, C, U, A);		\
 	_rc; })
 
 #define	VFS_STATFS(MP, SBP) ({						\
 	int _rc;							\
 									\
 	_rc = __vfs_statfs((MP), (SBP));				\
 	_rc; })
 
 #define	VFS_SYNC(MP, WAIT) ({						\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_sync)(MP, WAIT);			\
 	_rc; })
 
 #define	VFS_VGET(MP, INO, FLAGS, VPP) ({				\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_vget)(MP, INO, FLAGS, VPP);		\
 	_rc; })
 
 #define	VFS_FHTOVP(MP, FIDP, FLAGS, VPP) ({				\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, FLAGS, VPP);	\
 	_rc; })
 
 #define	VFS_CHECKEXP(MP, NAM, EXFLG, CRED, NUMSEC, SEC) ({		\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED, NUMSEC,\
 	    SEC);							\
 	_rc; })
 
 #define	VFS_EXTATTRCTL(MP, C, FN, NS, N) ({				\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N);	\
 	_rc; })
 
 #define	VFS_SYSCTL(MP, OP, REQ) ({					\
 	int _rc;							\
 									\
 	_rc = (*(MP)->mnt_op->vfs_sysctl)(MP, OP, REQ);			\
 	_rc; })
 
 #define	VFS_SUSP_CLEAN(MP) do {						\
 	if (*(MP)->mnt_op->vfs_susp_clean != NULL) {			\
 		(*(MP)->mnt_op->vfs_susp_clean)(MP);			\
 	}								\
 } while (0)
 
 #define	VFS_RECLAIM_LOWERVP(MP, VP) do {				\
 	if (*(MP)->mnt_op->vfs_reclaim_lowervp != NULL) {		\
 		(*(MP)->mnt_op->vfs_reclaim_lowervp)((MP), (VP));	\
 	}								\
 } while (0)
 
 #define	VFS_UNLINK_LOWERVP(MP, VP) do {					\
 	if (*(MP)->mnt_op->vfs_unlink_lowervp != NULL) {		\
 		(*(MP)->mnt_op->vfs_unlink_lowervp)((MP), (VP));	\
 	}								\
 } while (0)
 
 #define	VFS_PURGE(MP) do {						\
 	if (*(MP)->mnt_op->vfs_purge != NULL) {				\
 		(*(MP)->mnt_op->vfs_purge)(MP);				\
 	}								\
 } while (0)
 
 #define VFS_KNOTE_LOCKED(vp, hint) do					\
 {									\
 	if (((vp)->v_vflag & VV_NOKNOTE) == 0)				\
 		VN_KNOTE((vp), (hint), KNF_LISTLOCKED);			\
 } while (0)
 
 #define VFS_KNOTE_UNLOCKED(vp, hint) do					\
 {									\
 	if (((vp)->v_vflag & VV_NOKNOTE) == 0)				\
 		VN_KNOTE((vp), (hint), 0);				\
 } while (0)
 
 #define	VFS_NOTIFY_UPPER_RECLAIM	1
 #define	VFS_NOTIFY_UPPER_UNLINK		2
 
 #include <sys/module.h>
 
 /*
  * Version numbers.
  */
 #define VFS_VERSION_00	0x19660120
 #define VFS_VERSION_01	0x20121030
 #define VFS_VERSION_02	0x20180504
 #define VFS_VERSION	VFS_VERSION_02
 
 #define VFS_SET(vfsops, fsname, flags) \
 	static struct vfsconf fsname ## _vfsconf = {		\
 		.vfc_version = VFS_VERSION,			\
 		.vfc_name = #fsname,				\
 		.vfc_vfsops = &vfsops,				\
 		.vfc_typenum = -1,				\
 		.vfc_flags = flags,				\
 	};							\
 	static moduledata_t fsname ## _mod = {			\
 		#fsname,					\
 		vfs_modevent,					\
 		& fsname ## _vfsconf				\
 	};							\
 	DECLARE_MODULE(fsname, fsname ## _mod, SI_SUB_VFS, SI_ORDER_MIDDLE)
 
 /*
  * exported vnode operations
  */
 
 int	dounmount(struct mount *, int, struct thread *);
 
 int	kernel_mount(struct mntarg *ma, uint64_t flags);
 int	kernel_vmount(int flags, ...);
 struct mntarg *mount_arg(struct mntarg *ma, const char *name, const void *val, int len);
 struct mntarg *mount_argb(struct mntarg *ma, int flag, const char *name);
 struct mntarg *mount_argf(struct mntarg *ma, const char *name, const char *fmt, ...);
 struct mntarg *mount_argsu(struct mntarg *ma, const char *name, const void *val, int len);
 void	statfs_scale_blocks(struct statfs *sf, long max_size);
 struct vfsconf *vfs_byname(const char *);
 struct vfsconf *vfs_byname_kld(const char *, struct thread *td, int *);
 void	vfs_mount_destroy(struct mount *);
 void	vfs_event_signal(fsid_t *, u_int32_t, intptr_t);
 void	vfs_freeopts(struct vfsoptlist *opts);
 void	vfs_deleteopt(struct vfsoptlist *opts, const char *name);
 int	vfs_buildopts(struct uio *auio, struct vfsoptlist **options);
 int	vfs_flagopt(struct vfsoptlist *opts, const char *name, uint64_t *w,
 	    uint64_t val);
 int	vfs_getopt(struct vfsoptlist *, const char *, void **, int *);
 int	vfs_getopt_pos(struct vfsoptlist *opts, const char *name);
 int	vfs_getopt_size(struct vfsoptlist *opts, const char *name,
 	    off_t *value);
 char	*vfs_getopts(struct vfsoptlist *, const char *, int *error);
 int	vfs_copyopt(struct vfsoptlist *, const char *, void *, int);
 int	vfs_filteropt(struct vfsoptlist *, const char **legal);
 void	vfs_opterror(struct vfsoptlist *opts, const char *fmt, ...);
 int	vfs_scanopt(struct vfsoptlist *opts, const char *name, const char *fmt, ...);
 int	vfs_setopt(struct vfsoptlist *opts, const char *name, void *value,
 	    int len);
 int	vfs_setopt_part(struct vfsoptlist *opts, const char *name, void *value,
 	    int len);
 int	vfs_setopts(struct vfsoptlist *opts, const char *name,
 	    const char *value);
 int	vfs_setpublicfs			    /* set publicly exported fs */
 	    (struct mount *, struct netexport *, struct export_args *);
 void	vfs_periodic(struct mount *, int);
 int	vfs_busy(struct mount *, int);
 int	vfs_export			 /* process mount export info */
 	    (struct mount *, struct export_args *);
 void	vfs_allocate_syncvnode(struct mount *);
 void	vfs_deallocate_syncvnode(struct mount *);
 int	vfs_donmount(struct thread *td, uint64_t fsflags,
 	    struct uio *fsoptions);
 void	vfs_getnewfsid(struct mount *);
 struct cdev *vfs_getrootfsid(struct mount *);
 struct	mount *vfs_getvfs(fsid_t *);      /* return vfs given fsid */
 struct	mount *vfs_busyfs(fsid_t *);
 int	vfs_modevent(module_t, int, void *);
 void	vfs_mount_error(struct mount *, const char *, ...);
 void	vfs_mountroot(void);			/* mount our root filesystem */
 void	vfs_mountedfrom(struct mount *, const char *from);
 void	vfs_notify_upper(struct vnode *, int);
 struct mount *vfs_ref_from_vp(struct vnode *);
 void	vfs_ref(struct mount *);
 void	vfs_rel(struct mount *);
 struct mount *vfs_mount_alloc(struct vnode *, struct vfsconf *, const char *,
 	    struct ucred *);
 int	vfs_suser(struct mount *, struct thread *);
 void	vfs_unbusy(struct mount *);
 void	vfs_unmountall(void);
 extern	TAILQ_HEAD(mntlist, mount) mountlist;	/* mounted filesystem list */
 extern	struct mtx_padalign mountlist_mtx;
 extern	struct nfs_public nfs_pub;
 extern	struct sx vfsconf_sx;
 #define	vfsconf_lock()		sx_xlock(&vfsconf_sx)
 #define	vfsconf_unlock()	sx_xunlock(&vfsconf_sx)
 #define	vfsconf_slock()		sx_slock(&vfsconf_sx)
 #define	vfsconf_sunlock()	sx_sunlock(&vfsconf_sx)
 struct vnode *mntfs_allocvp(struct mount *, struct vnode *);
 void   mntfs_freevp(struct vnode *);
 
 /*
  * Declarations for these vfs default operations are located in
  * kern/vfs_default.c.  They will be automatically used to replace
  * null entries in VFS ops tables when registering a new filesystem
  * type in the global table.
  */
 vfs_root_t		vfs_stdroot;
 vfs_quotactl_t		vfs_stdquotactl;
 vfs_statfs_t		vfs_stdstatfs;
 vfs_sync_t		vfs_stdsync;
 vfs_sync_t		vfs_stdnosync;
 vfs_vget_t		vfs_stdvget;
 vfs_fhtovp_t		vfs_stdfhtovp;
 vfs_checkexp_t		vfs_stdcheckexp;
 vfs_init_t		vfs_stdinit;
 vfs_uninit_t		vfs_stduninit;
 vfs_extattrctl_t	vfs_stdextattrctl;
 vfs_sysctl_t		vfs_stdsysctl;
 
 void	syncer_suspend(void);
 void	syncer_resume(void);
 
 struct vnode *vfs_cache_root_clear(struct mount *);
 void	vfs_cache_root_set(struct mount *, struct vnode *);
 
 void	vfs_op_barrier_wait(struct mount *);
 void	vfs_op_enter(struct mount *);
 void	vfs_op_exit_locked(struct mount *);
 void	vfs_op_exit(struct mount *);
 
 #ifdef DIAGNOSTIC
 void	vfs_assert_mount_counters(struct mount *);
 void	vfs_dump_mount_counters(struct mount *);
 #else
 #define vfs_assert_mount_counters(mp) do { } while (0)
 #define vfs_dump_mount_counters(mp) do { } while (0)
 #endif
 
 enum mount_counter { MNT_COUNT_REF, MNT_COUNT_LOCKREF, MNT_COUNT_WRITEOPCOUNT };
 int	vfs_mount_fetch_counter(struct mount *, enum mount_counter);
 
 void suspend_all_fs(void);
 void resume_all_fs(void);
 
 /*
  * Code transitioning mnt_vfs_ops to > 0 issues IPIs until it observes
  * all CPUs not executing code enclosed by thread_in_ops_pcpu variable.
  *
  * This provides an invariant that by the time the last CPU is observed not
  * executing, everyone else entering will see the counter > 0 and exit.
  *
  * Note there is no barrier between vfs_ops and the rest of the code in the
  * section. It is not necessary as the writer has to wait for everyone to drain
  * before making any changes or only make changes safe while the section is
  * executed.
  */
 #define	vfs_mount_pcpu(mp)		zpcpu_get(mp->mnt_pcpu)
 #define	vfs_mount_pcpu_remote(mp, cpu)	zpcpu_get_cpu(mp->mnt_pcpu, cpu)
 
 #define vfs_op_thread_entered(mp) ({				\
 	MPASS(curthread->td_critnest > 0);			\
 	struct mount_pcpu *_mpcpu = vfs_mount_pcpu(mp);		\
 	_mpcpu->mntp_thread_in_ops == 1;			\
 })
 
 #define vfs_op_thread_enter_crit(mp, _mpcpu) ({			\
 	bool _retval_crit = true;				\
 	MPASS(curthread->td_critnest > 0);			\
 	_mpcpu = vfs_mount_pcpu(mp);				\
 	MPASS(mpcpu->mntp_thread_in_ops == 0);			\
 	_mpcpu->mntp_thread_in_ops = 1;				\
 	__compiler_membar();					\
 	if (__predict_false(mp->mnt_vfs_ops > 0)) {		\
 		vfs_op_thread_exit_crit(mp, _mpcpu);		\
 		_retval_crit = false;				\
 	}							\
 	_retval_crit;						\
 })
 
 #define vfs_op_thread_enter(mp, _mpcpu) ({			\
 	bool _retval;						\
 	critical_enter();					\
 	_retval = vfs_op_thread_enter_crit(mp, _mpcpu);		\
 	if (__predict_false(!_retval))				\
 		critical_exit();				\
 	_retval;						\
 })
 
 #define vfs_op_thread_exit_crit(mp, _mpcpu) do {		\
 	MPASS(_mpcpu == vfs_mount_pcpu(mp));			\
 	MPASS(_mpcpu->mntp_thread_in_ops == 1);			\
 	__compiler_membar();					\
 	_mpcpu->mntp_thread_in_ops = 0;				\
 } while (0)
 
 #define vfs_op_thread_exit(mp, _mpcpu) do {			\
 	vfs_op_thread_exit_crit(mp, _mpcpu);			\
 	critical_exit();					\
 } while (0)
 
 #define vfs_mp_count_add_pcpu(_mpcpu, count, val) do {		\
 	MPASS(_mpcpu->mntp_thread_in_ops == 1);			\
 	_mpcpu->mntp_##count += val;				\
 } while (0)
 
 #define vfs_mp_count_sub_pcpu(_mpcpu, count, val) do {		\
 	MPASS(_mpcpu->mntp_thread_in_ops == 1);			\
 	_mpcpu->mntp_##count -= val;				\
 } while (0)
 
 #else /* !_KERNEL */
 
 #include <sys/cdefs.h>
 
 struct stat;
 
 __BEGIN_DECLS
 int	fhlink(struct fhandle *, const char *);
 int	fhlinkat(struct fhandle *, int, const char *);
 int	fhopen(const struct fhandle *, int);
 int	fhreadlink(struct fhandle *, char *, size_t);
 int	fhstat(const struct fhandle *, struct stat *);
 int	fhstatfs(const struct fhandle *, struct statfs *);
 int	fstatfs(int, struct statfs *);
 int	getfh(const char *, fhandle_t *);
 int	getfhat(int, char *, struct fhandle *, int);
 int	getfsstat(struct statfs *, long, int);
 int	getmntinfo(struct statfs **, int);
 int	lgetfh(const char *, fhandle_t *);
 int	mount(const char *, const char *, int, void *);
 int	nmount(struct iovec *, unsigned int, int);
 int	statfs(const char *, struct statfs *);
 int	unmount(const char *, int);
 
 /* C library stuff */
 int	getvfsbyname(const char *, struct xvfsconf *);
 __END_DECLS
 
 #endif /* _KERNEL */
 
 #endif /* !_SYS_MOUNT_H_ */
diff --git a/sys/sys/pipe.h b/sys/sys/pipe.h
index f8b008151c6a..c9f222ffb01a 100644
--- a/sys/sys/pipe.h
+++ b/sys/sys/pipe.h
@@ -1,153 +1,153 @@
 /*-
  * Copyright (c) 1996 John S. Dyson
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice immediately at the beginning of the file, without modification,
  *    this list of conditions, and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Absolutely no warranty of function or purpose is made by the author
  *    John S. Dyson.
  * 4. This work was done expressly for inclusion into FreeBSD.  Other use
  *    is allowed if this notation is included.
  * 5. Modifications may be freely made to this file if the above conditions
  *    are met.
  *
  * $FreeBSD$
  */
 
 #ifndef _SYS_PIPE_H_
 #define _SYS_PIPE_H_
 
-#ifndef _KERNEL
-#error "no user-serviceable parts inside"
-#endif
-
 /*
  * Pipe buffer size, keep moderate in value, pipes take kva space.
  */
 #ifndef PIPE_SIZE
 #define PIPE_SIZE	16384
 #endif
 
 #ifndef BIG_PIPE_SIZE
 #define BIG_PIPE_SIZE	(64*1024)
 #endif
 
 #ifndef SMALL_PIPE_SIZE
 #define SMALL_PIPE_SIZE	PAGE_SIZE
 #endif
 
 /*
  * PIPE_MINDIRECT MUST be smaller than PIPE_SIZE and MUST be bigger
  * than PIPE_BUF.
  */
 #ifndef PIPE_MINDIRECT
 #define PIPE_MINDIRECT	8192
 #endif
 
 #define PIPENPAGES	(BIG_PIPE_SIZE / PAGE_SIZE + 1)
 
+#ifdef _KERNEL
 /*
  * See sys_pipe.c for info on what these limits mean. 
  */
 extern long	maxpipekva;
 extern struct	fileops pipeops;
+#endif
 
 /*
  * Pipe buffer information.
  * Separate in, out, cnt are used to simplify calculations.
  * Buffered write is active when the buffer.cnt field is set.
  */
 struct pipebuf {
 	u_int	cnt;		/* number of chars currently in buffer */
 	u_int	in;		/* in pointer */
 	u_int	out;		/* out pointer */
 	u_int	size;		/* size of buffer */
 	caddr_t	buffer;		/* kva of buffer */
 };
 
 /*
  * Information to support direct transfers between processes for pipes.
  */
 struct pipemapping {
 	vm_size_t	cnt;		/* number of chars in buffer */
 	vm_size_t	pos;		/* current position of transfer */
 	int		npages;		/* number of pages */
 	vm_page_t	ms[PIPENPAGES];	/* pages in source process */
 };
 
 /*
  * Bits in pipe_state.
  */
 #define PIPE_ASYNC	0x004	/* Async? I/O. */
 #define PIPE_WANTR	0x008	/* Reader wants some characters. */
 #define PIPE_WANTW	0x010	/* Writer wants space to put characters. */
 #define PIPE_WANT	0x020	/* Pipe is wanted to be run-down. */
 #define PIPE_SEL	0x040	/* Pipe has a select active. */
 #define PIPE_EOF	0x080	/* Pipe is in EOF condition. */
 #define PIPE_LOCKFL	0x100	/* Process has exclusive access to pointers/data. */
 #define PIPE_LWANT	0x200	/* Process wants exclusive access to pointers/data. */
 #define PIPE_DIRECTW	0x400	/* Pipe direct write active. */
 #define PIPE_DIRECTOK	0x800	/* Direct mode ok. */
 
 /*
  * Bits in pipe_type.
  */
 #define PIPE_TYPE_NAMED	0x001	/* Is a named pipe. */
 
 /*
  * Per-pipe data structure.
  * Two of these are linked together to produce bi-directional pipes.
  */
 struct pipe {
 	struct	pipebuf pipe_buffer;	/* data storage */
 	struct	pipemapping pipe_pages;	/* wired pages for direct I/O */
 	struct	selinfo pipe_sel;	/* for compat with select */
 	struct	timespec pipe_atime;	/* time of last access */
 	struct	timespec pipe_mtime;	/* time of last modify */
 	struct	timespec pipe_ctime;	/* time of status change */
 	struct	sigio *pipe_sigio;	/* information for async I/O */
 	struct	pipe *pipe_peer;	/* link with other direction */
 	struct	pipepair *pipe_pair;	/* container structure pointer */
 	u_short	pipe_state;		/* pipe status info */
 	u_char	pipe_type;		/* pipe type info */
 	u_char	pipe_present;		/* still present? */
 	int	pipe_waiters;		/* pipelock waiters */
 	int	pipe_busy;		/* busy flag, mostly to handle rundown sanely */
 	int	pipe_wgen;		/* writer generation for named pipe */
 	ino_t	pipe_ino;		/* fake inode for stat(2) */
 };
 
 /*
  * Values for the pipe_present.
  */
 #define PIPE_ACTIVE		1
 #define	PIPE_CLOSING		2
 #define	PIPE_FINALIZED		3
 
 /*
  * Container structure to hold the two pipe endpoints, mutex, and label
  * pointer.
  */
 struct pipepair {
 	struct pipe	pp_rpipe;
 	struct pipe	pp_wpipe;
 	struct mtx	pp_mtx;
 	struct label	*pp_label;
 };
 
 #define PIPE_MTX(pipe)		(&(pipe)->pipe_pair->pp_mtx)
 #define PIPE_LOCK(pipe)		mtx_lock(PIPE_MTX(pipe))
 #define PIPE_UNLOCK(pipe)	mtx_unlock(PIPE_MTX(pipe))
 #define PIPE_LOCK_ASSERT(pipe, type)  mtx_assert(PIPE_MTX(pipe), (type))
 
+#ifdef _KERNEL
 void	pipe_dtor(struct pipe *dpipe);
 int	pipe_named_ctor(struct pipe **ppipe, struct thread *td);
 void	pipeselwakeup(struct pipe *cpipe);
+#endif
 #endif /* !_SYS_PIPE_H_ */
diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h
index 781cc782f415..fa20f8c0b936 100644
--- a/sys/ufs/ufs/extattr.h
+++ b/sys/ufs/ufs/extattr.h
@@ -1,147 +1,148 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 1999-2001 Robert N. M. Watson
  * All rights reserved.
  *
  * This software was developed by Robert Watson for the TrustedBSD Project.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 /*
  * Developed by the TrustedBSD Project.
  * Support for extended filesystem attributes.
  */
 
 #ifndef _UFS_UFS_EXTATTR_H_
 #define	_UFS_UFS_EXTATTR_H_
 
 #define	UFS_EXTATTR_MAGIC		0x00b5d5ec
 #define	UFS_EXTATTR_VERSION		0x00000003
 #define	UFS_EXTATTR_FSROOTSUBDIR	".attribute"
 #define	UFS_EXTATTR_SUBDIR_SYSTEM	"system"
 #define	UFS_EXTATTR_SUBDIR_USER		"user"
 #define	UFS_EXTATTR_MAXEXTATTRNAME	65	/* including null */
 
 #define	UFS_EXTATTR_ATTR_FLAG_INUSE	0x00000001	/* attr has been set */
 #define	UFS_EXTATTR_PERM_KERNEL		0x00000000
 #define	UFS_EXTATTR_PERM_ROOT		0x00000001
 #define	UFS_EXTATTR_PERM_OWNER		0x00000002
 #define	UFS_EXTATTR_PERM_ANYONE		0x00000003
 
 #define	UFS_EXTATTR_UEPM_INITIALIZED	0x00000001
 #define	UFS_EXTATTR_UEPM_STARTED	0x00000002
 
 #define	UFS_EXTATTR_CMD_START		0x00000001
 #define	UFS_EXTATTR_CMD_STOP		0x00000002
 #define	UFS_EXTATTR_CMD_ENABLE		0x00000003
 #define	UFS_EXTATTR_CMD_DISABLE		0x00000004
 
 struct ufs_extattr_fileheader {
 	u_int	uef_magic;	/* magic number for sanity checking */
 	u_int	uef_version;	/* version of attribute file */
 	u_int	uef_size;	/* size of attributes, w/o header */
 };
 
 struct ufs_extattr_header {
 	u_int	ueh_flags;	/* flags for attribute */
 	u_int	ueh_len;	/* local defined length; <= uef_size */
 	u_int32_t	ueh_i_gen;	/* generation number for sanity */
 	/* data follows the header */
 };
 
 /*
  * This structure defines the required fields of an extended-attribute header.
  */
 struct extattr {
 	uint32_t ea_length;	    /* length of this attribute */
 	uint8_t	ea_namespace;	    /* name space of this attribute */
 	uint8_t	ea_contentpadlen;   /* bytes of padding at end of attribute */
 	uint8_t	ea_namelength;	    /* length of attribute name */
 	char	ea_name[1];	    /* attribute name (NOT nul-terminated) */
 	/* padding, if any, to align attribute content to 8 byte boundary */
 	/* extended attribute content follows */
 };
 
 /*
  * These macros are used to access and manipulate an extended attribute:
  *
  * EXTATTR_NEXT(eap) returns a pointer to the next extended attribute
  *	following eap.
  * EXTATTR_CONTENT(eap) returns a pointer to the extended attribute
  *	content referenced by eap.
  * EXTATTR_CONTENT_SIZE(eap) returns the size of the extended attribute
  *	content referenced by eap.
  */
 #define	EXTATTR_NEXT(eap) \
 	((struct extattr *)(__DECONST(char *, (eap)) + (eap)->ea_length))
 #define	EXTATTR_CONTENT(eap) \
 	(void *)(((u_char *)(eap)) + EXTATTR_BASE_LENGTH(eap))
 #define	EXTATTR_CONTENT_SIZE(eap) \
 	((eap)->ea_length - EXTATTR_BASE_LENGTH(eap) - (eap)->ea_contentpadlen)
 /* -1 below compensates for ea_name[1] */
 #define	EXTATTR_BASE_LENGTH(eap) \
 	roundup2((sizeof(struct extattr) - 1 + (eap)->ea_namelength), 8)
 
-#ifdef _KERNEL
-
-#include <sys/_sx.h>
-
 struct vnode;
 LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry);
 struct ufs_extattr_list_entry {
 	LIST_ENTRY(ufs_extattr_list_entry)	uele_entries;
 	struct ufs_extattr_fileheader		uele_fileheader;
 	int	uele_attrnamespace;
 	char	uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME];
 	struct vnode	*uele_backing_vnode;
 };
 
+#include <sys/_lock.h>
+#include <sys/_sx.h>
+
 struct ucred;
 struct ufs_extattr_per_mount {
 	struct sx	uepm_lock;
 	struct ufs_extattr_list_head	uepm_list;
 	struct ucred	*uepm_ucred;
 	int	uepm_flags;
 };
 
+#ifdef _KERNEL
+
 struct vop_getextattr_args;
 struct vop_deleteextattr_args;
 struct vop_setextattr_args;
 
 void	ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm);
 void	ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm);
 int	ufs_extattr_start(struct mount *mp, struct thread *td);
 int	ufs_extattr_autostart(struct mount *mp, struct thread *td);
 int	ufs_extattr_stop(struct mount *mp, struct thread *td);
 int	ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
 	    int attrnamespace, const char *attrname);
 int	ufs_getextattr(struct vop_getextattr_args *ap);
 int	ufs_deleteextattr(struct vop_deleteextattr_args *ap);
 int	ufs_setextattr(struct vop_setextattr_args *ap);
 void	ufs_extattr_vnode_inactive(struct vnode *vp);
 
 #endif /* !_KERNEL */
 
 #endif /* !_UFS_UFS_EXTATTR_H_ */
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 4515dcbed401..e00a89b012d0 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -1,308 +1,310 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1982, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  * (c) UNIX System Laboratories, Inc.
  * All or some portions of this file are derived from material licensed
  * to the University of California by American Telephone and Telegraph
  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  * the permission of UNIX System Laboratories, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)inode.h	8.9 (Berkeley) 5/14/95
  * $FreeBSD$
  */
 
 #ifndef _UFS_UFS_INODE_H_
 #define	_UFS_UFS_INODE_H_
 
 #include <sys/lock.h>
 #include <sys/queue.h>
 #include <ufs/ufs/dinode.h>
 #include <sys/seqc.h>
 #ifdef DIAGNOSTIC
 #include <sys/stack.h>
 #endif
 
 /*
  * This must agree with the definition in <ufs/ufs/dir.h>.
  */
 #define	doff_t		int32_t
 
 #ifdef DIAGNOSTIC
 struct iown_tracker {
 	struct thread	*tr_owner;
 	struct stack	tr_st;
 	struct stack	tr_unlock;
 	int		tr_gen;
 };
 #endif
 
 /*
  * The inode is used to describe each active (or recently active) file in the
  * UFS filesystem. It is composed of two types of information. The first part
  * is the information that is needed only while the file is active (such as
  * the identity of the file and linkage to speed its lookup). The second part
  * is the permanent meta-data associated with the file which is read in
  * from the permanent dinode from long term storage when the file becomes
  * active, and is put back when the file is no longer being used.
  *
  * An inode may only be changed while holding either the exclusive
  * vnode lock or the shared vnode lock and the vnode interlock. We use
  * the latter only for "read" and "get" operations that require
  * changing i_flag, or a timestamp. This locking protocol allows executing
  * those operations without having to upgrade the vnode lock from shared to
  * exclusive.
  */
 struct inode {
 	TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
 	struct	vnode  *i_vnode;/* Vnode associated with this inode. */
 	struct 	ufsmount *i_ump;/* Ufsmount point associated with this inode. */
 	struct	 dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
 	union {
 		struct dirhash *dirhash; /* Hashing for large directories. */
 		daddr_t *snapblklist;    /* Collect expunged snapshot blocks. */
 	} i_un;
 	/*
 	 * The real copy of the on-disk inode.
 	 */
 	union {
 		struct ufs1_dinode *din1;	/* UFS1 on-disk dinode. */
 		struct ufs2_dinode *din2;	/* UFS2 on-disk dinode. */
 	} dinode_u;
 
 	ino_t	  i_number;	/* The identity of the inode. */
 	u_int32_t i_flag;	/* flags, see below */
 	int	  i_effnlink;	/* i_nlink when I/O completes */
 
 	/*
 	 * Side effects; used during directory lookup.
 	 */
 	int32_t	  i_count;	/* Size of free slot in directory. */
 	doff_t	  i_endoff;	/* End of useful stuff in directory. */
 	doff_t	  i_diroff;	/* Offset in dir, where we found last entry. */
 	doff_t	  i_offset;	/* Offset of free space in directory. */
 #ifdef DIAGNOSTIC
 	int			i_lock_gen;
 	struct iown_tracker	i_count_tracker;
 	struct iown_tracker	i_endoff_tracker;
 	struct iown_tracker	i_offset_tracker;
 #endif
 
 	int	i_nextclustercg; /* last cg searched for cluster */
 
 	/*
 	 * Data for extended attribute modification.
  	 */
 	u_char	  *i_ea_area;	/* Pointer to malloced copy of EA area */
 	unsigned  i_ea_len;	/* Length of i_ea_area */
 	int	  i_ea_error;	/* First errno in transaction */
 	int	  i_ea_refs;	/* Number of users of EA area */
 
 	/*
 	 * Copies from the on-disk dinode itself.
 	 */
 	u_int64_t i_size;	/* File byte count. */
 	u_int64_t i_gen;	/* Generation number. */
 	u_int32_t i_flags;	/* Status flags (chflags). */
 	u_int32_t i_uid;	/* File owner. */
 	u_int32_t i_gid;	/* File group. */
 	u_int16_t i_mode;	/* IFMT, permissions; see below. */
 	int16_t	  i_nlink;	/* File link count. */
 };
 /*
  * These flags are kept in i_flag.
  */
 #define	IN_ACCESS	0x0001		/* Access time update request. */
 #define	IN_CHANGE	0x0002		/* Inode change time update request. */
 #define	IN_UPDATE	0x0004		/* Modification time update request. */
 #define	IN_MODIFIED	0x0008		/* Inode has been modified. */
 #define	IN_NEEDSYNC	0x0010		/* Inode requires fsync. */
 #define	IN_LAZYMOD	0x0020		/* Modified, but don't write yet. */
 #define	IN_LAZYACCESS	0x0040		/* Process IN_ACCESS after the
 					   suspension finished */
 #define	IN_EA_LOCKED	0x0080		/* Extended attributes locked */
 #define	IN_EA_LOCKWAIT	0x0100		/* Want extended attributes lock */
 #define	IN_TRUNCATED	0x0200		/* Journaled truncation pending. */
 #define	IN_UFS2		0x0400		/* UFS2 vs UFS1 */
 #define	IN_IBLKDATA	0x0800		/* datasync requires inode block
 					   update */
 #define	IN_SIZEMOD	0x1000		/* Inode size has been modified */
 #define	IN_ENDOFF	0x2000		/* Free space at the end of directory,
 					   try to truncate when possible */
 
 #define PRINT_INODE_FLAGS "\20\20b16\17b15\16b14\15sizemod" \
 	"\14iblkdata\13is_ufs2\12truncated\11ea_lockwait\10ea_locked" \
 	"\7lazyaccess\6lazymod\5needsync\4modified\3update\2change\1access"
 
 #define UFS_INODE_FLAG_LAZY_MASK	\
 	(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE | IN_LAZYMOD | \
 	 IN_LAZYACCESS)
 /*
  * Some flags can persist a vnode transitioning to 0 hold count and being tkaen
  * off the list.
  */
 #define UFS_INODE_FLAG_LAZY_MASK_ASSERTABLE \
 	(UFS_INODE_FLAG_LAZY_MASK & ~(IN_LAZYMOD | IN_LAZYACCESS))
 
 #define UFS_INODE_SET_MODE(ip, mode) do {			\
 	struct inode *_ip = (ip);				\
 	int _mode = (mode);					\
 								\
 	ASSERT_VOP_IN_SEQC(ITOV(_ip));				\
 	atomic_store_short(&(_ip)->i_mode, _mode);		\
 } while (0)
 
 #define UFS_INODE_SET_FLAG(ip, flags) do {			\
 	struct inode *_ip = (ip);				\
 	struct vnode *_vp = ITOV(_ip);				\
 	int _flags = (flags);					\
 								\
 	_ip->i_flag |= _flags;					\
 	if (_flags & UFS_INODE_FLAG_LAZY_MASK)			\
 		vlazy(_vp);					\
 } while (0)
 
 #define UFS_INODE_SET_FLAG_SHARED(ip, flags) do {		\
 	struct inode *_ip = (ip);				\
 	struct vnode *_vp = ITOV(_ip);				\
 	int _flags = (flags);					\
 								\
 	ASSERT_VI_UNLOCKED(_vp, __func__);			\
 	if ((_ip->i_flag & (_flags)) != _flags) {		\
 		VI_LOCK(_vp);					\
 		_ip->i_flag |= _flags;				\
 		if (_flags & UFS_INODE_FLAG_LAZY_MASK)		\
 			vlazy(_vp);				\
 		VI_UNLOCK(_vp);					\
 	}							\
 } while (0)
 
 #define	i_dirhash i_un.dirhash
 #define	i_snapblklist i_un.snapblklist
 #define	i_din1 dinode_u.din1
 #define	i_din2 dinode_u.din2
 
-#ifdef _KERNEL
-
 #define	ITOUMP(ip)	((ip)->i_ump)
 #define	ITODEV(ip)	(ITOUMP(ip)->um_dev)
 #define	ITODEVVP(ip)	(ITOUMP(ip)->um_devvp)
 #define	ITOFS(ip)	(ITOUMP(ip)->um_fs)
 #define	ITOVFS(ip)	((ip)->i_vnode->v_mount)
 
+#ifdef _KERNEL
+
 static inline _Bool
 I_IS_UFS1(const struct inode *ip)
 {
 
 	return ((ip->i_flag & IN_UFS2) == 0);
 }
 
 static inline _Bool
 I_IS_UFS2(const struct inode *ip)
 {
 
 	return ((ip->i_flag & IN_UFS2) != 0);
 }
+#endif	/* _KERNEL */
 
 /*
  * The DIP macro is used to access fields in the dinode that are
  * not cached in the inode itself.
  */
 #define	DIP(ip, field)	(I_IS_UFS1(ip) ? (ip)->i_din1->d##field : \
     (ip)->i_din2->d##field)
 #define	DIP_SET(ip, field, val) do {				\
 	if (I_IS_UFS1(ip))					\
 		(ip)->i_din1->d##field = (val); 		\
 	else							\
 		(ip)->i_din2->d##field = (val); 		\
 	} while (0)
 
 #define	SHORTLINK(ip)	(I_IS_UFS1(ip) ?			\
     (caddr_t)(ip)->i_din1->di_db : (caddr_t)(ip)->i_din2->di_db)
 #define	IS_SNAPSHOT(ip)		((ip)->i_flags & SF_SNAPSHOT)
 
 /*
  * Structure used to pass around logical block paths generated by
  * ufs_getlbns and used by truncate and bmap code.
  */
 struct indir {
 	ufs2_daddr_t in_lbn;		/* Logical block number. */
 	int	in_off;			/* Offset in buffer. */
 };
 
 /* Convert between inode pointers and vnode pointers. */
 #define	VTOI(vp)	((struct inode *)(vp)->v_data)
 #define	VTOI_SMR(vp)	((struct inode *)vn_load_v_data_smr(vp))
 #define	ITOV(ip)	((ip)->i_vnode)
 
 /* Determine if soft dependencies are being done */
 #define	DOINGSOFTDEP(vp)   \
 	(((vp)->v_mount->mnt_flag & (MNT_SOFTDEP | MNT_SUJ)) != 0)
 #define	MOUNTEDSOFTDEP(mp) (((mp)->mnt_flag & (MNT_SOFTDEP | MNT_SUJ)) != 0)
 #define	DOINGSUJ(vp)	   (((vp)->v_mount->mnt_flag & MNT_SUJ) != 0)
 #define	MOUNTEDSUJ(mp)	   (((mp)->mnt_flag & MNT_SUJ) != 0)
 
 /* This overlays the fid structure (see mount.h). */
 struct ufid {
 	u_int16_t ufid_len;	/* Length of structure. */
 	u_int16_t ufid_pad;	/* Force 32-bit alignment. */
 	uint32_t  ufid_ino;	/* File number (ino). */
 	uint32_t  ufid_gen;	/* Generation number. */
 };
 
+#ifdef _KERNEL
 #ifdef DIAGNOSTIC
 void ufs_init_trackers(struct inode *ip);
 void ufs_unlock_tracker(struct inode *ip);
 
 doff_t ufs_get_i_offset(struct inode *ip, const char *file, int line);
 void ufs_set_i_offset(struct inode *ip, doff_t off, const char *file, int line);
 #define	I_OFFSET(ip)		ufs_get_i_offset(ip, __FILE__, __LINE__)
 #define	SET_I_OFFSET(ip, off)	ufs_set_i_offset(ip, off, __FILE__, __LINE__)
 
 int32_t ufs_get_i_count(struct inode *ip, const char *file, int line);
 void ufs_set_i_count(struct inode *ip, int32_t cnt, const char *file, int line);
 #define	I_COUNT(ip)		ufs_get_i_count(ip, __FILE__, __LINE__)
 #define	SET_I_COUNT(ip, cnt)	ufs_set_i_count(ip, cnt, __FILE__, __LINE__)
 
 doff_t ufs_get_i_endoff(struct inode *ip, const char *file, int line);
 void ufs_set_i_endoff(struct inode *ip, doff_t off, const char *file, int line);
 #define	I_ENDOFF(ip)		ufs_get_i_endoff(ip, __FILE__, __LINE__)
 #define	SET_I_ENDOFF(ip, off)	ufs_set_i_endoff(ip, off, __FILE__, __LINE__)
 
 #else
 #define	I_OFFSET(ip)		((ip)->i_offset)
 #define	SET_I_OFFSET(ip, off)	((ip)->i_offset = (off))
 #define	I_COUNT(ip)		((ip)->i_count)
 #define	SET_I_COUNT(ip, cnt)	((ip)->i_count = cnt)
 #define	I_ENDOFF(ip)		((ip)->i_endoff)
 #define	SET_I_ENDOFF(ip, off)	((ip)->i_endoff = off)
 #endif
 
 #endif /* _KERNEL */
 
 #endif /* !_UFS_UFS_INODE_H_ */
diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h
index 57e163c11d77..0dfcecb178af 100644
--- a/sys/ufs/ufs/ufsmount.h
+++ b/sys/ufs/ufs/ufsmount.h
@@ -1,195 +1,197 @@
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)ufsmount.h	8.6 (Berkeley) 3/30/95
  * $FreeBSD$
  */
 
 #ifndef _UFS_UFS_UFSMOUNT_H_
 #define	_UFS_UFS_UFSMOUNT_H_
 
 /*
  * Arguments to mount UFS-based filesystems
  */
 struct ufs_args {
 	char	*fspec;			/* block special device to mount */
 	struct	oexport_args export;	/* network export information */
 };
 
-#ifdef _KERNEL
-
 #include <sys/_task.h>
 
+#ifdef _KERNEL
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_UFSMNT);
 MALLOC_DECLARE(M_TRIM);
 #endif
+#endif	/* _KERNEL */
 
 struct buf;
 struct inode;
 struct nameidata;
 struct taskqueue;
 struct timeval;
 struct ucred;
 struct uio;
 struct vnode;
 struct ufs_extattr_per_mount;
 struct jblocks;
 struct inodedep;
 
 TAILQ_HEAD(inodedeplst, inodedep);
 LIST_HEAD(bmsafemaphd, bmsafemap);
 LIST_HEAD(trimlist_hashhead, ffs_blkfree_trim_params);
 struct fsfail_task {
 	struct task task;
 	fsid_t fsid;
 };
 
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+
 /*
  * This structure describes the UFS specific mount structure data.
  * The function operators are used to support different versions of
  * UFS (UFS1, UFS2, etc).
  *
  * Lock reference:
  *	c - set at allocation then constant until freed
  *	i - ufsmount interlock (UFS_LOCK / UFS_UNLOCK)
  *	q - associated quota file is locked
  *	r - ref to parent mount structure is held (vfs_busy / vfs_unbusy)
  *	u - managed by user process fsck_ufs
  */
 struct ufsmount {
 	struct	mount *um_mountp;		/* (r) filesystem vfs struct */
 	struct	cdev *um_dev;			/* (r) device mounted */
 	struct	g_consumer *um_cp;		/* (r) GEOM access point */
 	struct	bufobj *um_bo;			/* (r) Buffer cache object */
 	struct	vnode *um_odevvp;		/* (r) devfs dev vnode */
 	struct	vnode *um_devvp;		/* (r) mntfs private vnode */
 	u_long	um_fstype;			/* (c) type of filesystem */
 	struct	fs *um_fs;			/* (r) pointer to superblock */
 	struct	ufs_extattr_per_mount um_extattr; /* (c) extended attrs */
 	u_long	um_nindir;			/* (c) indirect ptrs per blk */
 	u_long	um_bptrtodb;			/* (c) indir disk block ptr */
 	u_long	um_seqinc;			/* (c) inc between seq blocks */
 	struct	mtx um_lock;			/* (c) Protects ufsmount & fs */
 	pid_t	um_fsckpid;			/* (u) PID can do fsck sysctl */
 	struct	mount_softdeps *um_softdep;	/* (c) softdep mgmt structure */
 	struct	vnode *um_quotas[MAXQUOTAS];	/* (q) pointer to quota files */
 	struct	ucred *um_cred[MAXQUOTAS];	/* (q) quota file access cred */
 	time_t	um_btime[MAXQUOTAS];		/* (q) block quota time limit */
 	time_t	um_itime[MAXQUOTAS];		/* (q) inode quota time limit */
 	char	um_qflags[MAXQUOTAS];		/* (i) quota specific flags */
 	int64_t	um_savedmaxfilesize;		/* (c) track maxfilesize */
 	u_int	um_flags;			/* (i) filesystem flags */
 	struct	timeval um_last_fullmsg;	/* (i) last full msg time */
 	int	um_secs_fullmsg;		/* (i) seconds since full msg */
 	struct	timeval um_last_integritymsg;	/* (i) last integrity msg */
 	int	um_secs_integritymsg;		/* (i) secs since integ msg */
 	u_int	um_trim_inflight;		/* (i) outstanding trim count */
 	u_int	um_trim_inflight_blks;		/* (i) outstanding trim blks */
 	u_long	um_trim_total;			/* (i) total trim count */
 	u_long	um_trim_total_blks;		/* (i) total trim block count */
 	struct	taskqueue *um_trim_tq;		/* (c) trim request queue */
 	struct	trimlist_hashhead *um_trimhash;	/* (i) trimlist hash table */
 	u_long	um_trimlisthashsize;		/* (i) trim hash table size-1 */
 	struct	fsfail_task *um_fsfail_task;	/* (i) task for fsfail cleanup*/
 						/* (c) - below function ptrs */
 	int	(*um_balloc)(struct vnode *, off_t, int, struct ucred *,
 		    int, struct buf **);
 	int	(*um_blkatoff)(struct vnode *, off_t, char **, struct buf **);
 	int	(*um_truncate)(struct vnode *, off_t, int, struct ucred *);
 	int	(*um_update)(struct vnode *, int);
 	int	(*um_valloc)(struct vnode *, int, struct ucred *,
 		    struct vnode **);
 	int	(*um_vfree)(struct vnode *, ino_t, int);
 	void	(*um_ifree)(struct ufsmount *, struct inode *);
 	int	(*um_rdonly)(struct inode *);
 	void	(*um_snapgone)(struct inode *);
 	int	(*um_check_blkno)(struct mount *, ino_t, daddr_t, int);
 };
 
 /*
  * filesystem flags
  */
 #define UM_CANDELETE		0x00000001	/* devvp supports TRIM */
 #define UM_WRITESUSPENDED	0x00000002	/* suspension in progress */
 #define UM_CANSPEEDUP		0x00000004	/* devvp supports SPEEDUP */
 #define UM_FSFAIL_CLEANUP	0x00000008	/* need cleanup after
 						   unrecoverable error */
 /*
  * function prototypes
  */
 #define	UFS_BALLOC(aa, bb, cc, dd, ee, ff) \
 	VFSTOUFS((aa)->v_mount)->um_balloc(aa, bb, cc, dd, ee, ff)
 #define	UFS_BLKATOFF(aa, bb, cc, dd) \
 	VFSTOUFS((aa)->v_mount)->um_blkatoff(aa, bb, cc, dd)
 #define	UFS_TRUNCATE(aa, bb, cc, dd) \
 	VFSTOUFS((aa)->v_mount)->um_truncate(aa, bb, cc, dd)
 #define	UFS_UPDATE(aa, bb) VFSTOUFS((aa)->v_mount)->um_update(aa, bb)
 #define	UFS_VALLOC(aa, bb, cc, dd) \
 	VFSTOUFS((aa)->v_mount)->um_valloc(aa, bb, cc, dd)
 #define	UFS_VFREE(aa, bb, cc) VFSTOUFS((aa)->v_mount)->um_vfree(aa, bb, cc)
 #define	UFS_IFREE(aa, bb) ((aa)->um_ifree(aa, bb))
 #define	UFS_RDONLY(aa) (ITOUMP(aa)->um_rdonly(aa))
 #define	UFS_SNAPGONE(aa) (ITOUMP(aa)->um_snapgone(aa))
 #define	UFS_CHECK_BLKNO(aa, bb, cc, dd) 		\
 	(VFSTOUFS(aa)->um_check_blkno == NULL ? 0 :	\
 	 VFSTOUFS(aa)->um_check_blkno(aa, bb, cc, dd))
 
 #define	UFS_LOCK(aa)	mtx_lock(&(aa)->um_lock)
 #define	UFS_UNLOCK(aa)	mtx_unlock(&(aa)->um_lock)
 #define	UFS_MTX(aa)	(&(aa)->um_lock)
 
 /*
  * Filesystem types
  */
 #define	UFS1	1
 #define	UFS2	2
 
 /*
  * Flags describing the state of quotas.
  */
 #define	QTF_OPENING	0x01			/* Q_QUOTAON in progress */
 #define	QTF_CLOSING	0x02			/* Q_QUOTAOFF in progress */
 #define	QTF_64BIT	0x04			/* 64-bit quota file */
 
 /* Convert mount ptr to ufsmount ptr. */
 #define	VFSTOUFS(mp)	((struct ufsmount *)((mp)->mnt_data))
 #define	UFSTOVFS(ump)	(ump)->um_mountp
 
 /*
  * Macros to access filesystem parameters in the ufsmount structure.
  * Used by ufs_bmap.
  */
 #define	MNINDIR(ump)			((ump)->um_nindir)
 #define	blkptrtodb(ump, b)		((b) << (ump)->um_bptrtodb)
 #define	is_sequential(ump, a, b)	((b) == (a) + ump->um_seqinc)
-#endif /* _KERNEL */
 
 #endif
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index 4dfb37889b53..dcc6eb5cbed7 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -1,1189 +1,1189 @@
 /*	$NetBSD: ffs.c,v 1.45 2011/10/09 22:49:26 christos Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (c) 2001 Wasabi Systems, Inc.
  * All rights reserved.
  *
  * Written by Luke Mewburn for Wasabi Systems, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *      This product includes software developed for the NetBSD Project by
  *      Wasabi Systems, Inc.
  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
  *    or promote products derived from this software without specific prior
  *    written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)ffs_alloc.c	8.19 (Berkeley) 7/13/95
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #if HAVE_NBTOOL_CONFIG_H
 #include "nbtool_config.h"
 #endif
 
 #include <sys/param.h>
 
 #include <sys/mount.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 #include <util.h>
 
-#include "makefs.h"
-#include "ffs.h"
-
 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
 #include <sys/statvfs.h>
 #endif
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ufs/dir.h>
 #include <ufs/ffs/fs.h>
 
-
 #include "ffs/ufs_bswap.h"
 #include "ffs/ufs_inode.h"
 #include "ffs/newfs_extern.h"
 #include "ffs/ffs_extern.h"
 
+#undef clrbuf
+#include "makefs.h"
+#include "ffs.h"
+
 #undef DIP
 #define DIP(dp, field) \
 	((ffs_opts->version == 1) ? \
 	(dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
 
 /*
  * Various file system defaults (cribbed from newfs(8)).
  */
 #define	DFL_FRAGSIZE		4096		/* fragment size */
 #define	DFL_BLKSIZE		32768		/* block size */
 #define	DFL_SECSIZE		512		/* sector size */
 #define	DFL_CYLSPERGROUP	65536		/* cylinders per group */
 #define	DFL_FRAGSPERINODE	4		/* fragments per inode */
 #define	DFL_ROTDELAY		0		/* rotational delay */
 #define	DFL_NRPOS		1		/* rotational positions */
 #define	DFL_RPM			3600		/* rpm of disk */
 #define	DFL_NSECTORS		64		/* # of sectors */
 #define	DFL_NTRACKS		16		/* # of tracks */
 
 
 typedef struct {
 	u_char		*buf;		/* buf for directory */
 	doff_t		size;		/* full size of buf */
 	doff_t		cur;		/* offset of current entry */
 } dirbuf_t;
 
 
 static	int	ffs_create_image(const char *, fsinfo_t *);
 static	void	ffs_dump_fsinfo(fsinfo_t *);
 static	void	ffs_dump_dirbuf(dirbuf_t *, const char *, int);
 static	void	ffs_make_dirbuf(dirbuf_t *, const char *, fsnode *, int);
 static	int	ffs_populate_dir(const char *, fsnode *, fsinfo_t *);
 static	void	ffs_size_dir(fsnode *, fsinfo_t *);
 static	void	ffs_validate(const char *, fsnode *, fsinfo_t *);
 static	void	ffs_write_file(union dinode *, uint32_t, void *, fsinfo_t *);
 static	void	ffs_write_inode(union dinode *, uint32_t, const fsinfo_t *);
 static  void	*ffs_build_dinode1(struct ufs1_dinode *, dirbuf_t *, fsnode *,
 				 fsnode *, fsinfo_t *);
 static  void	*ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *,
 				 fsnode *, fsinfo_t *);
 
 
 	/* publicly visible functions */
 
 void
 ffs_prep_opts(fsinfo_t *fsopts)
 {
 	ffs_opt_t *ffs_opts = ecalloc(1, sizeof(*ffs_opts));
 
 	const option_t ffs_options[] = {
 	    { 'b', "bsize", &ffs_opts->bsize, OPT_INT32,
 	      1, INT_MAX, "block size" },
 	    { 'f', "fsize", &ffs_opts->fsize, OPT_INT32,
 	      1, INT_MAX, "fragment size" },
 	    { 'd', "density", &ffs_opts->density, OPT_INT32,
 	      1, INT_MAX, "bytes per inode" },
 	    { 'm', "minfree", &ffs_opts->minfree, OPT_INT32,
 	      0, 99, "minfree" },
 	    { 'M', "maxbpg", &ffs_opts->maxbpg, OPT_INT32,
 	      1, INT_MAX, "max blocks per file in a cg" },
 	    { 'a', "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32,
 	      1, INT_MAX, "expected average file size" },
 	    { 'n', "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32,
 	      1, INT_MAX, "expected # of files per directory" },
 	    { 'x', "extent", &ffs_opts->maxbsize, OPT_INT32,
 	      1, INT_MAX, "maximum # extent size" },
 	    { 'g', "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32,
 	      1, INT_MAX, "max # of blocks per group" },
 	    { 'v', "version", &ffs_opts->version, OPT_INT32,
 	      1, 2, "UFS version" },
 	    { 'o', "optimization", NULL, OPT_STRBUF,
 	      0, 0, "Optimization (time|space)" },
 	    { 'l', "label", ffs_opts->label, OPT_STRARRAY,
 	      1, sizeof(ffs_opts->label), "UFS label" },
 	    { 's', "softupdates", &ffs_opts->softupdates, OPT_INT32,
 	      0, 1, "enable softupdates" },
 	    { .name = NULL }
 	};
 
 	ffs_opts->bsize= -1;
 	ffs_opts->fsize= -1;
 	ffs_opts->cpg= -1;
 	ffs_opts->density= -1;
 	ffs_opts->minfree= -1;
 	ffs_opts->optimization= -1;
 	ffs_opts->maxcontig= -1;
 	ffs_opts->maxbpg= -1;
 	ffs_opts->avgfilesize= -1;
 	ffs_opts->avgfpdir= -1;
 	ffs_opts->version = 1;
 	ffs_opts->softupdates = 0;
 
 	fsopts->fs_specific = ffs_opts;
 	fsopts->fs_options = copy_opts(ffs_options);
 }
 
 void
 ffs_cleanup_opts(fsinfo_t *fsopts)
 {
 	free(fsopts->fs_specific);
 	free(fsopts->fs_options);
 }
 
 int
 ffs_parse_opts(const char *option, fsinfo_t *fsopts)
 {
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
 	option_t *ffs_options = fsopts->fs_options;
 	char buf[1024];
 
 	int	rv;
 
 	assert(option != NULL);
 	assert(fsopts != NULL);
 	assert(ffs_opts != NULL);
 
 	if (debug & DEBUG_FS_PARSE_OPTS)
 		printf("ffs_parse_opts: got `%s'\n", option);
 
 	rv = set_option(ffs_options, option, buf, sizeof(buf));
 	if (rv == -1)
 		return 0;
 
 	if (ffs_options[rv].name == NULL)
 		abort();
 
 	switch (ffs_options[rv].letter) {
 	case 'o':
 		if (strcmp(buf, "time") == 0) {
 			ffs_opts->optimization = FS_OPTTIME;
 		} else if (strcmp(buf, "space") == 0) {
 			ffs_opts->optimization = FS_OPTSPACE;
 		} else {
 			warnx("Invalid optimization `%s'", buf);
 			return 0;
 		}
 		break;
 	default:
 		break;
 	}
 	return 1;
 }
 
 
 void
 ffs_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
 {
 	struct fs	*superblock;
 	struct timeval	start;
 
 	assert(image != NULL);
 	assert(dir != NULL);
 	assert(root != NULL);
 	assert(fsopts != NULL);
 
 	if (debug & DEBUG_FS_MAKEFS)
 		printf("ffs_makefs: image %s directory %s root %p\n",
 		    image, dir, root);
 
 		/* validate tree and options */
 	TIMER_START(start);
 	ffs_validate(dir, root, fsopts);
 	TIMER_RESULTS(start, "ffs_validate");
 
 	printf("Calculated size of `%s': %lld bytes, %lld inodes\n",
 	    image, (long long)fsopts->size, (long long)fsopts->inodes);
 
 		/* create image */
 	TIMER_START(start);
 	if (ffs_create_image(image, fsopts) == -1)
 		errx(1, "Image file `%s' not created.", image);
 	TIMER_RESULTS(start, "ffs_create_image");
 
 	fsopts->curinode = UFS_ROOTINO;
 
 	if (debug & DEBUG_FS_MAKEFS)
 		putchar('\n');
 
 		/* populate image */
 	printf("Populating `%s'\n", image);
 	TIMER_START(start);
 	if (! ffs_populate_dir(dir, root, fsopts))
 		errx(1, "Image file `%s' not populated.", image);
 	TIMER_RESULTS(start, "ffs_populate_dir");
 
 		/* ensure no outstanding buffers remain */
 	if (debug & DEBUG_FS_MAKEFS)
 		bcleanup();
 
 		/* update various superblock parameters */
 	superblock = fsopts->superblock;
 	superblock->fs_fmod = 0;
 	superblock->fs_old_cstotal.cs_ndir   = superblock->fs_cstotal.cs_ndir;
 	superblock->fs_old_cstotal.cs_nbfree = superblock->fs_cstotal.cs_nbfree;
 	superblock->fs_old_cstotal.cs_nifree = superblock->fs_cstotal.cs_nifree;
 	superblock->fs_old_cstotal.cs_nffree = superblock->fs_cstotal.cs_nffree;
 
 		/* write out superblock; image is now complete */
 	ffs_write_superblock(fsopts->superblock, fsopts);
 	if (close(fsopts->fd) == -1)
 		err(1, "Closing `%s'", image);
 	fsopts->fd = -1;
 	printf("Image `%s' complete\n", image);
 }
 
 	/* end of public functions */
 
 
 static void
 ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
 {
 	int32_t	ncg = 1;
 #ifdef notyet
 	int32_t	spc, nspf, ncyl, fssize;
 #endif
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
 
 	assert(dir != NULL);
 	assert(root != NULL);
 	assert(fsopts != NULL);
 	assert(ffs_opts != NULL);
 
 	if (debug & DEBUG_FS_VALIDATE) {
 		printf("ffs_validate: before defaults set:\n");
 		ffs_dump_fsinfo(fsopts);
 	}
 
 		/* set FFS defaults */
 	if (fsopts->sectorsize == -1)
 		fsopts->sectorsize = DFL_SECSIZE;
 	if (ffs_opts->fsize == -1)
 		ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
 	if (ffs_opts->bsize == -1)
 		ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize);
 	if (ffs_opts->cpg == -1)
 		ffs_opts->cpg = DFL_CYLSPERGROUP;
 	else
 		ffs_opts->cpgflg = 1;
 				/* fsopts->density is set below */
 	if (ffs_opts->nsectors == -1)
 		ffs_opts->nsectors = DFL_NSECTORS;
 	if (ffs_opts->minfree == -1)
 		ffs_opts->minfree = MINFREE;
 	if (ffs_opts->optimization == -1)
 		ffs_opts->optimization = DEFAULTOPT;
 	if (ffs_opts->maxcontig == -1)
 		ffs_opts->maxcontig =
 		    MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize);
 	/* XXX ondisk32 */
 	if (ffs_opts->maxbpg == -1)
 		ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
 	if (ffs_opts->avgfilesize == -1)
 		ffs_opts->avgfilesize = AVFILESIZ;
 	if (ffs_opts->avgfpdir == -1)
 		ffs_opts->avgfpdir = AFPDIR;
 
 	if (fsopts->maxsize > 0 &&
 	    roundup(fsopts->minsize, ffs_opts->bsize) > fsopts->maxsize)
 		errx(1, "`%s' minsize of %lld rounded up to ffs bsize of %d "
 		    "exceeds maxsize %lld.  Lower bsize, or round the minimum "
 		    "and maximum sizes to bsize.", dir,
 		    (long long)fsopts->minsize, ffs_opts->bsize,
 		    (long long)fsopts->maxsize);
 
 		/* calculate size of tree */
 	ffs_size_dir(root, fsopts);
 	fsopts->inodes += UFS_ROOTINO;		/* include first two inodes */
 
 	if (debug & DEBUG_FS_VALIDATE)
 		printf("ffs_validate: size of tree: %lld bytes, %lld inodes\n",
 		    (long long)fsopts->size, (long long)fsopts->inodes);
 
 		/* add requested slop */
 	fsopts->size += fsopts->freeblocks;
 	fsopts->inodes += fsopts->freefiles;
 	if (fsopts->freefilepc > 0)
 		fsopts->inodes =
 		    fsopts->inodes * (100 + fsopts->freefilepc) / 100;
 	if (fsopts->freeblockpc > 0)
 		fsopts->size =
 		    fsopts->size * (100 + fsopts->freeblockpc) / 100;
 
 		/* add space needed for superblocks */
 	/*
 	 * The old SBOFF (SBLOCK_UFS1) is used here because makefs is
 	 * typically used for small filesystems where space matters.
 	 * XXX make this an option.
 	 */
 	fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
 		/* add space needed to store inodes, x3 for blockmaps, etc */
 	if (ffs_opts->version == 1)
 		fsopts->size += ncg * DINODE1_SIZE *
 		    roundup(fsopts->inodes / ncg, 
 			ffs_opts->bsize / DINODE1_SIZE);
 	else
 		fsopts->size += ncg * DINODE2_SIZE *
 		    roundup(fsopts->inodes / ncg, 
 			ffs_opts->bsize / DINODE2_SIZE);
 
 		/* add minfree */
 	if (ffs_opts->minfree > 0)
 		fsopts->size =
 		    fsopts->size * (100 + ffs_opts->minfree) / 100;
 	/*
 	 * XXX	any other fs slop to add, such as csum's, bitmaps, etc ??
 	 */
 
 	if (fsopts->size < fsopts->minsize)	/* ensure meets minimum size */
 		fsopts->size = fsopts->minsize;
 
 		/* round up to the next block */
 	fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
 
 		/* round up to requested block size, if any */
 	if (fsopts->roundup > 0)
 		fsopts->size = roundup(fsopts->size, fsopts->roundup);
 
 		/* calculate density if necessary */
 	if (ffs_opts->density == -1)
 		ffs_opts->density = fsopts->size / fsopts->inodes + 1;
 
 	if (debug & DEBUG_FS_VALIDATE) {
 		printf("ffs_validate: after defaults set:\n");
 		ffs_dump_fsinfo(fsopts);
 		printf("ffs_validate: dir %s; %lld bytes, %lld inodes\n",
 		    dir, (long long)fsopts->size, (long long)fsopts->inodes);
 	}
 		/* now check calculated sizes vs requested sizes */
 	if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
 		errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
 		    dir, (long long)fsopts->size, (long long)fsopts->maxsize);
 	}
 }
 
 
 static void
 ffs_dump_fsinfo(fsinfo_t *f)
 {
 
 	ffs_opt_t	*fs = f->fs_specific;
 
 	printf("fsopts at %p\n", f);
 
 	printf("\tsize %lld, inodes %lld, curinode %u\n",
 	    (long long)f->size, (long long)f->inodes, f->curinode);
 
 	printf("\tminsize %lld, maxsize %lld\n",
 	    (long long)f->minsize, (long long)f->maxsize);
 	printf("\tfree files %lld, freefile %% %d\n",
 	    (long long)f->freefiles, f->freefilepc);
 	printf("\tfree blocks %lld, freeblock %% %d\n",
 	    (long long)f->freeblocks, f->freeblockpc);
 	printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
 
 	printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
 	    fs->bsize, fs->fsize, fs->cpg, fs->density);
 	printf("\tnsectors %d, rpm %d, minfree %d\n",
 	    fs->nsectors, fs->rpm, fs->minfree);
 	printf("\tmaxcontig %d, maxbpg %d\n",
 	    fs->maxcontig, fs->maxbpg);
 	printf("\toptimization %s\n",
 	    fs->optimization == FS_OPTSPACE ? "space" : "time");
 }
 
 
 static int
 ffs_create_image(const char *image, fsinfo_t *fsopts)
 {
 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
 	struct statvfs	sfs;
 #endif
 	struct fs	*fs;
 	char	*buf;
 	int	i, bufsize;
 	off_t	bufrem;
 	int	oflags = O_RDWR | O_CREAT;
 	time_t	tstamp;
 
 	assert (image != NULL);
 	assert (fsopts != NULL);
 
 		/* create image */
 	if (fsopts->offset == 0)
 		oflags |= O_TRUNC;
 	if ((fsopts->fd = open(image, oflags, 0666)) == -1) {
 		warn("Can't open `%s' for writing", image);
 		return (-1);
 	}
 
 		/* zero image */
 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
 	if (fstatvfs(fsopts->fd, &sfs) == -1) {
 #endif
 		bufsize = 8192;
 #if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
 		warn("can't fstatvfs `%s', using default %d byte chunk",
 		    image, bufsize);
 	} else
 		bufsize = sfs.f_iosize;
 #endif
 	bufrem = fsopts->size;
 	if (fsopts->sparse) {
 		if (ftruncate(fsopts->fd, bufrem) == -1) {
 			warn("sparse option disabled.");
 			fsopts->sparse = 0;
 		}
 	}
 	if (fsopts->sparse) {
 		/* File truncated at bufrem. Remaining is 0 */
 		bufrem = 0;
 		buf = NULL;
 	} else {
 		if (debug & DEBUG_FS_CREATE_IMAGE)
 			printf("zero-ing image `%s', %lld sectors, "
 			    "using %d byte chunks\n", image, (long long)bufrem,
 			    bufsize);
 		buf = ecalloc(1, bufsize);
 	}
 
 	if (fsopts->offset != 0)
 		if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) {
 			warn("can't seek");
 			free(buf);
 			return -1;
 		}
 
 	while (bufrem > 0) {
 		i = write(fsopts->fd, buf, MIN(bufsize, bufrem));
 		if (i == -1) {
 			warn("zeroing image, %lld bytes to go",
 			    (long long)bufrem);
 			free(buf);
 			return (-1);
 		}
 		bufrem -= i;
 	}
 	if (buf)
 		free(buf);
 
 		/* make the file system */
 	if (debug & DEBUG_FS_CREATE_IMAGE)
 		printf("calling mkfs(\"%s\", ...)\n", image);
 
 	if (stampst.st_ino != 0)
 		tstamp = stampst.st_ctime;
 	else
 		tstamp = start_time.tv_sec;
 
 	srandom(tstamp);
 
 	fs = ffs_mkfs(image, fsopts, tstamp);
 	fsopts->superblock = (void *)fs;
 	if (debug & DEBUG_FS_CREATE_IMAGE) {
 		time_t t;
 
 		t = (time_t)((struct fs *)fsopts->superblock)->fs_time;
 		printf("mkfs returned %p; fs_time %s",
 		    fsopts->superblock, ctime(&t));
 		printf("fs totals: nbfree %lld, nffree %lld, nifree %lld, ndir %lld\n",
 		    (long long)fs->fs_cstotal.cs_nbfree,
 		    (long long)fs->fs_cstotal.cs_nffree,
 		    (long long)fs->fs_cstotal.cs_nifree,
 		    (long long)fs->fs_cstotal.cs_ndir);
 	}
 
 	if (fs->fs_cstotal.cs_nifree + UFS_ROOTINO < fsopts->inodes) {
 		warnx(
 		"Image file `%s' has %lld free inodes; %lld are required.",
 		    image,
 		    (long long)(fs->fs_cstotal.cs_nifree + UFS_ROOTINO),
 		    (long long)fsopts->inodes);
 		return (-1);
 	}
 	return (fsopts->fd);
 }
 
 
 static void
 ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
 {
 	struct direct	tmpdir;
 	fsnode *	node;
 	int		curdirsize, this;
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
 
 	/* node may be NULL (empty directory) */
 	assert(fsopts != NULL);
 	assert(ffs_opts != NULL);
 
 	if (debug & DEBUG_FS_SIZE_DIR)
 		printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
 		    (long long)fsopts->size, (long long)fsopts->inodes);
 
 #define	ADDDIRENT(e) do {						\
 	tmpdir.d_namlen = strlen((e));					\
 	this = DIRSIZ_SWAP(0, &tmpdir, 0);					\
 	if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)			\
 		printf("ADDDIRENT: was: %s (%d) this %d cur %d\n",	\
 		    e, tmpdir.d_namlen, this, curdirsize);		\
 	if (this + curdirsize > roundup(curdirsize, DIRBLKSIZ))		\
 		curdirsize = roundup(curdirsize, DIRBLKSIZ);		\
 	curdirsize += this;						\
 	if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT)			\
 		printf("ADDDIRENT: now: %s (%d) this %d cur %d\n",	\
 		    e, tmpdir.d_namlen, this, curdirsize);		\
 } while (0);
 
 	/*
 	 * XXX	this needs to take into account extra space consumed
 	 *	by indirect blocks, etc.
 	 */
 #define	ADDSIZE(x) do {							\
 	fsopts->size += roundup((x), ffs_opts->fsize);			\
 } while (0);
 
 	curdirsize = 0;
 	for (node = root; node != NULL; node = node->next) {
 		ADDDIRENT(node->name);
 		if (node == root) {			/* we're at "." */
 			assert(strcmp(node->name, ".") == 0);
 			ADDDIRENT("..");
 		} else if ((node->inode->flags & FI_SIZED) == 0) {
 				/* don't count duplicate names */
 			node->inode->flags |= FI_SIZED;
 			if (debug & DEBUG_FS_SIZE_DIR_NODE)
 				printf("ffs_size_dir: `%s' size %lld\n",
 				    node->name,
 				    (long long)node->inode->st.st_size);
 			fsopts->inodes++;
 			if (node->type == S_IFREG)
 				ADDSIZE(node->inode->st.st_size);
 			if (node->type == S_IFLNK) {
 				size_t slen;
 
 				slen = strlen(node->symlink) + 1;
 				if (slen >= (ffs_opts->version == 1 ?
 						UFS1_MAXSYMLINKLEN :
 						UFS2_MAXSYMLINKLEN))
 					ADDSIZE(slen);
 			}
 		}
 		if (node->type == S_IFDIR)
 			ffs_size_dir(node->child, fsopts);
 	}
 	ADDSIZE(curdirsize);
 
 	if (debug & DEBUG_FS_SIZE_DIR)
 		printf("ffs_size_dir: exit: size %lld inodes %lld\n",
 		    (long long)fsopts->size, (long long)fsopts->inodes);
 }
 
 static void *
 ffs_build_dinode1(struct ufs1_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
 		 fsnode *root, fsinfo_t *fsopts)
 {
 	size_t slen;
 	void *membuf;
 	struct stat *st = stampst.st_ino != 0 ? &stampst : &cur->inode->st;
 
 	memset(dinp, 0, sizeof(*dinp));
 	dinp->di_mode = cur->inode->st.st_mode;
 	dinp->di_nlink = cur->inode->nlink;
 	dinp->di_size = cur->inode->st.st_size;
 #if HAVE_STRUCT_STAT_ST_FLAGS
 	dinp->di_flags = cur->inode->st.st_flags;
 #endif
 	dinp->di_gen = random();
 	dinp->di_uid = cur->inode->st.st_uid;
 	dinp->di_gid = cur->inode->st.st_gid;
 
 	dinp->di_atime = st->st_atime;
 	dinp->di_mtime = st->st_mtime;
 	dinp->di_ctime = st->st_ctime;
 #if HAVE_STRUCT_STAT_ST_MTIMENSEC
 	dinp->di_atimensec = st->st_atimensec;
 	dinp->di_mtimensec = st->st_mtimensec;
 	dinp->di_ctimensec = st->st_ctimensec;
 #endif
 		/* not set: di_db, di_ib, di_blocks, di_spare */
 
 	membuf = NULL;
 	if (cur == root) {			/* "."; write dirbuf */
 		membuf = dbufp->buf;
 		dinp->di_size = dbufp->size;
 	} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
 		dinp->di_size = 0;	/* a device */
 		dinp->di_rdev =
 		    ufs_rw32(cur->inode->st.st_rdev, fsopts->needswap);
 	} else if (S_ISLNK(cur->type)) {	/* symlink */
 		slen = strlen(cur->symlink);
 		if (slen < UFS1_MAXSYMLINKLEN) {	/* short link */
 			memcpy(dinp->di_db, cur->symlink, slen);
 		} else
 			membuf = cur->symlink;
 		dinp->di_size = slen;
 	}
 	return membuf;
 }
 
 static void *
 ffs_build_dinode2(struct ufs2_dinode *dinp, dirbuf_t *dbufp, fsnode *cur,
 		 fsnode *root, fsinfo_t *fsopts)
 {
 	size_t slen;
 	void *membuf;
 	struct stat *st = stampst.st_ino != 0 ? &stampst : &cur->inode->st;
 
 	memset(dinp, 0, sizeof(*dinp));
 	dinp->di_mode = cur->inode->st.st_mode;
 	dinp->di_nlink = cur->inode->nlink;
 	dinp->di_size = cur->inode->st.st_size;
 #if HAVE_STRUCT_STAT_ST_FLAGS
 	dinp->di_flags = cur->inode->st.st_flags;
 #endif
 	dinp->di_gen = random();
 	dinp->di_uid = cur->inode->st.st_uid;
 	dinp->di_gid = cur->inode->st.st_gid;
 
 	dinp->di_atime = st->st_atime;
 	dinp->di_mtime = st->st_mtime;
 	dinp->di_ctime = st->st_ctime;
 #if HAVE_STRUCT_STAT_BIRTHTIME
 	dinp->di_birthtime = st->st_birthtime;
 #else
 	dinp->di_birthtime = st->st_ctime;
 #endif
 #if HAVE_STRUCT_STAT_ST_MTIMENSEC
 	dinp->di_atimensec = st->st_atimensec;
 	dinp->di_mtimensec = st->st_mtimensec;
 	dinp->di_ctimensec = st->st_ctimensec;
 #if HAVE_STRUCT_STAT_BIRTHTIME
 	dinp->di_birthnsec = st->st_birthtimensec;
 #else
 	dinp->di_birthnsec = st->st_ctimensec;
 #endif
 #endif
 
 		/* not set: di_db, di_ib, di_blocks, di_spare */
 
 	membuf = NULL;
 	if (cur == root) {			/* "."; write dirbuf */
 		membuf = dbufp->buf;
 		dinp->di_size = dbufp->size;
 	} else if (S_ISBLK(cur->type) || S_ISCHR(cur->type)) {
 		dinp->di_size = 0;	/* a device */
 		dinp->di_rdev =
 		    ufs_rw64(cur->inode->st.st_rdev, fsopts->needswap);
 	} else if (S_ISLNK(cur->type)) {	/* symlink */
 		slen = strlen(cur->symlink);
 		if (slen < UFS2_MAXSYMLINKLEN) {	/* short link */
 			memcpy(dinp->di_db, cur->symlink, slen);
 		} else
 			membuf = cur->symlink;
 		dinp->di_size = slen;
 	}
 	return membuf;
 }
 
 static int
 ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
 {
 	fsnode		*cur;
 	dirbuf_t	dirbuf;
 	union dinode	din;
 	void		*membuf;
 	char		path[MAXPATHLEN + 1];
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
 
 	assert(dir != NULL);
 	assert(root != NULL);
 	assert(fsopts != NULL);
 	assert(ffs_opts != NULL);
 
 	(void)memset(&dirbuf, 0, sizeof(dirbuf));
 
 	if (debug & DEBUG_FS_POPULATE)
 		printf("ffs_populate_dir: PASS 1  dir %s node %p\n", dir, root);
 
 		/*
 		 * pass 1: allocate inode numbers, build directory `file'
 		 */
 	for (cur = root; cur != NULL; cur = cur->next) {
 		if ((cur->inode->flags & FI_ALLOCATED) == 0) {
 			cur->inode->flags |= FI_ALLOCATED;
 			if (cur == root && cur->parent != NULL)
 				cur->inode->ino = cur->parent->inode->ino;
 			else {
 				cur->inode->ino = fsopts->curinode;
 				fsopts->curinode++;
 			}
 		}
 		ffs_make_dirbuf(&dirbuf, cur->name, cur, fsopts->needswap);
 		if (cur == root) {		/* we're at "."; add ".." */
 			ffs_make_dirbuf(&dirbuf, "..",
 			    cur->parent == NULL ? cur : cur->parent->first,
 			    fsopts->needswap);
 			root->inode->nlink++;	/* count my parent's link */
 		} else if (cur->child != NULL)
 			root->inode->nlink++;	/* count my child's link */
 
 		/*
 		 * XXX	possibly write file and long symlinks here,
 		 *	ensuring that blocks get written before inodes?
 		 *	otoh, this isn't a real filesystem, so who
 		 *	cares about ordering? :-)
 		 */
 	}
 	if (debug & DEBUG_FS_POPULATE_DIRBUF)
 		ffs_dump_dirbuf(&dirbuf, dir, fsopts->needswap);
 
 		/*
 		 * pass 2: write out dirbuf, then non-directories at this level
 		 */
 	if (debug & DEBUG_FS_POPULATE)
 		printf("ffs_populate_dir: PASS 2  dir %s\n", dir);
 	for (cur = root; cur != NULL; cur = cur->next) {
 		if (cur->inode->flags & FI_WRITTEN)
 			continue;		/* skip hard-linked entries */
 		cur->inode->flags |= FI_WRITTEN;
 
 		if (cur->contents == NULL) {
 			if (snprintf(path, sizeof(path), "%s/%s/%s", cur->root,
 			    cur->path, cur->name) >= (int)sizeof(path))
 				errx(1, "Pathname too long.");
 		}
 
 		if (cur->child != NULL)
 			continue;		/* child creates own inode */
 
 				/* build on-disk inode */
 		if (ffs_opts->version == 1)
 			membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
 			    root, fsopts);
 		else
 			membuf = ffs_build_dinode2(&din.ffs2_din, &dirbuf, cur,
 			    root, fsopts);
 
 		if (debug & DEBUG_FS_POPULATE_NODE) {
 			printf("ffs_populate_dir: writing ino %d, %s",
 			    cur->inode->ino, inode_type(cur->type));
 			if (cur->inode->nlink > 1)
 				printf(", nlink %d", cur->inode->nlink);
 			putchar('\n');
 		}
 
 		if (membuf != NULL) {
 			ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
 		} else if (S_ISREG(cur->type)) {
 			ffs_write_file(&din, cur->inode->ino,
 			    (cur->contents) ?  cur->contents : path, fsopts);
 		} else {
 			assert (! S_ISDIR(cur->type));
 			ffs_write_inode(&din, cur->inode->ino, fsopts);
 		}
 	}
 
 		/*
 		 * pass 3: write out sub-directories
 		 */
 	if (debug & DEBUG_FS_POPULATE)
 		printf("ffs_populate_dir: PASS 3  dir %s\n", dir);
 	for (cur = root; cur != NULL; cur = cur->next) {
 		if (cur->child == NULL)
 			continue;
 		if ((size_t)snprintf(path, sizeof(path), "%s/%s", dir,
 		    cur->name) >= sizeof(path))
 			errx(1, "Pathname too long.");
 		if (! ffs_populate_dir(path, cur->child, fsopts))
 			return (0);
 	}
 
 	if (debug & DEBUG_FS_POPULATE)
 		printf("ffs_populate_dir: DONE dir %s\n", dir);
 
 		/* cleanup */
 	if (dirbuf.buf != NULL)
 		free(dirbuf.buf);
 	return (1);
 }
 
 
 static void
 ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
 {
 	int 	isfile, ffd;
 	char	*fbuf, *p;
 	off_t	bufleft, chunk, offset;
 	ssize_t nread;
 	struct inode	in;
-	struct buf *	bp;
+	struct m_buf *	bp;
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
-	struct vnode vp = { fsopts, NULL };
+	struct m_vnode vp = { fsopts, NULL };
 
 	assert (din != NULL);
 	assert (buf != NULL);
 	assert (fsopts != NULL);
 	assert (ffs_opts != NULL);
 
 	isfile = S_ISREG(DIP(din, mode));
 	fbuf = NULL;
 	ffd = -1;
 	p = NULL;
 
 	in.i_fs = (struct fs *)fsopts->superblock;
-	in.i_devvp = &vp;
+	in.i_devvp = (void *)&vp;
 
 	if (debug & DEBUG_FS_WRITE_FILE) {
 		printf(
 		    "ffs_write_file: ino %u, din %p, isfile %d, %s, size %lld",
 		    ino, din, isfile, inode_type(DIP(din, mode) & S_IFMT),
 		    (long long)DIP(din, size));
 		if (isfile)
 			printf(", file '%s'\n", (char *)buf);
 		else
 			printf(", buffer %p\n", buf);
 	}
 
 	in.i_number = ino;
 	in.i_size = DIP(din, size);
 	if (ffs_opts->version == 1)
 		memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
 		    sizeof(in.i_din.ffs1_din));
 	else
 		memcpy(&in.i_din.ffs2_din, &din->ffs2_din,
 		    sizeof(in.i_din.ffs2_din));
 
 	if (DIP(din, size) == 0)
 		goto write_inode_and_leave;		/* mmm, cheating */
 
 	if (isfile) {
 		fbuf = emalloc(ffs_opts->bsize);
 		if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
 			err(EXIT_FAILURE, "Can't open `%s' for reading", (char *)buf);
 		}
 	} else {
 		p = buf;
 	}
 
 	chunk = 0;
 	for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
 		chunk = MIN(bufleft, ffs_opts->bsize);
 		if (!isfile)
 			;
 		else if ((nread = read(ffd, fbuf, chunk)) == -1)
 			err(EXIT_FAILURE, "Reading `%s', %lld bytes to go",
 			    (char *)buf, (long long)bufleft);
 		else if (nread != chunk)
 			errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, "
 			    "read %zd bytes, expected %ju bytes, does "
 			    "metalog size= attribute mismatch source size?",
 			    (char *)buf, (long long)bufleft, nread,
 			    (uintmax_t)chunk);
 		else
 			p = fbuf;
 		offset = DIP(din, size) - bufleft;
 		if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
 			printf(
 		"ffs_write_file: write %p offset %lld size %lld left %lld\n",
 			    p, (long long)offset,
 			    (long long)chunk, (long long)bufleft);
 	/*
 	 * XXX	if holey support is desired, do the check here
 	 *
 	 * XXX	might need to write out last bit in fragroundup
 	 *	sized chunk. however, ffs_balloc() handles this for us
 	 */
 		errno = ffs_balloc(&in, offset, chunk, &bp);
  bad_ffs_write_file:
 		if (errno != 0)
 			err(1,
 			    "Writing inode %d (%s), bytes %lld + %lld",
 			    ino,
 			    isfile ? (char *)buf :
 			      inode_type(DIP(din, mode) & S_IFMT),
 			    (long long)offset, (long long)chunk);
 		memcpy(bp->b_data, p, chunk);
 		errno = bwrite(bp);
 		if (errno != 0)
 			goto bad_ffs_write_file;
 		brelse(bp);
 		if (!isfile)
 			p += chunk;
 	}
   
  write_inode_and_leave:
 	ffs_write_inode(&in.i_din, in.i_number, fsopts);
 	if (fbuf)
 		free(fbuf);
 	if (ffd != -1)
 		close(ffd);
 }
 
 
 static void
 ffs_dump_dirbuf(dirbuf_t *dbuf, const char *dir, int needswap)
 {
 	doff_t		i;
 	struct direct	*de;
 	uint16_t	reclen;
 
 	assert (dbuf != NULL);
 	assert (dir != NULL);
 	printf("ffs_dump_dirbuf: dir %s size %d cur %d\n",
 	    dir, dbuf->size, dbuf->cur);
 
 	for (i = 0; i < dbuf->size; ) {
 		de = (struct direct *)(dbuf->buf + i);
 		reclen = ufs_rw16(de->d_reclen, needswap);
 		printf(
 	    " inode %4d %7s offset %4d reclen %3d namlen %3d name %s\n",
 		    ufs_rw32(de->d_ino, needswap),
 		    inode_type(DTTOIF(de->d_type)), i, reclen,
 		    de->d_namlen, de->d_name);
 		i += reclen;
 		assert(reclen > 0);
 	}
 }
 
 static void
 ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
 {
 	struct direct	de, *dp;
 	uint16_t	llen, reclen;
 	u_char		*newbuf;
 
 	assert (dbuf != NULL);
 	assert (name != NULL);
 	assert (node != NULL);
 					/* create direct entry */
 	(void)memset(&de, 0, sizeof(de));
 	de.d_ino = ufs_rw32(node->inode->ino, needswap);
 	de.d_type = IFTODT(node->type);
 	de.d_namlen = (uint8_t)strlen(name);
 	strcpy(de.d_name, name);
 	reclen = DIRSIZ_SWAP(0, &de, needswap);
 	de.d_reclen = ufs_rw16(reclen, needswap);
 
 	dp = (struct direct *)(dbuf->buf + dbuf->cur);
 	llen = 0;
 	if (dp != NULL)
 		llen = DIRSIZ_SWAP(0, dp, needswap);
 
 	if (debug & DEBUG_FS_MAKE_DIRBUF)
 		printf(
 		    "ffs_make_dirbuf: dbuf siz %d cur %d lastlen %d\n"
 		    "  ino %d type %d reclen %d namlen %d name %.30s\n",
 		    dbuf->size, dbuf->cur, llen,
 		    ufs_rw32(de.d_ino, needswap), de.d_type, reclen,
 		    de.d_namlen, de.d_name);
 
 	if (reclen + dbuf->cur + llen > roundup(dbuf->size, DIRBLKSIZ)) {
 		if (debug & DEBUG_FS_MAKE_DIRBUF)
 			printf("ffs_make_dirbuf: growing buf to %d\n",
 			    dbuf->size + DIRBLKSIZ);
 		newbuf = erealloc(dbuf->buf, dbuf->size + DIRBLKSIZ);
 		dbuf->buf = newbuf;
 		dbuf->size += DIRBLKSIZ;
 		memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
 		dbuf->cur = dbuf->size - DIRBLKSIZ;
 	} else if (dp) {			/* shrink end of previous */
 		dp->d_reclen = ufs_rw16(llen,needswap);
 		dbuf->cur += llen;
 	}
 	dp = (struct direct *)(dbuf->buf + dbuf->cur);
 	memcpy(dp, &de, reclen);
 	dp->d_reclen = ufs_rw16(dbuf->size - dbuf->cur, needswap);
 }
 
 /*
  * cribbed from sys/ufs/ffs/ffs_alloc.c
  */
 static void
 ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
 {
 	char 		*buf;
 	struct ufs1_dinode *dp1;
 	struct ufs2_dinode *dp2, *dip;
 	struct cg	*cgp;
 	struct fs	*fs;
 	int		cg, cgino;
 	uint32_t	i;
 	daddr_t		d;
 	char		sbbuf[FFS_MAXBSIZE];
 	uint32_t	initediblk;
 	ffs_opt_t	*ffs_opts = fsopts->fs_specific;
 
 	assert (dp != NULL);
 	assert (ino > 0);
 	assert (fsopts != NULL);
 	assert (ffs_opts != NULL);
 
 	fs = (struct fs *)fsopts->superblock;
 	cg = ino_to_cg(fs, ino);
 	cgino = ino % fs->fs_ipg;
 	if (debug & DEBUG_FS_WRITE_INODE)
 		printf("ffs_write_inode: din %p ino %u cg %d cgino %d\n",
 		    dp, ino, cg, cgino);
 
 	ffs_rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
 	    fsopts);
 	cgp = (struct cg *)sbbuf;
 	if (!cg_chkmagic_swap(cgp, fsopts->needswap))
 		errx(1, "ffs_write_inode: cg %d: bad magic number", cg);
 
 	assert (isclr(cg_inosused_swap(cgp, fsopts->needswap), cgino));
 
 	buf = emalloc(fs->fs_bsize);
 	dp1 = (struct ufs1_dinode *)buf;
 	dp2 = (struct ufs2_dinode *)buf;
 
 	if (fs->fs_cstotal.cs_nifree == 0)
 		errx(1, "ffs_write_inode: fs out of inodes for ino %u",
 		    ino);
 	if (fs->fs_cs(fs, cg).cs_nifree == 0)
 		errx(1,
 		    "ffs_write_inode: cg %d out of inodes for ino %u",
 		    cg, ino);
 	setbit(cg_inosused_swap(cgp, fsopts->needswap), cgino);
 	ufs_add32(cgp->cg_cs.cs_nifree, -1, fsopts->needswap);
 	fs->fs_cstotal.cs_nifree--;
 	fs->fs_cs(fs, cg).cs_nifree--;
 	if (S_ISDIR(DIP(dp, mode))) {
 		ufs_add32(cgp->cg_cs.cs_ndir, 1, fsopts->needswap);
 		fs->fs_cstotal.cs_ndir++;
 		fs->fs_cs(fs, cg).cs_ndir++; 
 	}
 
 	/*
 	 * Initialize inode blocks on the fly for UFS2.
 	 */
 	initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap);
 	while (ffs_opts->version == 2 && cgino + INOPB(fs) > initediblk &&
 	    initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) {
 		memset(buf, 0, fs->fs_bsize);
 		dip = (struct ufs2_dinode *)buf;
 		for (i = 0; i < INOPB(fs); i++) {
 			dip->di_gen = random();
 			dip++;
 		}
 		ffs_wtfs(fsbtodb(fs, ino_to_fsba(fs,
 				  cg * fs->fs_ipg + initediblk)),
 		    fs->fs_bsize, buf, fsopts);
 		initediblk += INOPB(fs);
 		cgp->cg_initediblk = ufs_rw32(initediblk, fsopts->needswap);
 	}
 
 
 	ffs_wtfs(fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, &sbbuf,
 	    fsopts);
 
 					/* now write inode */
 	d = fsbtodb(fs, ino_to_fsba(fs, ino));
 	ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
 	if (fsopts->needswap) {
 		if (ffs_opts->version == 1)
 			ffs_dinode1_swap(&dp->ffs1_din,
 			    &dp1[ino_to_fsbo(fs, ino)]);
 		else
 			ffs_dinode2_swap(&dp->ffs2_din,
 			    &dp2[ino_to_fsbo(fs, ino)]);
 	} else {
 		if (ffs_opts->version == 1)
 			dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
 		else
 			dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;
 	}
 	ffs_wtfs(d, fs->fs_bsize, buf, fsopts);
 	free(buf);
 }
 
 void
 panic(const char *fmt, ...)
 {
 	va_list ap;
 
 	va_start(ap, fmt);
 	vwarnx(fmt, ap);
 	va_end(ap);
 	exit(1);
 }
diff --git a/usr.sbin/makefs/ffs/buf.c b/usr.sbin/makefs/ffs/buf.c
index 959734cacddf..ccbfd8ae1e23 100644
--- a/usr.sbin/makefs/ffs/buf.c
+++ b/usr.sbin/makefs/ffs/buf.c
@@ -1,216 +1,216 @@
 /*	$NetBSD: buf.c,v 1.13 2004/06/20 22:20:18 jmc Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (c) 2001 Wasabi Systems, Inc.
  * All rights reserved.
  *
  * Written by Luke Mewburn for Wasabi Systems, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *      This product includes software developed for the NetBSD Project by
  *      Wasabi Systems, Inc.
  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
  *    or promote products derived from this software without specific prior
  *    written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/time.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <util.h>
 
 #include "makefs.h"
 #include "buf.h"
 
-static TAILQ_HEAD(buftailhead,buf) buftail;
+static TAILQ_HEAD(buftailhead, m_buf) buftail;
 
 int
-bread(struct vnode *vp, daddr_t blkno, int size, struct ucred *u1 __unused,
-    struct buf **bpp)
+bread(struct m_vnode *vp, daddr_t blkno, int size, struct ucred *u1 __unused,
+    struct m_buf **bpp)
 {
 	off_t	offset;
 	ssize_t	rv;
 	fsinfo_t *fs = vp->fs;
 
 	assert (bpp != NULL);
 
 	if (debug & DEBUG_BUF_BREAD)
 		printf("%s: blkno %lld size %d\n", __func__, (long long)blkno,
 		    size);
 	*bpp = getblk(vp, blkno, size, 0, 0, 0);
 	offset = (*bpp)->b_blkno * fs->sectorsize + fs->offset;
 	if (debug & DEBUG_BUF_BREAD)
 		printf("%s: blkno %lld offset %lld bcount %ld\n", __func__,
 		    (long long)(*bpp)->b_blkno, (long long) offset,
 		    (*bpp)->b_bcount);
 	if (lseek((*bpp)->b_fs->fd, offset, SEEK_SET) == -1)
 		err(1, "%s: lseek %lld (%lld)", __func__,
 		    (long long)(*bpp)->b_blkno, (long long)offset);
 	rv = read((*bpp)->b_fs->fd, (*bpp)->b_data, (*bpp)->b_bcount);
 	if (debug & DEBUG_BUF_BREAD)
 		printf("%s: read %ld (%lld) returned %d\n", __func__,
 		    (*bpp)->b_bcount, (long long)offset, (int)rv);
 	if (rv == -1)				/* read error */
 		err(1, "%s: read %ld (%lld) returned %d", __func__,
 		    (*bpp)->b_bcount, (long long)offset, (int)rv);
 	else if (rv != (*bpp)->b_bcount)	/* short read */
 		err(1, "%s: read %ld (%lld) returned %d", __func__,
 		    (*bpp)->b_bcount, (long long)offset, (int)rv);
 	else
 		return (0);
 }
 
 void
-brelse(struct buf *bp)
+brelse(struct m_buf *bp)
 {
 
 	assert (bp != NULL);
 	assert (bp->b_data != NULL);
 
 	if (bp->b_lblkno < 0) {
 		/*
 		 * XXX	don't remove any buffers with negative logical block
 		 *	numbers (lblkno), so that we retain the mapping
 		 *	of negative lblkno -> real blkno that ffs_balloc()
 		 *	sets up.
 		 *
 		 *	if we instead released these buffers, and implemented
 		 *	ufs_strategy() (and ufs_bmaparray()) and called those
 		 *	from bread() and bwrite() to convert the lblkno to
 		 *	a real blkno, we'd add a lot more code & complexity
 		 *	and reading off disk, for little gain, because this
 		 *	simple hack works for our purpose.
 		 */
 		bp->b_bcount = 0;
 		return;
 	}
 
 	TAILQ_REMOVE(&buftail, bp, b_tailq);
 	free(bp->b_data);
 	free(bp);
 }
 
 int
-bwrite(struct buf *bp)
+bwrite(struct m_buf *bp)
 {
 	off_t	offset;
 	ssize_t	rv;
 	fsinfo_t *fs = bp->b_fs;
 
 	assert (bp != NULL);
 	offset = bp->b_blkno * fs->sectorsize + fs->offset;
 	if (debug & DEBUG_BUF_BWRITE)
 		printf("bwrite: blkno %lld offset %lld bcount %ld\n",
 		    (long long)bp->b_blkno, (long long) offset,
 		    bp->b_bcount);
 	if (lseek(bp->b_fs->fd, offset, SEEK_SET) == -1)
 		return (errno);
 	rv = write(bp->b_fs->fd, bp->b_data, bp->b_bcount);
 	if (debug & DEBUG_BUF_BWRITE)
 		printf("bwrite: write %ld (offset %lld) returned %lld\n",
 		    bp->b_bcount, (long long)offset, (long long)rv);
 	if (rv == bp->b_bcount)
 		return (0);
 	else if (rv == -1)		/* write error */
 		return (errno);
 	else				/* short write ? */
 		return (EAGAIN);
 }
 
 void
 bcleanup(void)
 {
-	struct buf *bp;
+	struct m_buf *bp;
 
 	/*
 	 * XXX	this really shouldn't be necessary, but i'm curious to
 	 *	know why there's still some buffers lying around that
 	 *	aren't brelse()d
 	 */
 
 	if (TAILQ_EMPTY(&buftail))
 		return;
 
 	printf("bcleanup: unflushed buffers:\n");
 	TAILQ_FOREACH(bp, &buftail, b_tailq) {
 		printf("\tlblkno %10lld  blkno %10lld  count %6ld  bufsize %6ld\n",
 		    (long long)bp->b_lblkno, (long long)bp->b_blkno,
 		    bp->b_bcount, bp->b_bufsize);
 	}
 	printf("bcleanup: done\n");
 }
 
-struct buf *
-getblk(struct vnode *vp, daddr_t blkno, int size, int u1 __unused,
+struct m_buf *
+getblk(struct m_vnode *vp, daddr_t blkno, int size, int u1 __unused,
     int u2 __unused, int u3 __unused)
 {
 	static int buftailinitted;
-	struct buf *bp;
+	struct m_buf *bp;
 	void *n;
 
 	if (debug & DEBUG_BUF_GETBLK)
 		printf("getblk: blkno %lld size %d\n", (long long)blkno, size);
 
 	bp = NULL;
 	if (!buftailinitted) {
 		if (debug & DEBUG_BUF_GETBLK)
 			printf("getblk: initialising tailq\n");
 		TAILQ_INIT(&buftail);
 		buftailinitted = 1;
 	} else {
 		TAILQ_FOREACH(bp, &buftail, b_tailq) {
 			if (bp->b_lblkno != blkno)
 				continue;
 			break;
 		}
 	}
 	if (bp == NULL) {
 		bp = ecalloc(1, sizeof(*bp));
 		bp->b_bufsize = 0;
 		bp->b_blkno = bp->b_lblkno = blkno;
 		bp->b_fs = vp->fs;
 		bp->b_data = NULL;
 		TAILQ_INSERT_HEAD(&buftail, bp, b_tailq);
 	}
 	bp->b_bcount = size;
 	if (bp->b_data == NULL || bp->b_bcount > bp->b_bufsize) {
 		n = erealloc(bp->b_data, size);
 		memset(n, 0, size);
 		bp->b_data = n;
 		bp->b_bufsize = size;
 	}
 
 	return (bp);
 }
diff --git a/usr.sbin/makefs/ffs/buf.h b/usr.sbin/makefs/ffs/buf.h
index 3bdd7ca2a9f1..31196b8b2fbe 100644
--- a/usr.sbin/makefs/ffs/buf.h
+++ b/usr.sbin/makefs/ffs/buf.h
@@ -1,78 +1,78 @@
 /*	$NetBSD: buf.h,v 1.3 2001/11/02 03:12:49 lukem Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (c) 2001 Wasabi Systems, Inc.
  * All rights reserved.
  *
  * Written by Luke Mewburn for Wasabi Systems, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *      This product includes software developed for the NetBSD Project by
  *      Wasabi Systems, Inc.
  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
  *    or promote products derived from this software without specific prior
  *    written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #ifndef _FFS_BUF_H
 #define	_FFS_BUF_H
 
 #include <sys/param.h>
 #include <sys/queue.h>
 
 struct componentname;
 struct makefs_fsinfo;
 struct ucred;
 
-struct vnode {
+struct m_vnode {
 	struct makefs_fsinfo *fs;
 	void *v_data;
 };
 
-struct buf {
+struct m_buf {
 	char *		b_data;
 	long		b_bufsize;
 	long		b_bcount;
 	daddr_t		b_blkno;
 	daddr_t		b_lblkno;
 	struct makefs_fsinfo *b_fs;
 
-	TAILQ_ENTRY(buf)	b_tailq;
+	TAILQ_ENTRY(m_buf)	b_tailq;
 };
 
 void		bcleanup(void);
-int		bread(struct vnode *, daddr_t, int, struct ucred *,
-    struct buf **);
-void		brelse(struct buf *);
-int		bwrite(struct buf *);
-struct buf *	getblk(struct vnode *, daddr_t, int, int, int, int);
+int		bread(struct m_vnode *, daddr_t, int, struct ucred *,
+    struct m_buf **);
+void		brelse(struct m_buf *);
+int		bwrite(struct m_buf *);
+struct m_buf *	getblk(struct m_vnode *, daddr_t, int, int, int, int);
 
 #define	bdwrite(bp)	bwrite(bp)
 #define	clrbuf(bp)	memset((bp)->b_data, 0, (u_int)(bp)->b_bcount)
 
 #endif	/* _FFS_BUF_H */
diff --git a/usr.sbin/makefs/ffs/ffs_alloc.c b/usr.sbin/makefs/ffs/ffs_alloc.c
index 88d95d6e5dda..c31106772b45 100644
--- a/usr.sbin/makefs/ffs/ffs_alloc.c
+++ b/usr.sbin/makefs/ffs/ffs_alloc.c
@@ -1,683 +1,683 @@
 /*	$NetBSD: ffs_alloc.c,v 1.14 2004/06/20 22:20:18 jmc Exp $	*/
 /* From: NetBSD: ffs_alloc.c,v 1.50 2001/09/06 02:16:01 lukem Exp */
 
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 2002 Networks Associates Technology, Inc.
  * All rights reserved.
  *
  * This software was developed for the FreeBSD Project by Marshall
  * Kirk McKusick and Network Associates Laboratories, the Security
  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
  * research program
  *
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)ffs_alloc.c	8.19 (Berkeley) 7/13/95
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/time.h>
 
 #include <errno.h>
 #include <stdint.h>
 
 #include "makefs.h"
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include "ffs/ufs_bswap.h"
 #include "ffs/buf.h"
 #include "ffs/ufs_inode.h"
 #include "ffs/ffs_extern.h"
 
 static int scanc(u_int, const u_char *, const u_char *, int);
 
 static daddr_t ffs_alloccg(struct inode *, int, daddr_t, int);
-static daddr_t ffs_alloccgblk(struct inode *, struct buf *, daddr_t);
+static daddr_t ffs_alloccgblk(struct inode *, struct m_buf *, daddr_t);
 static daddr_t ffs_hashalloc(struct inode *, u_int, daddr_t, int,
 		     daddr_t (*)(struct inode *, int, daddr_t, int));
 static int32_t ffs_mapsearch(struct fs *, struct cg *, daddr_t, int);
 
 /*
  * Allocate a block in the file system.
  * 
  * The size of the requested block is given, which must be some
  * multiple of fs_fsize and <= fs_bsize.
  * A preference may be optionally specified. If a preference is given
  * the following hierarchy is used to allocate a block:
  *   1) allocate the requested block.
  *   2) allocate a rotationally optimal block in the same cylinder.
  *   3) allocate a block in the same cylinder group.
  *   4) quadradically rehash into other cylinder groups, until an
  *      available block is located.
  * If no block preference is given the following hierarchy is used
  * to allocate a block:
  *   1) allocate a block in the cylinder group that contains the
  *      inode for the file.
  *   2) quadradically rehash into other cylinder groups, until an
  *      available block is located.
  */
 int
 ffs_alloc(struct inode *ip, daddr_t lbn __unused, daddr_t bpref, int size,
     daddr_t *bnp)
 {
 	struct fs *fs = ip->i_fs;
 	daddr_t bno;
 	int cg;
 	
 	*bnp = 0;
 	if (size > fs->fs_bsize || fragoff(fs, size) != 0) {
 		errx(1, "ffs_alloc: bad size: bsize %d size %d",
 		    fs->fs_bsize, size);
 	}
 	if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
 		goto nospace;
 	if (bpref >= fs->fs_size)
 		bpref = 0;
 	if (bpref == 0)
 		cg = ino_to_cg(fs, ip->i_number);
 	else
 		cg = dtog(fs, bpref);
 	bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg);
 	if (bno > 0) {
 		if (ip->i_fs->fs_magic == FS_UFS1_MAGIC)
 			ip->i_ffs1_blocks += size / DEV_BSIZE;
 		else
 			ip->i_ffs2_blocks += size / DEV_BSIZE;
 		*bnp = bno;
 		return (0);
 	}
 nospace:
 	return (ENOSPC);
 }
 
 /*
  * Select the desired position for the next block in a file.  The file is
  * logically divided into sections. The first section is composed of the
  * direct blocks. Each additional section contains fs_maxbpg blocks.
  * 
  * If no blocks have been allocated in the first section, the policy is to
  * request a block in the same cylinder group as the inode that describes
  * the file. If no blocks have been allocated in any other section, the
  * policy is to place the section in a cylinder group with a greater than
  * average number of free blocks.  An appropriate cylinder group is found
  * by using a rotor that sweeps the cylinder groups. When a new group of
  * blocks is needed, the sweep begins in the cylinder group following the
  * cylinder group from which the previous allocation was made. The sweep
  * continues until a cylinder group with greater than the average number
  * of free blocks is found. If the allocation is for the first block in an
  * indirect block, the information on the previous allocation is unavailable;
  * here a best guess is made based upon the logical block number being
  * allocated.
  * 
  * If a section is already partially allocated, the policy is to
  * contiguously allocate fs_maxcontig blocks.  The end of one of these
  * contiguous blocks and the beginning of the next is physically separated
  * so that the disk head will be in transit between them for at least
  * fs_rotdelay milliseconds.  This is to allow time for the processor to
  * schedule another I/O transfer.
  */
 /* XXX ondisk32 */
 daddr_t
 ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int32_t *bap)
 {
 	struct fs *fs;
 	u_int cg, startcg;
 	int avgbfree;
 
 	fs = ip->i_fs;
 	if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
 		if (lbn < UFS_NDADDR + NINDIR(fs)) {
 			cg = ino_to_cg(fs, ip->i_number);
 			return (fs->fs_fpg * cg + fs->fs_frag);
 		}
 		/*
 		 * Find a cylinder with greater than average number of
 		 * unused data blocks.
 		 */
 		if (indx == 0 || bap[indx - 1] == 0)
 			startcg =
 			    ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
 		else
 			startcg = dtog(fs,
 				ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
 		startcg %= fs->fs_ncg;
 		avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
 		for (cg = startcg; cg < fs->fs_ncg; cg++)
 			if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
 				return (fs->fs_fpg * cg + fs->fs_frag);
 		for (cg = 0; cg <= startcg; cg++)
 			if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree)
 				return (fs->fs_fpg * cg + fs->fs_frag);
 		return (0);
 	}
 	/*
 	 * We just always try to lay things out contiguously.
 	 */
 	return ufs_rw32(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
 }
 
 daddr_t
 ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int64_t *bap)
 {
 	struct fs *fs;
 	u_int cg, startcg;
 	int avgbfree;
 
 	fs = ip->i_fs;
 	if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
 		if (lbn < UFS_NDADDR + NINDIR(fs)) {
 			cg = ino_to_cg(fs, ip->i_number);
 			return (fs->fs_fpg * cg + fs->fs_frag);
 		}
 		/*
 		 * Find a cylinder with greater than average number of
 		 * unused data blocks.
 		 */
 		if (indx == 0 || bap[indx - 1] == 0)
 			startcg =
 			    ino_to_cg(fs, ip->i_number) + lbn / fs->fs_maxbpg;
 		else
 			startcg = dtog(fs,
 				ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + 1);
 		startcg %= fs->fs_ncg;
 		avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
 		for (cg = startcg; cg < fs->fs_ncg; cg++)
 			if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
 				return (fs->fs_fpg * cg + fs->fs_frag);
 			}
 		for (cg = 0; cg < startcg; cg++)
 			if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
 				return (fs->fs_fpg * cg + fs->fs_frag);
 			}
 		return (0);
 	}
 	/*
 	 * We just always try to lay things out contiguously.
 	 */
 	return ufs_rw64(bap[indx - 1], UFS_FSNEEDSWAP(fs)) + fs->fs_frag;
 }
 
 /*
  * Implement the cylinder overflow algorithm.
  *
  * The policy implemented by this algorithm is:
  *   1) allocate the block in its requested cylinder group.
  *   2) quadradically rehash on the cylinder group number.
  *   3) brute force search for a free block.
  *
  * `size':	size for data blocks, mode for inodes
  */
 /*VARARGS5*/
 static daddr_t
 ffs_hashalloc(struct inode *ip, u_int cg, daddr_t pref, int size,
     daddr_t (*allocator)(struct inode *, int, daddr_t, int))
 {
 	struct fs *fs;
 	daddr_t result;
 	u_int i, icg = cg;
 
 	fs = ip->i_fs;
 	/*
 	 * 1: preferred cylinder group
 	 */
 	result = (*allocator)(ip, cg, pref, size);
 	if (result)
 		return (result);
 	/*
 	 * 2: quadratic rehash
 	 */
 	for (i = 1; i < fs->fs_ncg; i *= 2) {
 		cg += i;
 		if (cg >= fs->fs_ncg)
 			cg -= fs->fs_ncg;
 		result = (*allocator)(ip, cg, 0, size);
 		if (result)
 			return (result);
 	}
 	/*
 	 * 3: brute force search
 	 * Note that we start at i == 2, since 0 was checked initially,
 	 * and 1 is always checked in the quadratic rehash.
 	 */
 	cg = (icg + 2) % fs->fs_ncg;
 	for (i = 2; i < fs->fs_ncg; i++) {
 		result = (*allocator)(ip, cg, 0, size);
 		if (result)
 			return (result);
 		cg++;
 		if (cg == fs->fs_ncg)
 			cg = 0;
 	}
 	return (0);
 }
 
 /*
  * Determine whether a block can be allocated.
  *
  * Check to see if a block of the appropriate size is available,
  * and if it is, allocate it.
  */
 static daddr_t
 ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
 {
 	struct cg *cgp;
-	struct buf *bp;
+	struct m_buf *bp;
 	daddr_t bno, blkno;
 	int error, frags, allocsiz, i;
 	struct fs *fs = ip->i_fs;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 
 	if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
 		return (0);
-	error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-	    NULL, &bp);
+	error = bread((void *)ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+	    (int)fs->fs_cgsize, NULL, &bp);
 	if (error) {
 		brelse(bp);
 		return (0);
 	}
 	cgp = (struct cg *)bp->b_data;
 	if (!cg_chkmagic_swap(cgp, needswap) ||
 	    (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
 		brelse(bp);
 		return (0);
 	}
 	if (size == fs->fs_bsize) {
 		bno = ffs_alloccgblk(ip, bp, bpref);
 		bdwrite(bp);
 		return (bno);
 	}
 	/*
 	 * check to see if any fragments are already available
 	 * allocsiz is the size which will be allocated, hacking
 	 * it down to a smaller size if necessary
 	 */
 	frags = numfrags(fs, size);
 	for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++)
 		if (cgp->cg_frsum[allocsiz] != 0)
 			break;
 	if (allocsiz == fs->fs_frag) {
 		/*
 		 * no fragments were available, so a block will be 
 		 * allocated, and hacked up
 		 */
 		if (cgp->cg_cs.cs_nbfree == 0) {
 			brelse(bp);
 			return (0);
 		}
 		bno = ffs_alloccgblk(ip, bp, bpref);
 		bpref = dtogd(fs, bno);
 		for (i = frags; i < fs->fs_frag; i++)
 			setbit(cg_blksfree_swap(cgp, needswap), bpref + i);
 		i = fs->fs_frag - frags;
 		ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
 		fs->fs_cstotal.cs_nffree += i;
 		fs->fs_cs(fs, cg).cs_nffree += i;
 		fs->fs_fmod = 1;
 		ufs_add32(cgp->cg_frsum[i], 1, needswap);
 		bdwrite(bp);
 		return (bno);
 	}
 	bno = ffs_mapsearch(fs, cgp, bpref, allocsiz);
 	for (i = 0; i < frags; i++)
 		clrbit(cg_blksfree_swap(cgp, needswap), bno + i);
 	ufs_add32(cgp->cg_cs.cs_nffree, -frags, needswap);
 	fs->fs_cstotal.cs_nffree -= frags;
 	fs->fs_cs(fs, cg).cs_nffree -= frags;
 	fs->fs_fmod = 1;
 	ufs_add32(cgp->cg_frsum[allocsiz], -1, needswap);
 	if (frags != allocsiz)
 		ufs_add32(cgp->cg_frsum[allocsiz - frags], 1, needswap);
 	blkno = cg * fs->fs_fpg + bno;
 	bdwrite(bp);
 	return blkno;
 }
 
 /*
  * Allocate a block in a cylinder group.
  *
  * This algorithm implements the following policy:
  *   1) allocate the requested block.
  *   2) allocate a rotationally optimal block in the same cylinder.
  *   3) allocate the next available block on the block rotor for the
  *      specified cylinder group.
  * Note that this routine only allocates fs_bsize blocks; these
  * blocks may be fragmented by the routine that allocates them.
  */
 static daddr_t
-ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
+ffs_alloccgblk(struct inode *ip, struct m_buf *bp, daddr_t bpref)
 {
 	struct cg *cgp;
 	daddr_t blkno;
 	int32_t bno;
 	struct fs *fs = ip->i_fs;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 	u_int8_t *blksfree_swap;
 
 	cgp = (struct cg *)bp->b_data;
 	blksfree_swap = cg_blksfree_swap(cgp, needswap);
 	if (bpref == 0 || (uint32_t)dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
 		bpref = ufs_rw32(cgp->cg_rotor, needswap);
 	} else {
 		bpref = blknum(fs, bpref);
 		bno = dtogd(fs, bpref);
 		/*
 		 * if the requested block is available, use it
 		 */
 		if (ffs_isblock(fs, blksfree_swap, fragstoblks(fs, bno)))
 			goto gotit;
 	}
 	/*
 	 * Take the next available one in this cylinder group.
 	 */
 	bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag);
 	if (bno < 0)
 		return (0);
 	cgp->cg_rotor = ufs_rw32(bno, needswap);
 gotit:
 	blkno = fragstoblks(fs, bno);
 	ffs_clrblock(fs, blksfree_swap, (long)blkno);
 	ffs_clusteracct(fs, cgp, blkno, -1);
 	ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap);
 	fs->fs_cstotal.cs_nbfree--;
 	fs->fs_cs(fs, ufs_rw32(cgp->cg_cgx, needswap)).cs_nbfree--;
 	fs->fs_fmod = 1;
 	blkno = ufs_rw32(cgp->cg_cgx, needswap) * fs->fs_fpg + bno;
 	return (blkno);
 }
 
 /*
  * Free a block or fragment.
  *
  * The specified block or fragment is placed back in the
  * free map. If a fragment is deallocated, a possible 
  * block reassembly is checked.
  */
 void
 ffs_blkfree(struct inode *ip, daddr_t bno, long size)
 {
 	struct cg *cgp;
-	struct buf *bp;
+	struct m_buf *bp;
 	int32_t fragno, cgbno;
 	int i, error, cg, blk, frags, bbase;
 	struct fs *fs = ip->i_fs;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 
 	if (size > fs->fs_bsize || fragoff(fs, size) != 0 ||
 	    fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
 		errx(1, "blkfree: bad size: bno %lld bsize %d size %ld",
 		    (long long)bno, fs->fs_bsize, size);
 	}
 	cg = dtog(fs, bno);
 	if (bno >= fs->fs_size) {
 		warnx("bad block %lld, ino %ju", (long long)bno,
 		    (uintmax_t)ip->i_number);
 		return;
 	}
-	error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-	    NULL, &bp);
+	error = bread((void *)ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+	    (int)fs->fs_cgsize, NULL, &bp);
 	if (error) {
 		brelse(bp);
 		return;
 	}
 	cgp = (struct cg *)bp->b_data;
 	if (!cg_chkmagic_swap(cgp, needswap)) {
 		brelse(bp);
 		return;
 	}
 	cgbno = dtogd(fs, bno);
 	if (size == fs->fs_bsize) {
 		fragno = fragstoblks(fs, cgbno);
 		if (!ffs_isfreeblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) {
 			errx(1, "blkfree: freeing free block %lld",
 			    (long long)bno);
 		}
 		ffs_setblock(fs, cg_blksfree_swap(cgp, needswap), fragno);
 		ffs_clusteracct(fs, cgp, fragno, 1);
 		ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
 		fs->fs_cstotal.cs_nbfree++;
 		fs->fs_cs(fs, cg).cs_nbfree++;
 	} else {
 		bbase = cgbno - fragnum(fs, cgbno);
 		/*
 		 * decrement the counts associated with the old frags
 		 */
 		blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bbase);
 		ffs_fragacct_swap(fs, blk, cgp->cg_frsum, -1, needswap);
 		/*
 		 * deallocate the fragment
 		 */
 		frags = numfrags(fs, size);
 		for (i = 0; i < frags; i++) {
 			if (isset(cg_blksfree_swap(cgp, needswap), cgbno + i)) {
 				errx(1, "blkfree: freeing free frag: block %lld",
 				    (long long)(cgbno + i));
 			}
 			setbit(cg_blksfree_swap(cgp, needswap), cgbno + i);
 		}
 		ufs_add32(cgp->cg_cs.cs_nffree, i, needswap);
 		fs->fs_cstotal.cs_nffree += i;
 		fs->fs_cs(fs, cg).cs_nffree += i;
 		/*
 		 * add back in counts associated with the new frags
 		 */
 		blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bbase);
 		ffs_fragacct_swap(fs, blk, cgp->cg_frsum, 1, needswap);
 		/*
 		 * if a complete block has been reassembled, account for it
 		 */
 		fragno = fragstoblks(fs, bbase);
 		if (ffs_isblock(fs, cg_blksfree_swap(cgp, needswap), fragno)) {
 			ufs_add32(cgp->cg_cs.cs_nffree, -fs->fs_frag, needswap);
 			fs->fs_cstotal.cs_nffree -= fs->fs_frag;
 			fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
 			ffs_clusteracct(fs, cgp, fragno, 1);
 			ufs_add32(cgp->cg_cs.cs_nbfree, 1, needswap);
 			fs->fs_cstotal.cs_nbfree++;
 			fs->fs_cs(fs, cg).cs_nbfree++;
 		}
 	}
 	fs->fs_fmod = 1;
 	bdwrite(bp);
 }
 
 
 static int
 scanc(u_int size, const u_char *cp, const u_char table[], int mask)
 {
 	const u_char *end = &cp[size];
 
 	while (cp < end && (table[*cp] & mask) == 0)
 		cp++;
 	return (end - cp);
 }
 
 /*
  * Find a block of the specified size in the specified cylinder group.
  *
  * It is a panic if a request is made to find a block if none are
  * available.
  */
 static int32_t
 ffs_mapsearch(struct fs *fs, struct cg *cgp, daddr_t bpref, int allocsiz)
 {
 	int32_t bno;
 	int start, len, loc, i;
 	int blk, field, subfield, pos;
 	int ostart, olen;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 
 	/*
 	 * find the fragment by searching through the free block
 	 * map for an appropriate bit pattern
 	 */
 	if (bpref)
 		start = dtogd(fs, bpref) / NBBY;
 	else
 		start = ufs_rw32(cgp->cg_frotor, needswap) / NBBY;
 	len = howmany(fs->fs_fpg, NBBY) - start;
 	ostart = start;
 	olen = len;
 	loc = scanc((u_int)len,
 		(const u_char *)&cg_blksfree_swap(cgp, needswap)[start],
 		(const u_char *)fragtbl[fs->fs_frag],
 		(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
 	if (loc == 0) {
 		len = start + 1;
 		start = 0;
 		loc = scanc((u_int)len,
 			(const u_char *)&cg_blksfree_swap(cgp, needswap)[0],
 			(const u_char *)fragtbl[fs->fs_frag],
 			(1 << (allocsiz - 1 + (fs->fs_frag % NBBY))));
 		if (loc == 0) {
 			errx(1,
     "ffs_alloccg: map corrupted: start %d len %d offset %d %ld",
 				ostart, olen,
 				ufs_rw32(cgp->cg_freeoff, needswap),
 				(long)cg_blksfree_swap(cgp, needswap) - (long)cgp);
 			/* NOTREACHED */
 		}
 	}
 	bno = (start + len - loc) * NBBY;
 	cgp->cg_frotor = ufs_rw32(bno, needswap);
 	/*
 	 * found the byte in the map
 	 * sift through the bits to find the selected frag
 	 */
 	for (i = bno + NBBY; bno < i; bno += fs->fs_frag) {
 		blk = blkmap(fs, cg_blksfree_swap(cgp, needswap), bno);
 		blk <<= 1;
 		field = around[allocsiz];
 		subfield = inside[allocsiz];
 		for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) {
 			if ((blk & field) == subfield)
 				return (bno + pos);
 			field <<= 1;
 			subfield <<= 1;
 		}
 	}
 	errx(1, "ffs_alloccg: block not in map: bno %lld", (long long)bno);
 	return (-1);
 }
 
 /*
  * Update the cluster map because of an allocation or free.
  *
  * Cnt == 1 means free; cnt == -1 means allocating.
  */
 void
 ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt)
 {
 	int32_t *sump;
 	int32_t *lp;
 	u_char *freemapp, *mapp;
 	int i, start, end, forw, back, map, bit;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 
 	if (fs->fs_contigsumsize <= 0)
 		return;
 	freemapp = cg_clustersfree_swap(cgp, needswap);
 	sump = cg_clustersum_swap(cgp, needswap);
 	/*
 	 * Allocate or clear the actual block.
 	 */
 	if (cnt > 0)
 		setbit(freemapp, blkno);
 	else
 		clrbit(freemapp, blkno);
 	/*
 	 * Find the size of the cluster going forward.
 	 */
 	start = blkno + 1;
 	end = start + fs->fs_contigsumsize;
 	if ((unsigned)end >= ufs_rw32(cgp->cg_nclusterblks, needswap))
 		end = ufs_rw32(cgp->cg_nclusterblks, needswap);
 	mapp = &freemapp[start / NBBY];
 	map = *mapp++;
 	bit = 1 << (start % NBBY);
 	for (i = start; i < end; i++) {
 		if ((map & bit) == 0)
 			break;
 		if ((i & (NBBY - 1)) != (NBBY - 1)) {
 			bit <<= 1;
 		} else {
 			map = *mapp++;
 			bit = 1;
 		}
 	}
 	forw = i - start;
 	/*
 	 * Find the size of the cluster going backward.
 	 */
 	start = blkno - 1;
 	end = start - fs->fs_contigsumsize;
 	if (end < 0)
 		end = -1;
 	mapp = &freemapp[start / NBBY];
 	map = *mapp--;
 	bit = 1 << (start % NBBY);
 	for (i = start; i > end; i--) {
 		if ((map & bit) == 0)
 			break;
 		if ((i & (NBBY - 1)) != 0) {
 			bit >>= 1;
 		} else {
 			map = *mapp--;
 			bit = 1 << (NBBY - 1);
 		}
 	}
 	back = start - i;
 	/*
 	 * Account for old cluster and the possibly new forward and
 	 * back clusters.
 	 */
 	i = back + forw + 1;
 	if (i > fs->fs_contigsumsize)
 		i = fs->fs_contigsumsize;
 	ufs_add32(sump[i], cnt, needswap);
 	if (back > 0)
 		ufs_add32(sump[back], -cnt, needswap);
 	if (forw > 0)
 		ufs_add32(sump[forw], -cnt, needswap);
 
 	/*
 	 * Update cluster summary information.
 	 */
 	lp = &sump[fs->fs_contigsumsize];
 	for (i = fs->fs_contigsumsize; i > 0; i--)
 		if (ufs_rw32(*lp--, needswap) > 0)
 			break;
 	fs->fs_maxcluster[ufs_rw32(cgp->cg_cgx, needswap)] = i;
 }
diff --git a/usr.sbin/makefs/ffs/ffs_balloc.c b/usr.sbin/makefs/ffs/ffs_balloc.c
index d56ed061457b..275ec4c04471 100644
--- a/usr.sbin/makefs/ffs/ffs_balloc.c
+++ b/usr.sbin/makefs/ffs/ffs_balloc.c
@@ -1,580 +1,592 @@
 /*	$NetBSD: ffs_balloc.c,v 1.13 2004/06/20 22:20:18 jmc Exp $	*/
 /* From NetBSD: ffs_balloc.c,v 1.25 2001/08/08 08:36:36 lukem Exp */
 
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)ffs_balloc.c	8.8 (Berkeley) 6/16/95
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/time.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "makefs.h"
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
 
 #include "ffs/ufs_bswap.h"
 #include "ffs/buf.h"
 #include "ffs/ufs_inode.h"
 #include "ffs/ffs_extern.h"
 
-static int ffs_balloc_ufs1(struct inode *, off_t, int, struct buf **);
-static int ffs_balloc_ufs2(struct inode *, off_t, int, struct buf **);
+static int ffs_balloc_ufs1(struct inode *, off_t, int, struct m_buf **);
+static int ffs_balloc_ufs2(struct inode *, off_t, int, struct m_buf **);
 
 /*
  * Balloc defines the structure of file system storage
  * by allocating the physical blocks on a device given
  * the inode and the logical block number in a file.
  *
  * Assume: flags == B_SYNC | B_CLRBUF
  */
 
 int
-ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
+ffs_balloc(struct inode *ip, off_t offset, int bufsize, struct m_buf **bpp)
 {
 	if (ip->i_fs->fs_magic == FS_UFS2_MAGIC)
 		return ffs_balloc_ufs2(ip, offset, bufsize, bpp);
 	else
 		return ffs_balloc_ufs1(ip, offset, bufsize, bpp);
 }
 
 static int
-ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
+ffs_balloc_ufs1(struct inode *ip, off_t offset, int bufsize,
+    struct m_buf **bpp)
 {
 	daddr_t lbn, lastlbn;
 	int size;
 	int32_t nb;
-	struct buf *bp, *nbp;
+	struct m_buf *bp, *nbp;
 	struct fs *fs = ip->i_fs;
 	struct indir indirs[UFS_NIADDR + 2];
 	daddr_t newb, pref;
 	int32_t *bap;
 	int osize, nsize, num, i, error;
 	int32_t *allocblk, allociblk[UFS_NIADDR + 1];
 	int32_t *allocib;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 
 	lbn = lblkno(fs, offset);
 	size = blkoff(fs, offset) + bufsize;
 	if (bpp != NULL) {
 		*bpp = NULL;
 	}
 
 	assert(size <= fs->fs_bsize);
 	if (lbn < 0)
 		return (EFBIG);
 
 	/*
 	 * If the next write will extend the file into a new block,
 	 * and the file is currently composed of a fragment
 	 * this fragment has to be extended to be a full block.
 	 */
 
 	lastlbn = lblkno(fs, ip->i_ffs1_size);
 	if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
 		nb = lastlbn;
 		osize = blksize(fs, ip, nb);
 		if (osize < fs->fs_bsize && osize > 0) {
 			warnx("need to ffs_realloccg; not supported!");
 			abort();
 		}
 	}
 
 	/*
 	 * The first UFS_NDADDR blocks are direct blocks
 	 */
 
 	if (lbn < UFS_NDADDR) {
 		nb = ufs_rw32(ip->i_ffs1_db[lbn], needswap);
 		if (nb != 0 && ip->i_ffs1_size >=
 		    (uint64_t)lblktosize(fs, lbn + 1)) {
 
 			/*
 			 * The block is an already-allocated direct block
 			 * and the file already extends past this block,
 			 * thus this must be a whole block.
 			 * Just read the block (if requested).
 			 */
 
 			if (bpp != NULL) {
-				error = bread(ip->i_devvp, lbn, fs->fs_bsize,
-				    NULL, bpp);
+				error = bread((void *)ip->i_devvp, lbn,
+				    fs->fs_bsize, NULL, bpp);
 				if (error) {
 					brelse(*bpp);
 					return (error);
 				}
 			}
 			return (0);
 		}
 		if (nb != 0) {
 
 			/*
 			 * Consider need to reallocate a fragment.
 			 */
 
 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size));
 			nsize = fragroundup(fs, size);
 			if (nsize <= osize) {
 
 				/*
 				 * The existing block is already
 				 * at least as big as we want.
 				 * Just read the block (if requested).
 				 */
 
 				if (bpp != NULL) {
-					error = bread(ip->i_devvp, lbn, osize,
-					    NULL, bpp);
+					error = bread((void *)ip->i_devvp, lbn,
+					    osize, NULL, bpp);
 					if (error) {
 						brelse(*bpp);
 						return (error);
 					}
 				}
 				return 0;
 			} else {
 				warnx("need to ffs_realloccg; not supported!");
 				abort();
 			}
 		} else {
 
 			/*
 			 * the block was not previously allocated,
 			 * allocate a new block or fragment.
 			 */
 
 			if (ip->i_ffs1_size < (uint64_t)lblktosize(fs, lbn + 1))
 				nsize = fragroundup(fs, size);
 			else
 				nsize = fs->fs_bsize;
 			error = ffs_alloc(ip, lbn,
 			    ffs_blkpref_ufs1(ip, lbn, (int)lbn,
 				&ip->i_ffs1_db[0]),
 				nsize, &newb);
 			if (error)
 				return (error);
 			if (bpp != NULL) {
-				bp = getblk(ip->i_devvp, lbn, nsize, 0, 0, 0);
+				bp = getblk((void *)ip->i_devvp, lbn, nsize,
+				    0, 0, 0);
 				bp->b_blkno = fsbtodb(fs, newb);
 				clrbuf(bp);
 				*bpp = bp;
 			}
 		}
 		ip->i_ffs1_db[lbn] = ufs_rw32((int32_t)newb, needswap);
 		return (0);
 	}
 
 	/*
 	 * Determine the number of levels of indirection.
 	 */
 
 	pref = 0;
 	if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
 		return (error);
 
 	if (num < 1) {
 		warnx("ffs_balloc: ufs_getlbns returned indirect block");
 		abort();
 	}
 
 	/*
 	 * Fetch the first indirect block allocating if necessary.
 	 */
 
 	--num;
 	nb = ufs_rw32(ip->i_ffs1_ib[indirs[0].in_off], needswap);
 	allocib = NULL;
 	allocblk = allociblk;
 	if (nb == 0) {
 		pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
 		if (error)
 			return error;
 		nb = newb;
 		*allocblk++ = nb;
-		bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
+		bp = getblk((void *)ip->i_devvp, indirs[1].in_lbn,
+		    fs->fs_bsize, 0, 0, 0);
 		bp->b_blkno = fsbtodb(fs, nb);
 		clrbuf(bp);
 		/*
 		 * Write synchronously so that indirect blocks
 		 * never point at garbage.
 		 */
 		if ((error = bwrite(bp)) != 0)
 			return error;
 		allocib = &ip->i_ffs1_ib[indirs[0].in_off];
 		*allocib = ufs_rw32((int32_t)nb, needswap);
 	}
 
 	/*
 	 * Fetch through the indirect blocks, allocating as necessary.
 	 */
 
 	for (i = 1;;) {
-		error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
-		    NULL, &bp);
+		error = bread((void *)ip->i_devvp, indirs[i].in_lbn,
+		    fs->fs_bsize, NULL, &bp);
 		if (error) {
 			brelse(bp);
 			return error;
 		}
 		bap = (int32_t *)bp->b_data;
 		nb = ufs_rw32(bap[indirs[i].in_off], needswap);
 		if (i == num)
 			break;
 		i++;
 		if (nb != 0) {
 			brelse(bp);
 			continue;
 		}
 		if (pref == 0)
 			pref = ffs_blkpref_ufs1(ip, lbn, 0, (int32_t *)0);
 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
 		if (error) {
 			brelse(bp);
 			return error;
 		}
 		nb = newb;
 		*allocblk++ = nb;
-		nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
+		nbp = getblk((void *)ip->i_devvp, indirs[i].in_lbn,
+		    fs->fs_bsize, 0, 0, 0);
 		nbp->b_blkno = fsbtodb(fs, nb);
 		clrbuf(nbp);
 		/*
 		 * Write synchronously so that indirect blocks
 		 * never point at garbage.
 		 */
 
 		if ((error = bwrite(nbp)) != 0) {
 			brelse(bp);
 			return error;
 		}
 		bap[indirs[i - 1].in_off] = ufs_rw32(nb, needswap);
 
 		bwrite(bp);
 	}
 
 	/*
 	 * Get the data block, allocating if necessary.
 	 */
 
 	if (nb == 0) {
 		pref = ffs_blkpref_ufs1(ip, lbn, indirs[num].in_off, &bap[0]);
 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
 		if (error) {
 			brelse(bp);
 			return error;
 		}
 		nb = newb;
 		*allocblk++ = nb;
 		if (bpp != NULL) {
-			nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0, 0);
+			nbp = getblk((void *)ip->i_devvp, lbn, fs->fs_bsize,
+			    0, 0, 0);
 			nbp->b_blkno = fsbtodb(fs, nb);
 			clrbuf(nbp);
 			*bpp = nbp;
 		}
 		bap[indirs[num].in_off] = ufs_rw32(nb, needswap);
 
 		/*
 		 * If required, write synchronously, otherwise use
 		 * delayed write.
 		 */
 		bwrite(bp);
 		return (0);
 	}
 	brelse(bp);
 	if (bpp != NULL) {
-		error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, NULL, &nbp);
+		error = bread((void *)ip->i_devvp, lbn, (int)fs->fs_bsize,
+		    NULL, &nbp);
 		if (error) {
 			brelse(nbp);
 			return error;
 		}
 		*bpp = nbp;
 	}
 	return (0);
 }
 
 static int
-ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize, struct buf **bpp)
+ffs_balloc_ufs2(struct inode *ip, off_t offset, int bufsize,
+    struct m_buf **bpp)
 {
 	daddr_t lbn, lastlbn;
 	int size;
-	struct buf *bp, *nbp;
+	struct m_buf *bp, *nbp;
 	struct fs *fs = ip->i_fs;
 	struct indir indirs[UFS_NIADDR + 2];
 	daddr_t newb, pref, nb;
 	int64_t *bap;
 	int osize, nsize, num, i, error;
 	int64_t *allocblk, allociblk[UFS_NIADDR + 1];
 	int64_t *allocib;
 	const int needswap = UFS_FSNEEDSWAP(fs);
 
 	lbn = lblkno(fs, offset);
 	size = blkoff(fs, offset) + bufsize;
 	if (bpp != NULL) {
 		*bpp = NULL;
 	}
 
 	assert(size <= fs->fs_bsize);
 	if (lbn < 0)
 		return (EFBIG);
 
 	/*
 	 * If the next write will extend the file into a new block,
 	 * and the file is currently composed of a fragment
 	 * this fragment has to be extended to be a full block.
 	 */
 
 	lastlbn = lblkno(fs, ip->i_ffs2_size);
 	if (lastlbn < UFS_NDADDR && lastlbn < lbn) {
 		nb = lastlbn;
 		osize = blksize(fs, ip, nb);
 		if (osize < fs->fs_bsize && osize > 0) {
 			warnx("need to ffs_realloccg; not supported!");
 			abort();
 		}
 	}
 
 	/*
 	 * The first UFS_NDADDR blocks are direct blocks
 	 */
 
 	if (lbn < UFS_NDADDR) {
 		nb = ufs_rw64(ip->i_ffs2_db[lbn], needswap);
 		if (nb != 0 && ip->i_ffs2_size >=
 		    (uint64_t)lblktosize(fs, lbn + 1)) {
 
 			/*
 			 * The block is an already-allocated direct block
 			 * and the file already extends past this block,
 			 * thus this must be a whole block.
 			 * Just read the block (if requested).
 			 */
 
 			if (bpp != NULL) {
-				error = bread(ip->i_devvp, lbn, fs->fs_bsize,
-				    NULL, bpp);
+				error = bread((void *)ip->i_devvp, lbn,
+				    fs->fs_bsize, NULL, bpp);
 				if (error) {
 					brelse(*bpp);
 					return (error);
 				}
 			}
 			return (0);
 		}
 		if (nb != 0) {
 
 			/*
 			 * Consider need to reallocate a fragment.
 			 */
 
 			osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size));
 			nsize = fragroundup(fs, size);
 			if (nsize <= osize) {
 
 				/*
 				 * The existing block is already
 				 * at least as big as we want.
 				 * Just read the block (if requested).
 				 */
 
 				if (bpp != NULL) {
-					error = bread(ip->i_devvp, lbn, osize,
-					    NULL, bpp);
+					error = bread((void *)ip->i_devvp, lbn,
+					    osize, NULL, bpp);
 					if (error) {
 						brelse(*bpp);
 						return (error);
 					}
 				}
 				return 0;
 			} else {
 				warnx("need to ffs_realloccg; not supported!");
 				abort();
 			}
 		} else {
 
 			/*
 			 * the block was not previously allocated,
 			 * allocate a new block or fragment.
 			 */
 
 			if (ip->i_ffs2_size < (uint64_t)lblktosize(fs, lbn + 1))
 				nsize = fragroundup(fs, size);
 			else
 				nsize = fs->fs_bsize;
 			error = ffs_alloc(ip, lbn,
 			    ffs_blkpref_ufs2(ip, lbn, (int)lbn,
 				&ip->i_ffs2_db[0]),
 				nsize, &newb);
 			if (error)
 				return (error);
 			if (bpp != NULL) {
-				bp = getblk(ip->i_devvp, lbn, nsize, 0, 0, 0);
+				bp = getblk((void *)ip->i_devvp, lbn, nsize,
+				    0, 0, 0);
 				bp->b_blkno = fsbtodb(fs, newb);
 				clrbuf(bp);
 				*bpp = bp;
 			}
 		}
 		ip->i_ffs2_db[lbn] = ufs_rw64(newb, needswap);
 		return (0);
 	}
 
 	/*
 	 * Determine the number of levels of indirection.
 	 */
 
 	pref = 0;
 	if ((error = ufs_getlbns(ip, lbn, indirs, &num)) != 0)
 		return (error);
 
 	if (num < 1) {
 		warnx("ffs_balloc: ufs_getlbns returned indirect block");
 		abort();
 	}
 
 	/*
 	 * Fetch the first indirect block allocating if necessary.
 	 */
 
 	--num;
 	nb = ufs_rw64(ip->i_ffs2_ib[indirs[0].in_off], needswap);
 	allocib = NULL;
 	allocblk = allociblk;
 	if (nb == 0) {
 		pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
 		if (error)
 			return error;
 		nb = newb;
 		*allocblk++ = nb;
-		bp = getblk(ip->i_devvp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0);
+		bp = getblk((void *)ip->i_devvp, indirs[1].in_lbn,
+		    fs->fs_bsize, 0, 0, 0);
 		bp->b_blkno = fsbtodb(fs, nb);
 		clrbuf(bp);
 		/*
 		 * Write synchronously so that indirect blocks
 		 * never point at garbage.
 		 */
 		if ((error = bwrite(bp)) != 0)
 			return error;
 		allocib = &ip->i_ffs2_ib[indirs[0].in_off];
 		*allocib = ufs_rw64(nb, needswap);
 	}
 
 	/*
 	 * Fetch through the indirect blocks, allocating as necessary.
 	 */
 
 	for (i = 1;;) {
-		error = bread(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize,
-		    NULL, &bp);
+		error = bread((void *)ip->i_devvp, indirs[i].in_lbn,
+		    fs->fs_bsize, NULL, &bp);
 		if (error) {
 			brelse(bp);
 			return error;
 		}
 		bap = (int64_t *)bp->b_data;
 		nb = ufs_rw64(bap[indirs[i].in_off], needswap);
 		if (i == num)
 			break;
 		i++;
 		if (nb != 0) {
 			brelse(bp);
 			continue;
 		}
 		if (pref == 0)
 			pref = ffs_blkpref_ufs2(ip, lbn, 0, (int64_t *)0);
 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
 		if (error) {
 			brelse(bp);
 			return error;
 		}
 		nb = newb;
 		*allocblk++ = nb;
-		nbp = getblk(ip->i_devvp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0);
+		nbp = getblk((void *)ip->i_devvp, indirs[i].in_lbn,
+		    fs->fs_bsize, 0, 0, 0);
 		nbp->b_blkno = fsbtodb(fs, nb);
 		clrbuf(nbp);
 		/*
 		 * Write synchronously so that indirect blocks
 		 * never point at garbage.
 		 */
 
 		if ((error = bwrite(nbp)) != 0) {
 			brelse(bp);
 			return error;
 		}
 		bap[indirs[i - 1].in_off] = ufs_rw64(nb, needswap);
 
 		bwrite(bp);
 	}
 
 	/*
 	 * Get the data block, allocating if necessary.
 	 */
 
 	if (nb == 0) {
 		pref = ffs_blkpref_ufs2(ip, lbn, indirs[num].in_off, &bap[0]);
 		error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, &newb);
 		if (error) {
 			brelse(bp);
 			return error;
 		}
 		nb = newb;
 		*allocblk++ = nb;
 		if (bpp != NULL) {
-			nbp = getblk(ip->i_devvp, lbn, fs->fs_bsize, 0, 0, 0);
+			nbp = getblk((void *)ip->i_devvp, lbn, fs->fs_bsize,
+			    0, 0, 0);
 			nbp->b_blkno = fsbtodb(fs, nb);
 			clrbuf(nbp);
 			*bpp = nbp;
 		}
 		bap[indirs[num].in_off] = ufs_rw64(nb, needswap);
 
 		/*
 		 * If required, write synchronously, otherwise use
 		 * delayed write.
 		 */
 		bwrite(bp);
 		return (0);
 	}
 	brelse(bp);
 	if (bpp != NULL) {
-		error = bread(ip->i_devvp, lbn, (int)fs->fs_bsize, NULL, &nbp);
+		error = bread((void *)ip->i_devvp, lbn, (int)fs->fs_bsize,
+		    NULL, &nbp);
 		if (error) {
 			brelse(nbp);
 			return error;
 		}
 		*bpp = nbp;
 	}
 	return (0);
 }
diff --git a/usr.sbin/makefs/ffs/ffs_extern.h b/usr.sbin/makefs/ffs/ffs_extern.h
index b4d4bbaef6e9..12ba0b77989c 100644
--- a/usr.sbin/makefs/ffs/ffs_extern.h
+++ b/usr.sbin/makefs/ffs/ffs_extern.h
@@ -1,79 +1,79 @@
 /*	$NetBSD: ffs_extern.h,v 1.6 2003/08/07 11:25:33 agc Exp $	*/
 /* From: NetBSD: ffs_extern.h,v 1.19 2001/08/17 02:18:48 lukem Exp */
 
 /*-
  * SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (c) 1991, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  *	@(#)ffs_extern.h	8.6 (Berkeley) 3/30/95
  * $FreeBSD$
  */
 
 #include "ffs/buf.h"
 
 struct inode;
 
 /*
  * Structure used to pass around logical block paths generated by
  * ufs_getlbns and used by truncate and bmap code.
  */
 struct indir {
 	daddr_t in_lbn;		/* Logical block number. */
 	int	in_off;			/* Offset in buffer. */
 };
 
 	/* ffs.c */
 _Noreturn void panic(const char *, ...) __printflike(1, 2);
 
 	/* ffs_alloc.c */
 int ffs_alloc(struct inode *, daddr_t, daddr_t, int, daddr_t *);
 daddr_t ffs_blkpref_ufs1(struct inode *, daddr_t, int, int32_t *);
 daddr_t ffs_blkpref_ufs2(struct inode *, daddr_t, int, int64_t *);
 void ffs_blkfree(struct inode *, daddr_t, long);
 void ffs_clusteracct(struct fs *, struct cg *, int32_t, int);
 
 	/* ffs_balloc.c */
-int ffs_balloc(struct inode *, off_t, int, struct buf **);
+int ffs_balloc(struct inode *, off_t, int, struct m_buf **);
 
 	/* ffs_bswap.c */
 void ffs_sb_swap(struct fs*, struct fs *);
 void ffs_dinode1_swap(struct ufs1_dinode *, struct ufs1_dinode *);
 void ffs_dinode2_swap(struct ufs2_dinode *, struct ufs2_dinode *);
 void ffs_csum_swap(struct csum *, struct csum *, int);
 void ffs_cg_swap(struct cg *, struct cg *, struct fs *);
 
 	/* ffs_subr.c */
 void ffs_fragacct(struct fs *, int, int32_t[], int, int);
 int ffs_isblock(struct fs *, u_char *, int32_t);
 int ffs_isfreeblock(struct fs *, u_char *, int32_t);
 void ffs_clrblock(struct fs *, u_char *, int32_t);
 void ffs_setblock(struct fs *, u_char *, int32_t);
 
 	/* ufs_bmap.c */
 int ufs_getlbns(struct inode *, daddr_t, struct indir *, int *);
diff --git a/usr.sbin/makefs/msdos.c b/usr.sbin/makefs/msdos.c
index a0e0f7174f25..567122c1db7e 100644
--- a/usr.sbin/makefs/msdos.c
+++ b/usr.sbin/makefs/msdos.c
@@ -1,272 +1,273 @@
 /*	$NetBSD: msdos.c,v 1.20 2017/04/14 15:40:35 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Christos Zoulas.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #if HAVE_NBTOOL_CONFIG_H
 #include "nbtool_config.h"
 #endif
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(__lint)
 __FBSDID("$FreeBSD$");
 #endif	/* !__lint */
 
 #include <sys/param.h>
 
 #if !HAVE_NBTOOL_CONFIG_H
 #include <sys/mount.h>
 #endif
 
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdint.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <util.h>
 
-#include "ffs/buf.h"
-#include "makefs.h"
-#include "msdos.h"
-
 #include <mkfs_msdos.h>
 #include <fs/msdosfs/bpb.h>
 #include "msdos/direntry.h"
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+#undef clrbuf
+#include "ffs/buf.h"
+#include "makefs.h"
+#include "msdos.h"
+
 static int msdos_populate_dir(const char *, struct denode *, fsnode *,
     fsnode *, fsinfo_t *);
 
 struct msdos_options_ex {
 	struct msdos_options options;
 };
 
 void
 msdos_prep_opts(fsinfo_t *fsopts)
 {
 	struct msdos_options_ex *msdos_opt = ecalloc(1, sizeof(*msdos_opt));
 	const option_t msdos_options[] = {
 #define AOPT(_opt, _type, _name, _min, _desc) {				\
 	.letter = _opt,							\
 	.name = # _name,						\
 	.type = _min == -1 ? OPT_STRPTR :				\
 	    (_min == -2 ? OPT_BOOL :					\
 	    (sizeof(_type) == 1 ? OPT_INT8 :				\
 	    (sizeof(_type) == 2 ? OPT_INT16 :				\
 	    (sizeof(_type) == 4 ? OPT_INT32 : OPT_INT64)))),		\
 	.value = &msdos_opt->options._name,				\
 	.minimum = _min,						\
 	.maximum = sizeof(_type) == 1 ? UINT8_MAX :			\
 	    (sizeof(_type) == 2 ? UINT16_MAX :				\
 	    (sizeof(_type) == 4 ? UINT32_MAX : INT64_MAX)),		\
 	.desc = _desc,							\
 },
 ALLOPTS
 #undef AOPT
 		{ .name = NULL }
 	};
 
 	fsopts->fs_specific = msdos_opt;
 	fsopts->fs_options = copy_opts(msdos_options);
 }
 
 void
 msdos_cleanup_opts(fsinfo_t *fsopts)
 {
 	free(fsopts->fs_specific);
 	free(fsopts->fs_options);
 }
 
 int
 msdos_parse_opts(const char *option, fsinfo_t *fsopts)
 {
 	struct msdos_options *msdos_opt = fsopts->fs_specific;
 	option_t *msdos_options = fsopts->fs_options;
 	int rv;
 
 	assert(option != NULL);
 	assert(fsopts != NULL);
 	assert(msdos_opt != NULL);
 
 	if (debug & DEBUG_FS_PARSE_OPTS)
 		printf("msdos_parse_opts: got `%s'\n", option);
 
 	rv = set_option(msdos_options, option, NULL, 0);
 	if (rv == -1)
 		return rv;
 
 	if (strcmp(msdos_options[rv].name, "volume_id") == 0)
 		msdos_opt->volume_id_set = 1;
 	else if (strcmp(msdos_options[rv].name, "media_descriptor") == 0)
 		msdos_opt->media_descriptor_set = 1;
 	else if (strcmp(msdos_options[rv].name, "hidden_sectors") == 0)
 		msdos_opt->hidden_sectors_set = 1;
 
 	if (stampst.st_ino) {
 		msdos_opt->timestamp_set = 1;
 		msdos_opt->timestamp = stampst.st_mtime;
 	}
 
 	return 1;
 }
 
 
 void
 msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
 {
 	struct msdos_options_ex *msdos_opt = fsopts->fs_specific;
-	struct vnode vp, rootvp;
+	struct m_vnode vp, rootvp;
 	struct timeval start;
 	struct msdosfsmount *pmp;
 	uint32_t flags;
 
 	assert(image != NULL);
 	assert(dir != NULL);
 	assert(root != NULL);
 	assert(fsopts != NULL);
 
 	fsopts->size = fsopts->maxsize;
 	msdos_opt->options.create_size = MAX(msdos_opt->options.create_size,
 	    fsopts->offset + fsopts->size);
 	if (fsopts->offset > 0)
 		msdos_opt->options.offset = fsopts->offset;
 	if (msdos_opt->options.bytes_per_sector == 0) {
 		if (fsopts->sectorsize == -1)
 			fsopts->sectorsize = 512;
 		msdos_opt->options.bytes_per_sector = fsopts->sectorsize;
 	} else if (fsopts->sectorsize == -1) {
 		fsopts->sectorsize = msdos_opt->options.bytes_per_sector;
 	} else if (fsopts->sectorsize != msdos_opt->options.bytes_per_sector) {
 		err(1, "inconsistent sectorsize -S %u"
 		    "!= -o bytes_per_sector %u",
 		    fsopts->sectorsize, msdos_opt->options.bytes_per_sector);
 	}
 
 	/* create image */
 	printf("Creating `%s'\n", image);
 	TIMER_START(start);
 	if (mkfs_msdos(image, NULL, &msdos_opt->options) == -1)
 		return;
 	TIMER_RESULTS(start, "mkfs_msdos");
 
 	fsopts->fd = open(image, O_RDWR);
 	vp.fs = fsopts;
 
 	flags = 0;
-	if ((pmp = msdosfs_mount(&vp)) == NULL)
+	if ((pmp = m_msdosfs_mount(&vp)) == NULL)
 		err(1, "msdosfs_mount");
 
 	if (msdosfs_root(pmp, &rootvp) != 0)
 		err(1, "msdosfs_root");
 
 	if (debug & DEBUG_FS_MAKEFS)
 		printf("msdos_makefs: image %s directory %s root %p\n",
 		    image, dir, root);
 
 	/* populate image */
 	printf("Populating `%s'\n", image);
 	TIMER_START(start);
 	if (msdos_populate_dir(dir, VTODE(&rootvp), root, root, fsopts) == -1)
 		errx(1, "Image file `%s' not created.", image);
 	TIMER_RESULTS(start, "msdos_populate_dir");
 
 	if (msdosfs_fsiflush(pmp) != 0)
 		errx(1, "Unable to update FSInfo block.");
 	if (debug & DEBUG_FS_MAKEFS)
 		putchar('\n');
 
 	/* ensure no outstanding buffers remain */
 	if (debug & DEBUG_FS_MAKEFS)
 		bcleanup();
 
 	printf("Image `%s' complete\n", image);
 }
 
 static int
 msdos_populate_dir(const char *path, struct denode *dir, fsnode *root,
     fsnode *parent, fsinfo_t *fsopts)
 {
 	fsnode *cur;
 	char pbuf[MAXPATHLEN];
 
 	assert(dir != NULL);
 	assert(root != NULL);
 	assert(fsopts != NULL);
 
 	for (cur = root->next; cur != NULL; cur = cur->next) {
 		if ((size_t)snprintf(pbuf, sizeof(pbuf), "%s/%s", path,
 		    cur->name) >= sizeof(pbuf)) {
 			warnx("path %s too long", pbuf);
 			return -1;
 		}
 
 		if ((cur->inode->flags & FI_ALLOCATED) == 0) {
 			cur->inode->flags |= FI_ALLOCATED;
 			if (cur != root) {
 				fsopts->curinode++;
 				cur->inode->ino = fsopts->curinode;
 				cur->parent = parent;
 			}
 		}
 
 		if (cur->inode->flags & FI_WRITTEN) {
 			continue;	// hard link
 		}
 		cur->inode->flags |= FI_WRITTEN;
 
 		if (cur->child) {
 			struct denode *de;
 			if ((de = msdosfs_mkdire(pbuf, dir, cur)) == NULL) {
 				warn("msdosfs_mkdire %s", pbuf);
 				return -1;
 			}
 			if (msdos_populate_dir(pbuf, de, cur->child, cur,
 			    fsopts) == -1) {
 				warn("msdos_populate_dir %s", pbuf);
 				return -1;
 			}
 			continue;
 		} else if (!S_ISREG(cur->type)) {
 			warnx("skipping non-regular file %s/%s", cur->path,
 			    cur->name);
 			continue;
 		}
 		if (msdosfs_mkfile(cur->contents ? cur->contents : pbuf, dir,
 		    cur) == NULL) {
 			warn("msdosfs_mkfile %s", pbuf);
 			return -1;
 		}
 	}
 	return 0;
 }
diff --git a/usr.sbin/makefs/msdos.h b/usr.sbin/makefs/msdos.h
index d9f1cc4cdb11..a51420de76e5 100644
--- a/usr.sbin/makefs/msdos.h
+++ b/usr.sbin/makefs/msdos.h
@@ -1,61 +1,71 @@
 /*	$FreeBSD$ */
 /*	$NetBSD: msdos.h,v 1.3 2015/10/16 16:40:02 christos Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Christos Zoulas.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef _MAKEFS_MSDOS_H
 #define _MAKEFS_MSDOS_H
 
 #define NOCRED NULL
 
 #define MSDOSFS_DPRINTF(args) do {	\
 	if (debug & DEBUG_MSDOSFS)	\
 		printf args;		\
 } while (0);
 
 
 struct vnode;
 struct denode;
 struct fsnode;
 struct msdosfsmount;
 
 struct componentname {
 	char *cn_nameptr;
 	size_t cn_namelen;
 };
 
+struct m_vnode;
+struct m_buf;
+
 int msdosfs_fsiflush(struct msdosfsmount *);
-struct msdosfsmount *msdosfs_mount(struct vnode *);
-int msdosfs_root(struct msdosfsmount *, struct vnode *);
+struct msdosfsmount *msdosfs_mount(struct m_vnode *);
+int msdosfs_root(struct msdosfsmount *, struct m_vnode *);
 
 struct denode *msdosfs_mkfile(const char *, struct denode *, fsnode *);
 struct denode *msdosfs_mkdire(const char *, struct denode *, fsnode *);
 
+int m_readde(struct denode *dep, struct m_buf **bpp, struct direntry **epp);
+int m_readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
+    struct m_buf **bpp, struct direntry **epp);
+int m_extendfile(struct denode *dep, u_long count, struct m_buf **bpp,
+    u_long *ncp, int flags);
+
+struct msdosfsmount *m_msdosfs_mount(struct m_vnode *devvp);
 #endif
diff --git a/usr.sbin/makefs/msdos/msdosfs_denode.c b/usr.sbin/makefs/msdos/msdosfs_denode.c
index 283ef2e83e0b..f2faed234228 100644
--- a/usr.sbin/makefs/msdos/msdosfs_denode.c
+++ b/usr.sbin/makefs/msdos/msdosfs_denode.c
@@ -1,378 +1,378 @@
 /*	$NetBSD: msdosfs_denode.c,v 1.7 2015/03/29 05:52:59 agc Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
  * All rights reserved.
  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by TooLs GmbH.
  * 4. The name of TooLs GmbH may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*-
  * Written by Paul Popelka (paulp@uts.amdahl.com)
  *
  * You can do anything you want with this software, just don't say you wrote
  * it, and don't remove this notice.
  *
  * This software is provided "as is".
  *
  * The author supplies this software to be publicly redistributed on the
  * understanding that the author is not responsible for the correct
  * functioning of this software in any circumstances and is not liable for
  * any damages caused by this software.
  *
  * October 1992
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/errno.h>
 
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <util.h>
 
-#include "ffs/buf.h"
-
 #include <fs/msdosfs/bpb.h>
 #include <fs/msdosfs/direntry.h>
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+#undef clrbuf
+#include "ffs/buf.h"
 #include "makefs.h"
 #include "msdos.h"
 
 
 /*
  * If deget() succeeds it returns with the gotten denode locked().
  *
  * pmp	     - address of msdosfsmount structure of the filesystem containing
  *	       the denode of interest.  The pm_dev field and the address of
  *	       the msdosfsmount structure are used.
  * dirclust  - which cluster bp contains, if dirclust is 0 (root directory)
  *	       diroffset is relative to the beginning of the root directory,
  *	       otherwise it is cluster relative.
  * diroffset - offset past begin of cluster of denode we want
  * depp	     - returns the address of the gotten denode.
  */
 int
 deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
     struct denode **depp)
 {
 	int error;
 	uint64_t inode;
 	struct direntry *direntptr;
 	struct denode *ldep;
-	struct buf *bp;
+	struct m_buf *bp;
 
 	MSDOSFS_DPRINTF(("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
 	    pmp, dirclust, diroffset, depp));
 
 	/*
 	 * On FAT32 filesystems, root is a (more or less) normal
 	 * directory
 	 */
 	if (FAT32(pmp) && dirclust == MSDOSFSROOT)
 		dirclust = pmp->pm_rootdirblk;
 
 	inode = (uint64_t)pmp->pm_bpcluster * dirclust + diroffset;
 
 	ldep = ecalloc(1, sizeof(*ldep));
 	ldep->de_vnode = NULL;
 	ldep->de_flag = 0;
 	ldep->de_dirclust = dirclust;
 	ldep->de_diroffset = diroffset;
 	ldep->de_inode = inode;
 	ldep->de_pmp = pmp;
 	ldep->de_refcnt = 1;
 	fc_purge(ldep, 0);	/* init the FAT cache for this denode */
 	/*
 	 * Copy the directory entry into the denode area of the vnode.
 	 */
 	if ((dirclust == MSDOSFSROOT
 	     || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
 	    && diroffset == MSDOSFSROOT_OFS) {
 		/*
 		 * Directory entry for the root directory. There isn't one,
 		 * so we manufacture one. We should probably rummage
 		 * through the root directory and find a label entry (if it
 		 * exists), and then use the time and date from that entry
 		 * as the time and date for the root denode.
 		 */
 		ldep->de_vnode = (struct vnode *)-1;
 
 		ldep->de_Attributes = ATTR_DIRECTORY;
 		ldep->de_LowerCase = 0;
 		if (FAT32(pmp))
 			ldep->de_StartCluster = pmp->pm_rootdirblk;
 			/* de_FileSize will be filled in further down */
 		else {
 			ldep->de_StartCluster = MSDOSFSROOT;
 			ldep->de_FileSize = pmp->pm_rootdirsize * DEV_BSIZE;
 		}
 		/*
 		 * fill in time and date so that dos2unixtime() doesn't
 		 * spit up when called from msdosfs_getattr() with root
 		 * denode
 		 */
 		ldep->de_CHun = 0;
 		ldep->de_CTime = 0x0000;	/* 00:00:00	 */
 		ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
 		    | (1 << DD_DAY_SHIFT);
 		/* Jan 1, 1980	 */
 		ldep->de_ADate = ldep->de_CDate;
 		ldep->de_MTime = ldep->de_CTime;
 		ldep->de_MDate = ldep->de_CDate;
 		/* leave the other fields as garbage */
 	} else {
-		error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
+		error = m_readep(pmp, dirclust, diroffset, &bp, &direntptr);
 		if (error) {
 			ldep->de_Name[0] = SLOT_DELETED;
 
 			*depp = NULL;
 			return (error);
 		}
 		(void)DE_INTERNALIZE(ldep, direntptr);
 		brelse(bp);
 	}
 
 	/*
 	 * Fill in a few fields of the vnode and finish filling in the
 	 * denode.  Then return the address of the found denode.
 	 */
 	if (ldep->de_Attributes & ATTR_DIRECTORY) {
 		/*
 		 * Since DOS directory entries that describe directories
 		 * have 0 in the filesize field, we take this opportunity
 		 * to find out the length of the directory and plug it into
 		 * the denode structure.
 		 */
 		u_long size;
 
 		/*
 		 * XXX it sometimes happens that the "." entry has cluster
 		 * number 0 when it shouldn't.  Use the actual cluster number
 		 * instead of what is written in directory entry.
 		 */
 		if (diroffset == 0 && ldep->de_StartCluster != dirclust) {
 			MSDOSFS_DPRINTF(("deget(): \".\" entry at clust %lu != %lu\n",
 			    dirclust, ldep->de_StartCluster));
 
 			ldep->de_StartCluster = dirclust;
 		}
 
 		if (ldep->de_StartCluster != MSDOSFSROOT) {
 			error = pcbmap(ldep, 0xffff, 0, &size, 0);
 			if (error == E2BIG) {
 				ldep->de_FileSize = de_cn2off(pmp, size);
 				error = 0;
 			} else {
 				MSDOSFS_DPRINTF(("deget(): pcbmap returned %d\n",
 				    error));
 			}
 		}
 	}
 	*depp = ldep;
 	return (0);
 }
 
 /*
  * Truncate the file described by dep to the length specified by length.
  */
 int
 detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred)
 {
 	int error;
 	int allerror;
 	u_long eofentry;
 	u_long chaintofree;
 	daddr_t bn;
 	int boff;
 	int isadir = dep->de_Attributes & ATTR_DIRECTORY;
-	struct buf *bp;
+	struct m_buf *bp;
 	struct msdosfsmount *pmp = dep->de_pmp;
 
 	MSDOSFS_DPRINTF(("detrunc(): file %s, length %lu, flags %x\n",
 	    dep->de_Name, length, flags));
 
 	/*
 	 * Disallow attempts to truncate the root directory since it is of
 	 * fixed size.  That's just the way dos filesystems are.  We use
 	 * the VROOT bit in the vnode because checking for the directory
 	 * bit and a startcluster of 0 in the denode is not adequate to
 	 * recognize the root directory at this point in a file or
 	 * directory's life.
 	 */
 	if (dep->de_vnode != NULL && !FAT32(pmp)) {
 		MSDOSFS_DPRINTF(("detrunc(): can't truncate root directory, "
 		    "clust %ld, offset %ld\n",
 		    dep->de_dirclust, dep->de_diroffset));
 
 		return (EINVAL);
 	}
 
 	if (dep->de_FileSize < length)
 		return deextend(dep, length, cred);
 
 	/*
 	 * If the desired length is 0 then remember the starting cluster of
 	 * the file and set the StartCluster field in the directory entry
 	 * to 0.  If the desired length is not zero, then get the number of
 	 * the last cluster in the shortened file.  Then get the number of
 	 * the first cluster in the part of the file that is to be freed.
 	 * Then set the next cluster pointer in the last cluster of the
 	 * file to CLUST_EOFE.
 	 */
 	if (length == 0) {
 		chaintofree = dep->de_StartCluster;
 		dep->de_StartCluster = 0;
 		eofentry = ~0;
 	} else {
 		error = pcbmap(dep, de_clcount(pmp, length) - 1, 0,
 		    &eofentry, 0);
 		if (error) {
 			MSDOSFS_DPRINTF(("detrunc(): pcbmap fails %d\n",
 			    error));
 			return (error);
 		}
 	}
 
 	fc_purge(dep, de_clcount(pmp, length));
 
 	/*
 	 * If the new length is not a multiple of the cluster size then we
 	 * must zero the tail end of the new last cluster in case it
 	 * becomes part of the file again because of a seek.
 	 */
 	if ((boff = length & pmp->pm_crbomask) != 0) {
 		if (isadir) {
 			bn = cntobn(pmp, eofentry);
-			error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
-			    0, &bp);
+			error = bread((void *)pmp->pm_devvp, bn,
+			    pmp->pm_bpcluster, 0, &bp);
 			if (error) {
 				brelse(bp);
 				MSDOSFS_DPRINTF(("detrunc(): bread fails %d\n",
 				    error));
 
 				return (error);
 			}
 			memset(bp->b_data + boff, 0, pmp->pm_bpcluster - boff);
 			bwrite(bp);
 		}
 	}
 
 	/*
 	 * Write out the updated directory entry.  Even if the update fails
 	 * we free the trailing clusters.
 	 */
 	dep->de_FileSize = length;
 	if (!isadir)
 		dep->de_flag |= DE_UPDATE|DE_MODIFIED;
 	MSDOSFS_DPRINTF(("detrunc(): allerror %d, eofentry %lu\n",
 	    allerror, eofentry));
 
 	/*
 	 * If we need to break the cluster chain for the file then do it
 	 * now.
 	 */
 	if (eofentry != ~0) {
 		error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
 				 &chaintofree, CLUST_EOFE);
 		if (error) {
 			MSDOSFS_DPRINTF(("detrunc(): fatentry errors %d\n",
 			    error));
 			return (error);
 		}
 		fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
 		    eofentry);
 	}
 
 	/*
 	 * Now free the clusters removed from the file because of the
 	 * truncation.
 	 */
 	if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
 		freeclusterchain(pmp, chaintofree);
 
 	return (allerror);
 }
 
 /*
  * Extend the file described by dep to length specified by length.
  */
 int
 deextend(struct denode *dep, u_long length, struct ucred *cred)
 {
 	struct msdosfsmount *pmp = dep->de_pmp;
 	u_long count;
 	int error;
 
 	/*
 	 * The root of a DOS filesystem cannot be extended.
 	 */
 	if (dep->de_vnode != NULL && !FAT32(pmp))
 		return (EINVAL);
 
 	/*
 	 * Directories cannot be extended.
 	 */
 	if (dep->de_Attributes & ATTR_DIRECTORY)
 		return (EISDIR);
 
 	if (length <= dep->de_FileSize)
 		return (E2BIG);
 
 	/*
 	 * Compute the number of clusters to allocate.
 	 */
 	count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
 	if (count > 0) {
 		if (count > pmp->pm_freeclustercount)
 			return (ENOSPC);
-		error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
+		error = m_extendfile(dep, count, NULL, NULL, DE_CLEAR);
 		if (error) {
 			/* truncate the added clusters away again */
 			(void) detrunc(dep, dep->de_FileSize, 0, cred);
 			return (error);
 		}
 	}
 
 	/*
 	 * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a
 	 * memset(); we set the write size so ubc won't read in file data that
 	 * is zero'd later.
 	 */
 	dep->de_FileSize = length;
 	dep->de_flag |= DE_UPDATE | DE_MODIFIED;
 	return 0;
 }
diff --git a/usr.sbin/makefs/msdos/msdosfs_fat.c b/usr.sbin/makefs/msdos/msdosfs_fat.c
index eacc448b09de..a70b5741aa78 100644
--- a/usr.sbin/makefs/msdos/msdosfs_fat.c
+++ b/usr.sbin/makefs/msdos/msdosfs_fat.c
@@ -1,1057 +1,1060 @@
 /* $FreeBSD$ */
 /*	$NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
  * All rights reserved.
  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by TooLs GmbH.
  * 4. The name of TooLs GmbH may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*-
  * Written by Paul Popelka (paulp@uts.amdahl.com)
  *
  * You can do anything you want with this software, just don't say you wrote
  * it, and don't remove this notice.
  *
  * This software is provided "as is".
  *
  * The author supplies this software to be publicly redistributed on the
  * understanding that the author is not responsible for the correct
  * functioning of this software in any circumstances and is not liable for
  * any damages caused by this software.
  *
  * October 1992
  */
 
 #include <sys/param.h>
 #include <sys/errno.h>
 
 #include <assert.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
 
-#include "ffs/buf.h"
-
 #include <fs/msdosfs/bpb.h>
 #include "msdos/direntry.h"
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+#undef clrbuf
+#include "ffs/buf.h"
 #include "makefs.h"
 #include "msdos.h"
 
 #define	FULL_RUN	((u_int)0xffffffff)
 #define	SYNCHRONOUS_WRITES(pmp)	1
 
 static int	chainalloc(struct msdosfsmount *pmp, u_long start,
 		    u_long count, u_long fillwith, u_long *retcluster,
 		    u_long *got);
 static int	chainlength(struct msdosfsmount *pmp, u_long start,
 		    u_long count);
 static void	fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp,
 		    u_long *sizep, u_long *bop);
 static int	fatchain(struct msdosfsmount *pmp, u_long start, u_long count,
 		    u_long fillwith);
 static void	fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp,
 		    u_long *fsrcnp);
-static void	updatefats(struct msdosfsmount *pmp, struct buf *bp,
+static void	updatefats(struct msdosfsmount *pmp, struct m_buf *bp,
 		    u_long fatbn);
 static __inline void
 		usemap_alloc(struct msdosfsmount *pmp, u_long cn);
 static __inline void
 		usemap_free(struct msdosfsmount *pmp, u_long cn);
 static int	clusteralloc1(struct msdosfsmount *pmp, u_long start,
 		    u_long count, u_long fillwith, u_long *retcluster,
 		    u_long *got);
 
 static void
 fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, u_long *sizep,
     u_long *bop)
 {
 	u_long bn, size;
 
 	bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
 	size = MIN(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
 	    * DEV_BSIZE;
 	bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs;
 
 	if (bnp)
 		*bnp = bn;
 	if (sizep)
 		*sizep = size;
 	if (bop)
 		*bop = ofs % pmp->pm_fatblocksize;
 }
 
 /*
  * Map the logical cluster number of a file into a physical disk sector
  * that is filesystem relative.
  *
  * dep	  - address of denode representing the file of interest
  * findcn - file relative cluster whose filesystem relative cluster number
  *	    and/or block number are/is to be found
  * bnp	  - address of where to place the filesystem relative block number.
  *	    If this pointer is null then don't return this quantity.
  * cnp	  - address of where to place the filesystem relative cluster number.
  *	    If this pointer is null then don't return this quantity.
  * sp     - pointer to returned block size
  *
  * NOTE: Either bnp or cnp must be non-null.
  * This function has one side effect.  If the requested file relative cluster
  * is beyond the end of file, then the actual number of clusters in the file
  * is returned in *cnp.  This is useful for determining how long a directory is.
  *  If cnp is null, nothing is returned.
  */
 int
 pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int *sp)
 {
 	int error;
 	u_long i;
 	u_long cn;
 	u_long prevcn = 0; /* XXX: prevcn could be used unititialized */
 	u_long byteoffset;
 	u_long bn;
 	u_long bo;
-	struct buf *bp = NULL;
+	struct m_buf *bp = NULL;
 	u_long bp_bn = -1;
 	struct msdosfsmount *pmp = dep->de_pmp;
 	u_long bsize;
 
 	assert(bnp != NULL || cnp != NULL || sp != NULL);
 
 	cn = dep->de_StartCluster;
 	/*
 	 * The "file" that makes up the root directory is contiguous,
 	 * permanently allocated, of fixed size, and is not made up of
 	 * clusters.  If the cluster number is beyond the end of the root
 	 * directory, then return the number of clusters in the file.
 	 */
 	if (cn == MSDOSFSROOT) {
 		if (dep->de_Attributes & ATTR_DIRECTORY) {
 			if (de_cn2off(pmp, findcn) >= dep->de_FileSize) {
 				if (cnp)
 					*cnp = de_bn2cn(pmp, pmp->pm_rootdirsize);
 				return (E2BIG);
 			}
 			if (bnp)
 				*bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn);
 			if (cnp)
 				*cnp = MSDOSFSROOT;
 			if (sp)
 				*sp = MIN(pmp->pm_bpcluster,
 				    dep->de_FileSize - de_cn2off(pmp, findcn));
 			return (0);
 		} else {		/* just an empty file */
 			if (cnp)
 				*cnp = 0;
 			return (E2BIG);
 		}
 	}
 
 	/*
 	 * All other files do I/O in cluster sized blocks
 	 */
 	if (sp)
 		*sp = pmp->pm_bpcluster;
 
 	/*
 	 * Rummage around in the FAT cache, maybe we can avoid tromping
 	 * through every FAT entry for the file. And, keep track of how far
 	 * off the cache was from where we wanted to be.
 	 */
 	i = 0;
 	fc_lookup(dep, findcn, &i, &cn);
 
 	/*
 	 * Handle all other files or directories the normal way.
 	 */
 	for (; i < findcn; i++) {
 		/*
 		 * Stop with all reserved clusters, not just with EOF.
 		 */
 		if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
 			goto hiteof;
 		byteoffset = FATOFS(pmp, cn);
 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
 		if (bn != bp_bn) {
 			if (bp)
 				brelse(bp);
-			error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
+			error = bread((void *)pmp->pm_devvp, bn, bsize,
+			    NOCRED, &bp);
 			if (error) {
 				brelse(bp);
 				return (error);
 			}
 			bp_bn = bn;
 		}
 		prevcn = cn;
 		if (bo >= bsize) {
 			if (bp)
 				brelse(bp);
 			return (EIO);
 		}
 		if (FAT32(pmp))
 			cn = getulong(bp->b_data + bo);
 		else
 			cn = getushort(bp->b_data + bo);
 		if (FAT12(pmp) && (prevcn & 1))
 			cn >>= 4;
 		cn &= pmp->pm_fatmask;
 
 		/*
 		 * Force the special cluster numbers
 		 * to be the same for all cluster sizes
 		 * to let the rest of msdosfs handle
 		 * all cases the same.
 		 */
 		if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
 			cn |= ~pmp->pm_fatmask;
 	}
 
 	if (!MSDOSFSEOF(pmp, cn)) {
 		if (bp)
 			brelse(bp);
 		if (bnp)
 			*bnp = cntobn(pmp, cn);
 		if (cnp)
 			*cnp = cn;
 		fc_setcache(dep, FC_LASTMAP, i, cn);
 		return (0);
 	}
 
 hiteof:;
 	if (cnp)
 		*cnp = i;
 	if (bp)
 		brelse(bp);
 	/* update last file cluster entry in the FAT cache */
 	fc_setcache(dep, FC_LASTFC, i - 1, prevcn);
 	return (E2BIG);
 }
 
 /*
  * Find the closest entry in the FAT cache to the cluster we are looking
  * for.
  */
 static void
 fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, u_long *fsrcnp)
 {
 	int i;
 	u_long cn;
 	struct fatcache *closest = NULL;
 
 	for (i = 0; i < FC_SIZE; i++) {
 		cn = dep->de_fc[i].fc_frcn;
 		if (cn != FCE_EMPTY && cn <= findcn) {
 			if (closest == NULL || cn > closest->fc_frcn)
 				closest = &dep->de_fc[i];
 		}
 	}
 	if (closest) {
 		*frcnp = closest->fc_frcn;
 		*fsrcnp = closest->fc_fsrcn;
 	}
 }
 
 /*
  * Purge the FAT cache in denode dep of all entries relating to file
  * relative cluster frcn and beyond.
  */
 void
 fc_purge(struct denode *dep, u_int frcn)
 {
 	int i;
 	struct fatcache *fcp;
 
 	fcp = dep->de_fc;
 	for (i = 0; i < FC_SIZE; i++, fcp++) {
 		if (fcp->fc_frcn >= frcn)
 			fcp->fc_frcn = FCE_EMPTY;
 	}
 }
 
 /*
  * Update the FAT.
  * If mirroring the FAT, update all copies, with the first copy as last.
  * Else update only the current FAT (ignoring the others).
  *
  * pmp	 - msdosfsmount structure for filesystem to update
  * bp	 - addr of modified FAT block
  * fatbn - block number relative to begin of filesystem of the modified FAT block.
  */
 static void
-updatefats(struct msdosfsmount *pmp, struct buf *bp, u_long fatbn)
+updatefats(struct msdosfsmount *pmp, struct m_buf *bp, u_long fatbn)
 {
-	struct buf *bpn;
+	struct m_buf *bpn;
 	int cleanfat, i;
 
 #ifdef MSDOSFS_DEBUG
 	printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp, bp, fatbn);
 #endif
 
 	if (pmp->pm_flags & MSDOSFS_FATMIRROR) {
 		/*
 		 * Now copy the block(s) of the modified FAT to the other copies of
 		 * the FAT and write them out.  This is faster than reading in the
 		 * other FATs and then writing them back out.  This could tie up
 		 * the FAT for quite a while. Preventing others from accessing it.
 		 * To prevent us from going after the FAT quite so much we use
 		 * delayed writes, unless they specified "synchronous" when the
 		 * filesystem was mounted.  If synch is asked for then use
 		 * bwrite()'s and really slow things down.
 		 */
 		if (fatbn != pmp->pm_fatblk || FAT12(pmp))
 			cleanfat = 0;
 		else if (FAT16(pmp))
 			cleanfat = 16;
 		else
 			cleanfat = 32;
 		for (i = 1; i < pmp->pm_FATs; i++) {
 			fatbn += pmp->pm_FATsecs;
 			/* getblk() never fails */
-			bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount,
-			    0, 0, 0);
+			bpn = getblk((void *)pmp->pm_devvp, fatbn,
+			    bp->b_bcount, 0, 0, 0);
 			memcpy(bpn->b_data, bp->b_data, bp->b_bcount);
 			/* Force the clean bit on in the other copies. */
 			if (cleanfat == 16)
 				((uint8_t *)bpn->b_data)[3] |= 0x80;
 			else if (cleanfat == 32)
 				((uint8_t *)bpn->b_data)[7] |= 0x08;
 			if (SYNCHRONOUS_WRITES(pmp))
 				bwrite(bpn);
 			else
 				bdwrite(bpn);
 		}
 	}
 
 	/*
 	 * Write out the first (or current) FAT last.
 	 */
 	if (SYNCHRONOUS_WRITES(pmp))
 		bwrite(bp);
 	else
 		bdwrite(bp);
 }
 
 /*
  * Updating entries in 12 bit FATs is a pain in the butt.
  *
  * The following picture shows where nibbles go when moving from a 12 bit
  * cluster number into the appropriate bytes in the FAT.
  *
  *	byte m        byte m+1      byte m+2
  *	+----+----+   +----+----+   +----+----+
  *	|  0    1 |   |  2    3 |   |  4    5 |   FAT bytes
  *	+----+----+   +----+----+   +----+----+
  *
  *	+----+----+----+   +----+----+----+
  *	|  3    0    1 |   |  4    5    2 |
  *	+----+----+----+   +----+----+----+
  *	cluster n	   cluster n+1
  *
  * Where n is even. m = n + (n >> 2)
  *
  */
 static __inline void
 usemap_alloc(struct msdosfsmount *pmp, u_long cn)
 {
 
 	assert(cn <= pmp->pm_maxcluster);
 	assert((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0);
 	assert((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
 	    == 0);
 	assert(pmp->pm_freeclustercount > 0);
 
 	pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS);
 	pmp->pm_freeclustercount--;
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
 }
 
 static __inline void
 usemap_free(struct msdosfsmount *pmp, u_long cn)
 {
 
 	assert(cn <= pmp->pm_maxcluster);
 	assert((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0);
 	assert((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
 	    != 0);
 
 	pmp->pm_freeclustercount++;
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
 	pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS));
 }
 
 int
 clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp)
 {
 	int error;
 	u_long oldcn;
 
 	error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
 	if (error)
 		return (error);
 	/*
 	 * If the cluster was successfully marked free, then update
 	 * the count of free clusters, and turn off the "allocated"
 	 * bit in the "in use" cluster bit map.
 	 */
 	usemap_free(pmp, cluster);
 	if (oldcnp)
 		*oldcnp = oldcn;
 	return (0);
 }
 
 /*
  * Get or Set or 'Get and Set' the cluster'th entry in the FAT.
  *
  * function	- whether to get or set a FAT entry
  * pmp		- address of the msdosfsmount structure for the filesystem
  *		  whose FAT is to be manipulated.
  * cn		- which cluster is of interest
  * oldcontents	- address of a word that is to receive the contents of the
  *		  cluster'th entry if this is a get function
  * newcontents	- the new value to be written into the cluster'th element of
  *		  the FAT if this is a set function.
  *
  * This function can also be used to free a cluster by setting the FAT entry
  * for a cluster to 0.
  *
  * All copies of the FAT are updated if this is a set function. NOTE: If
  * fatentry() marks a cluster as free it does not update the inusemap in
  * the msdosfsmount structure. This is left to the caller.
  */
 int
 fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents,
     u_long newcontents)
 {
 	int error;
 	u_long readcn;
 	u_long bn, bo, bsize, byteoffset;
-	struct buf *bp;
+	struct m_buf *bp;
 
 #ifdef	MSDOSFS_DEBUG
 	printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
 	    function, pmp, cn, oldcontents, newcontents);
 #endif
 
 #ifdef DIAGNOSTIC
 	/*
 	 * Be sure they asked us to do something.
 	 */
 	if ((function & (FAT_SET | FAT_GET)) == 0) {
 #ifdef MSDOSFS_DEBUG
 		printf("fatentry(): function code doesn't specify get or set\n");
 #endif
 		return (EINVAL);
 	}
 
 	/*
 	 * If they asked us to return a cluster number but didn't tell us
 	 * where to put it, give them an error.
 	 */
 	if ((function & FAT_GET) && oldcontents == NULL) {
 #ifdef MSDOSFS_DEBUG
 		printf("fatentry(): get function with no place to put result\n");
 #endif
 		return (EINVAL);
 	}
 #endif
 
 	/*
 	 * Be sure the requested cluster is in the filesystem.
 	 */
 	if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
 		return (EINVAL);
 
 	byteoffset = FATOFS(pmp, cn);
 	fatblock(pmp, byteoffset, &bn, &bsize, &bo);
-	error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
+	error = bread((void *)pmp->pm_devvp, bn, bsize, NOCRED, &bp);
 	if (error) {
 		brelse(bp);
 		return (error);
 	}
 
 	if (function & FAT_GET) {
 		if (FAT32(pmp))
 			readcn = getulong(bp->b_data + bo);
 		else
 			readcn = getushort(bp->b_data + bo);
 		if (FAT12(pmp) & (cn & 1))
 			readcn >>= 4;
 		readcn &= pmp->pm_fatmask;
 		/* map reserved FAT entries to same values for all FATs */
 		if ((readcn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
 			readcn |= ~pmp->pm_fatmask;
 		*oldcontents = readcn;
 	}
 	if (function & FAT_SET) {
 		switch (pmp->pm_fatmask) {
 		case FAT12_MASK:
 			readcn = getushort(bp->b_data + bo);
 			if (cn & 1) {
 				readcn &= 0x000f;
 				readcn |= newcontents << 4;
 			} else {
 				readcn &= 0xf000;
 				readcn |= newcontents & 0xfff;
 			}
 			putushort(bp->b_data + bo, readcn);
 			break;
 		case FAT16_MASK:
 			putushort(bp->b_data + bo, newcontents);
 			break;
 		case FAT32_MASK:
 			/*
 			 * According to spec we have to retain the
 			 * high order bits of the FAT entry.
 			 */
 			readcn = getulong(bp->b_data + bo);
 			readcn &= ~FAT32_MASK;
 			readcn |= newcontents & FAT32_MASK;
 			putulong(bp->b_data + bo, readcn);
 			break;
 		}
 		updatefats(pmp, bp, bn);
 		bp = NULL;
 		pmp->pm_fmod = 1;
 	}
 	if (bp)
 		brelse(bp);
 	return (0);
 }
 
 /*
  * Update a contiguous cluster chain
  *
  * pmp	    - mount point
  * start    - first cluster of chain
  * count    - number of clusters in chain
  * fillwith - what to write into FAT entry of last cluster
  */
 static int
 fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith)
 {
 	int error;
 	u_long bn, bo, bsize, byteoffset, readcn, newc;
-	struct buf *bp;
+	struct m_buf *bp;
 
 #ifdef MSDOSFS_DEBUG
 	printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
 	    pmp, start, count, fillwith);
 #endif
 	/*
 	 * Be sure the clusters are in the filesystem.
 	 */
 	if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster)
 		return (EINVAL);
 
 	while (count > 0) {
 		byteoffset = FATOFS(pmp, start);
 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
-		error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
+		error = bread((void *)pmp->pm_devvp, bn, bsize, NOCRED, &bp);
 		if (error) {
 			brelse(bp);
 			return (error);
 		}
 		while (count > 0) {
 			start++;
 			newc = --count > 0 ? start : fillwith;
 			switch (pmp->pm_fatmask) {
 			case FAT12_MASK:
 				readcn = getushort(bp->b_data + bo);
 				if (start & 1) {
 					readcn &= 0xf000;
 					readcn |= newc & 0xfff;
 				} else {
 					readcn &= 0x000f;
 					readcn |= newc << 4;
 				}
 				putushort(bp->b_data + bo, readcn);
 				bo++;
 				if (!(start & 1))
 					bo++;
 				break;
 			case FAT16_MASK:
 				putushort(bp->b_data + bo, newc);
 				bo += 2;
 				break;
 			case FAT32_MASK:
 				readcn = getulong(bp->b_data + bo);
 				readcn &= ~pmp->pm_fatmask;
 				readcn |= newc & pmp->pm_fatmask;
 				putulong(bp->b_data + bo, readcn);
 				bo += 4;
 				break;
 			}
 			if (bo >= bsize)
 				break;
 		}
 		updatefats(pmp, bp, bn);
 	}
 	pmp->pm_fmod = 1;
 	return (0);
 }
 
 /*
  * Check the length of a free cluster chain starting at start.
  *
  * pmp	 - mount point
  * start - start of chain
  * count - maximum interesting length
  */
 static int
 chainlength(struct msdosfsmount *pmp, u_long start, u_long count)
 {
 	u_long idx, max_idx;
 	u_int map;
 	u_long len;
 
 	if (start > pmp->pm_maxcluster)
 		return (0);
 	max_idx = pmp->pm_maxcluster / N_INUSEBITS;
 	idx = start / N_INUSEBITS;
 	start %= N_INUSEBITS;
 	map = pmp->pm_inusemap[idx];
 	map &= ~((1 << start) - 1);
 	if (map) {
 		len = ffs(map) - 1 - start;
 		len = MIN(len, count);
 		if (start + len > pmp->pm_maxcluster)
 			len = pmp->pm_maxcluster - start + 1;
 		return (len);
 	}
 	len = N_INUSEBITS - start;
 	if (len >= count) {
 		len = count;
 		if (start + len > pmp->pm_maxcluster)
 			len = pmp->pm_maxcluster - start + 1;
 		return (len);
 	}
 	while (++idx <= max_idx) {
 		if (len >= count)
 			break;
 		map = pmp->pm_inusemap[idx];
 		if (map) {
 			len += ffs(map) - 1;
 			break;
 		}
 		len += N_INUSEBITS;
 	}
 	len = MIN(len, count);
 	if (start + len > pmp->pm_maxcluster)
 		len = pmp->pm_maxcluster - start + 1;
 	return (len);
 }
 
 /*
  * Allocate contigous free clusters.
  *
  * pmp	      - mount point.
  * start      - start of cluster chain.
  * count      - number of clusters to allocate.
  * fillwith   - put this value into the FAT entry for the
  *		last allocated cluster.
  * retcluster - put the first allocated cluster's number here.
  * got	      - how many clusters were actually allocated.
  */
 static int
 chainalloc(struct msdosfsmount *pmp, u_long start, u_long count,
     u_long fillwith, u_long *retcluster, u_long *got)
 {
 	int error;
 	u_long cl, n;
 
 	assert((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0);
 
 	for (cl = start, n = count; n-- > 0;)
 		usemap_alloc(pmp, cl++);
 	pmp->pm_nxtfree = start + count;
 	if (pmp->pm_nxtfree > pmp->pm_maxcluster)
 		pmp->pm_nxtfree = CLUST_FIRST;
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
 	error = fatchain(pmp, start, count, fillwith);
 	if (error != 0) {
 		for (cl = start, n = count; n-- > 0;)
 			usemap_free(pmp, cl++);
 		return (error);
 	}
 #ifdef MSDOSFS_DEBUG
 	printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
 	    start, count);
 #endif
 	if (retcluster)
 		*retcluster = start;
 	if (got)
 		*got = count;
 	return (0);
 }
 
 /*
  * Allocate contiguous free clusters.
  *
  * pmp	      - mount point.
  * start      - preferred start of cluster chain.
  * count      - number of clusters requested.
  * fillwith   - put this value into the FAT entry for the
  *		last allocated cluster.
  * retcluster - put the first allocated cluster's number here.
  * got	      - how many clusters were actually allocated.
  */
 int
 clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count,
     u_long fillwith, u_long *retcluster, u_long *got)
 {
 	int error;
 
 	error = clusteralloc1(pmp, start, count, fillwith, retcluster, got);
 	return (error);
 }
 
 static int
 clusteralloc1(struct msdosfsmount *pmp, u_long start, u_long count,
     u_long fillwith, u_long *retcluster, u_long *got)
 {
 	u_long idx;
 	u_long len, newst, foundl, cn, l;
 	u_long foundcn = 0; /* XXX: foundcn could be used unititialized */
 	u_int map;
 
 	MSDOSFS_DPRINTF(("clusteralloc(): find %lu clusters\n", count));
 
 	if (start) {
 		if ((len = chainlength(pmp, start, count)) >= count)
 			return (chainalloc(pmp, start, count, fillwith, retcluster, got));
 	} else
 		len = 0;
 
 	newst = pmp->pm_nxtfree;
 	foundl = 0;
 
 	for (cn = newst; cn <= pmp->pm_maxcluster;) {
 		idx = cn / N_INUSEBITS;
 		map = pmp->pm_inusemap[idx];
 		map |= (1U << (cn % N_INUSEBITS)) - 1;
 		if (map != FULL_RUN) {
 			cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1;
 			if ((l = chainlength(pmp, cn, count)) >= count)
 				return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
 			if (l > foundl) {
 				foundcn = cn;
 				foundl = l;
 			}
 			cn += l + 1;
 			continue;
 		}
 		cn += N_INUSEBITS - cn % N_INUSEBITS;
 	}
 	for (cn = 0; cn < newst;) {
 		idx = cn / N_INUSEBITS;
 		map = pmp->pm_inusemap[idx];
 		map |= (1U << (cn % N_INUSEBITS)) - 1;
 		if (map != FULL_RUN) {
 			cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1;
 			if ((l = chainlength(pmp, cn, count)) >= count)
 				return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
 			if (l > foundl) {
 				foundcn = cn;
 				foundl = l;
 			}
 			cn += l + 1;
 			continue;
 		}
 		cn += N_INUSEBITS - cn % N_INUSEBITS;
 	}
 
 	if (!foundl)
 		return (ENOSPC);
 
 	if (len)
 		return (chainalloc(pmp, start, len, fillwith, retcluster, got));
 	else
 		return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got));
 }
 
 
 /*
  * Free a chain of clusters.
  *
  * pmp		- address of the msdosfs mount structure for the filesystem
  *		  containing the cluster chain to be freed.
  * startcluster - number of the 1st cluster in the chain of clusters to be
  *		  freed.
  */
 int
 freeclusterchain(struct msdosfsmount *pmp, u_long cluster)
 {
 	int error;
-	struct buf *bp = NULL;
+	struct m_buf *bp = NULL;
 	u_long bn, bo, bsize, byteoffset;
 	u_long readcn, lbn = -1;
 
 	while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) {
 		byteoffset = FATOFS(pmp, cluster);
 		fatblock(pmp, byteoffset, &bn, &bsize, &bo);
 		if (lbn != bn) {
 			if (bp)
 				updatefats(pmp, bp, lbn);
-			error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
+			error = bread((void *)pmp->pm_devvp, bn, bsize,
+			    NOCRED, &bp);
 			if (error) {
 				brelse(bp);
 				return (error);
 			}
 			lbn = bn;
 		}
 		usemap_free(pmp, cluster);
 		switch (pmp->pm_fatmask) {
 		case FAT12_MASK:
 			readcn = getushort(bp->b_data + bo);
 			if (cluster & 1) {
 				cluster = readcn >> 4;
 				readcn &= 0x000f;
 				readcn |= MSDOSFSFREE << 4;
 			} else {
 				cluster = readcn;
 				readcn &= 0xf000;
 				readcn |= MSDOSFSFREE & 0xfff;
 			}
 			putushort(bp->b_data + bo, readcn);
 			break;
 		case FAT16_MASK:
 			cluster = getushort(bp->b_data + bo);
 			putushort(bp->b_data + bo, MSDOSFSFREE);
 			break;
 		case FAT32_MASK:
 			cluster = getulong(bp->b_data + bo);
 			putulong(bp->b_data + bo,
 				 (MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK));
 			break;
 		}
 		cluster &= pmp->pm_fatmask;
 		if ((cluster | ~pmp->pm_fatmask) >= CLUST_RSRVD)
 			cluster |= pmp->pm_fatmask;
 	}
 	if (bp)
 		updatefats(pmp, bp, bn);
 	return (0);
 }
 
 /*
  * Read in FAT blocks looking for free clusters. For every free cluster
  * found turn off its corresponding bit in the pm_inusemap.
  */
 int
 fillinusemap(struct msdosfsmount *pmp)
 {
-	struct buf *bp;
+	struct m_buf *bp;
 	u_long bn, bo, bsize, byteoffset, cn, readcn;
 	int error;
 
 	bp = NULL;
 
 	/*
 	 * Mark all clusters in use, we mark the free ones in the FAT scan
 	 * loop further down.
 	 */
 	for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++)
 		pmp->pm_inusemap[cn] = FULL_RUN;
 
 	/*
 	 * Figure how many free clusters are in the filesystem by ripping
 	 * through the FAT counting the number of entries whose content is
 	 * zero.  These represent free clusters.
 	 */
 	pmp->pm_freeclustercount = 0;
 	for (cn = 0; cn <= pmp->pm_maxcluster; cn++) {
 		byteoffset = FATOFS(pmp, cn);
 		bo = byteoffset % pmp->pm_fatblocksize;
 		if (bo == 0) {
 			/* Read new FAT block */
 			if (bp != NULL)
 				brelse(bp);
 			fatblock(pmp, byteoffset, &bn, &bsize, NULL);
-			error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
+			error = bread((void *)pmp->pm_devvp, bn, bsize,
+			    NOCRED, &bp);
 			if (error != 0)
 				return (error);
 		}
 		if (FAT32(pmp))
 			readcn = getulong(bp->b_data + bo);
 		else
 			readcn = getushort(bp->b_data + bo);
 		if (FAT12(pmp) && (cn & 1))
 			readcn >>= 4;
 		readcn &= pmp->pm_fatmask;
 
 		/*
 		 * Check if the FAT ID matches the BPB's media descriptor and
 		 * all other bits are set to 1.
 		 */
 		if (cn == 0 && readcn != ((pmp->pm_fatmask & 0xffffff00) |
 		    pmp->pm_bpb.bpbMedia)) {
 #ifdef MSDOSFS_DEBUG
 			printf("mountmsdosfs(): Media descriptor in BPB"
 			    "does not match FAT ID\n");
 #endif
 			brelse(bp);
 			return (EINVAL);
 		} else if (readcn == CLUST_FREE)
 			usemap_free(pmp, cn);
 	}
 	if (bp != NULL)
 		brelse(bp);
 
 	for (cn = pmp->pm_maxcluster + 1; cn < (pmp->pm_maxcluster +
 	    N_INUSEBITS) / N_INUSEBITS; cn++)
 		pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS);
 
 	return (0);
 }
 
 /*
  * Allocate a new cluster and chain it onto the end of the file.
  *
  * dep	 - the file to extend
  * count - number of clusters to allocate
  * bpp	 - where to return the address of the buf header for the first new
  *	   file block
  * ncp	 - where to put cluster number of the first newly allocated cluster
  *	   If this pointer is 0, do not return the cluster number.
  * flags - see fat.h
  *
  * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
  * the de_flag field of the denode and it does not change the de_FileSize
  * field.  This is left for the caller to do.
  */
 int
-extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp,
+m_extendfile(struct denode *dep, u_long count, struct m_buf **bpp, u_long *ncp,
     int flags)
 {
 	int error;
 	u_long frcn;
 	u_long cn, got;
 	struct msdosfsmount *pmp = dep->de_pmp;
-	struct buf *bp;
+	struct m_buf *bp;
 
 	/*
 	 * Don't try to extend the root directory
 	 */
 	if (dep->de_StartCluster == MSDOSFSROOT
 	    && (dep->de_Attributes & ATTR_DIRECTORY)) {
 #ifdef MSDOSFS_DEBUG
 		printf("extendfile(): attempt to extend root directory\n");
 #endif
 		return (ENOSPC);
 	}
 
 	/*
 	 * If the "file's last cluster" cache entry is empty, and the file
 	 * is not empty, then fill the cache entry by calling pcbmap().
 	 */
 	if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
 	    dep->de_StartCluster != 0) {
 		error = pcbmap(dep, 0xffff, 0, &cn, 0);
 		/* we expect it to return E2BIG */
 		if (error != E2BIG)
 			return (error);
 	}
 
 	dep->de_fc[FC_NEXTTOLASTFC].fc_frcn =
 	    dep->de_fc[FC_LASTFC].fc_frcn;
 	dep->de_fc[FC_NEXTTOLASTFC].fc_fsrcn =
 	    dep->de_fc[FC_LASTFC].fc_fsrcn;
 	while (count > 0) {
 		/*
 		 * Allocate a new cluster chain and cat onto the end of the
 		 * file.  If the file is empty we make de_StartCluster point
 		 * to the new block.  Note that de_StartCluster being 0 is
 		 * sufficient to be sure the file is empty since we exclude
 		 * attempts to extend the root directory above, and the root
 		 * dir is the only file with a startcluster of 0 that has
 		 * blocks allocated (sort of).
 		 */
 		if (dep->de_StartCluster == 0)
 			cn = 0;
 		else
 			cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1;
 		error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got);
 		if (error)
 			return (error);
 
 		count -= got;
 
 		/*
 		 * Give them the filesystem relative cluster number if they want
 		 * it.
 		 */
 		if (ncp) {
 			*ncp = cn;
 			ncp = NULL;
 		}
 
 		if (dep->de_StartCluster == 0) {
 			dep->de_StartCluster = cn;
 			frcn = 0;
 		} else {
 			error = fatentry(FAT_SET, pmp,
 					 dep->de_fc[FC_LASTFC].fc_fsrcn,
 					 0, cn);
 			if (error) {
 				clusterfree(pmp, cn, NULL);
 				return (error);
 			}
 			frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
 		}
 
 		/*
 		 * Update the "last cluster of the file" entry in the
 		 * denode's FAT cache.
 		 */
 		fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1);
 
 		if ((flags & DE_CLEAR) &&
 		    (dep->de_Attributes & ATTR_DIRECTORY)) {
 			while (got-- > 0) {
-				bp = getblk(pmp->pm_devvp,
+				bp = getblk((void *)pmp->pm_devvp,
 				    cntobn(pmp, cn++),
 				    pmp->pm_bpcluster, 0, 0, 0);
 				clrbuf(bp);
 				if (bpp) {
 					*bpp = bp;
 					bpp = NULL;
 				} else {
 					bdwrite(bp);
 				}
 			}
 		}
 	}
 
 	return (0);
 }
diff --git a/usr.sbin/makefs/msdos/msdosfs_lookup.c b/usr.sbin/makefs/msdos/msdosfs_lookup.c
index 27ce216a488f..3fca0532468b 100644
--- a/usr.sbin/makefs/msdos/msdosfs_lookup.c
+++ b/usr.sbin/makefs/msdos/msdosfs_lookup.c
@@ -1,302 +1,306 @@
 /* $FreeBSD$ */
 /*	$NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
  * All rights reserved.
  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by TooLs GmbH.
  * 4. The name of TooLs GmbH may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*-
  * Written by Paul Popelka (paulp@uts.amdahl.com)
  *
  * You can do anything you want with this software, just don't say you wrote
  * it, and don't remove this notice.
  *
  * This software is provided "as is".
  *
  * The author supplies this software to be publicly redistributed on the
  * understanding that the author is not responsible for the correct
  * functioning of this software in any circumstances and is not liable for
  * any damages caused by this software.
  *
  * October 1992
  */
 
 #include <sys/param.h>
 #include <sys/errno.h>
 
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "ffs/buf.h"
 #include <fs/msdosfs/bpb.h>
 #include "msdos/direntry.h"
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+#undef clrbuf
+#include "ffs/buf.h"
 #include "makefs.h"
 #include "msdos.h"
 
 /*
  * dep  - directory entry to copy into the directory
  * ddep - directory to add to
  * depp - return the address of the denode for the created directory entry
  *	  if depp != 0
  * cnp  - componentname needed for Win95 long filenames
  */
 int
 createde(struct denode *dep, struct denode *ddep, struct denode **depp,
     struct componentname *cnp)
 {
 	int error;
 	u_long dirclust, diroffset;
 	struct direntry *ndep;
 	struct msdosfsmount *pmp = ddep->de_pmp;
-	struct buf *bp;
+	struct m_buf *bp;
 	daddr_t bn;
 	int blsize;
 
 	MSDOSFS_DPRINTF(("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
 	    dep, ddep, depp, cnp));
 
 	/*
 	 * If no space left in the directory then allocate another cluster
 	 * and chain it onto the end of the file.  There is one exception
 	 * to this.  That is, if the root directory has no more space it
 	 * can NOT be expanded.  extendfile() checks for and fails attempts
 	 * to extend the root directory.  We just return an error in that
 	 * case.
 	 */
 	if (ddep->de_fndoffset >= ddep->de_FileSize) {
 		diroffset = ddep->de_fndoffset + sizeof(struct direntry)
 		    - ddep->de_FileSize;
 		dirclust = de_clcount(pmp, diroffset);
-		error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
+		error = m_extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
 		if (error) {
 			(void)detrunc(ddep, ddep->de_FileSize, 0, NULL);
 			return error;
 		}
 
 		/*
 		 * Update the size of the directory
 		 */
 		ddep->de_FileSize += de_cn2off(pmp, dirclust);
 	}
 
 	/*
 	 * We just read in the cluster with space.  Copy the new directory
 	 * entry in.  Then write it to disk. NOTE:  DOS directories
 	 * do not get smaller as clusters are emptied.
 	 */
 	error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
 		       &bn, &dirclust, &blsize);
 	if (error)
 		return error;
 	diroffset = ddep->de_fndoffset;
 	if (dirclust != MSDOSFSROOT)
 		diroffset &= pmp->pm_crbomask;
-	if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
+	if ((error = bread((void *)pmp->pm_devvp, bn, blsize, NOCRED,
+	    &bp)) != 0) {
 		brelse(bp);
 		return error;
 	}
 	ndep = bptoep(pmp, bp, ddep->de_fndoffset);
 
 	DE_EXTERNALIZE(ndep, dep);
 
 	/*
 	 * Now write the Win95 long name
 	 */
 	if (ddep->de_fndcnt > 0) {
 		uint8_t chksum = winChksum(ndep->deName);
 		const u_char *un = (const u_char *)cnp->cn_nameptr;
 		int unlen = cnp->cn_namelen;
 		int cnt = 1;
 
 		while (--ddep->de_fndcnt >= 0) {
 			if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
 				if ((error = bwrite(bp)) != 0)
 					return error;
 
 				ddep->de_fndoffset -= sizeof(struct direntry);
 				error = pcbmap(ddep,
 					       de_cluster(pmp,
 							  ddep->de_fndoffset),
 					       &bn, 0, &blsize);
 				if (error)
 					return error;
 
-				error = bread(pmp->pm_devvp, bn, blsize,
+				error = bread((void *)pmp->pm_devvp, bn, blsize,
 					      NOCRED, &bp);
 				if (error) {
 					brelse(bp);
 					return error;
 				}
 				ndep = bptoep(pmp, bp, ddep->de_fndoffset);
 			} else {
 				ndep--;
 				ddep->de_fndoffset -= sizeof(struct direntry);
 			}
 			if (!unix2winfn(un, unlen, (struct winentry *)ndep,
 					cnt++, chksum))
 				break;
 		}
 	}
 
 	if ((error = bwrite(bp)) != 0)
 		return error;
 
 	/*
 	 * If they want us to return with the denode gotten.
 	 */
 	if (depp) {
 		if (dep->de_Attributes & ATTR_DIRECTORY) {
 			dirclust = dep->de_StartCluster;
 			if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
 				dirclust = MSDOSFSROOT;
 			if (dirclust == MSDOSFSROOT)
 				diroffset = MSDOSFSROOT_OFS;
 			else
 				diroffset = 0;
 		}
 		return deget(pmp, dirclust, diroffset, depp);
 	}
 
 	return 0;
 }
 
 /*
  * Read in the disk block containing the directory entry (dirclu, dirofs)
  * and return the address of the buf header, and the address of the
  * directory entry within the block.
  */
 int
-readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
-    struct buf **bpp, struct direntry **epp)
+m_readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
+    struct m_buf **bpp, struct direntry **epp)
 {
 	int error;
 	daddr_t bn;
 	int blsize;
 
 	blsize = pmp->pm_bpcluster;
 	if (dirclust == MSDOSFSROOT
 	    && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
 		blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
 	bn = detobn(pmp, dirclust, diroffset);
-	if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
+	if ((error = bread((void *)pmp->pm_devvp, bn, blsize, NOCRED,
+	    bpp)) != 0) {
 		brelse(*bpp);
 		*bpp = NULL;
 		return (error);
 	}
 	if (epp)
 		*epp = bptoep(pmp, *bpp, diroffset);
 	return (0);
 }
 
 /*
  * Read in the disk block containing the directory entry dep came from and
  * return the address of the buf header, and the address of the directory
  * entry within the block.
  */
 int
-readde(struct denode *dep, struct buf **bpp, struct direntry **epp)
+m_readde(struct denode *dep, struct m_buf **bpp, struct direntry **epp)
 {
 
-	return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
+	return (m_readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
 	    bpp, epp));
 }
 
 /*
  * Create a unique DOS name in dvp
  */
 int
 uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp)
 {
 	struct msdosfsmount *pmp = dep->de_pmp;
 	struct direntry *dentp;
 	int gen;
 	int blsize;
 	u_long cn;
 	daddr_t bn;
-	struct buf *bp;
+	struct m_buf *bp;
 	int error;
 
 	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 		return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
 		    cnp->cn_namelen, 0) ? 0 : EINVAL);
 
 	for (gen = 1;; gen++) {
 		/*
 		 * Generate DOS name with generation number
 		 */
 		if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
 		    cnp->cn_namelen, gen))
 			return gen == 1 ? EINVAL : EEXIST;
 
 		/*
 		 * Now look for a dir entry with this exact name
 		 */
 		for (cn = error = 0; !error; cn++) {
 			if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
 				if (error == E2BIG)	/* EOF reached and not found */
 					return 0;
 				return error;
 			}
-			error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+			error = bread((void *)pmp->pm_devvp, bn, blsize,
+			    NOCRED, &bp);
 			if (error) {
 				brelse(bp);
 				return error;
 			}
 			for (dentp = (struct direntry *)bp->b_data;
 			     (char *)dentp < bp->b_data + blsize;
 			     dentp++) {
 				if (dentp->deName[0] == SLOT_EMPTY) {
 					/*
 					 * Last used entry and not found
 					 */
 					brelse(bp);
 					return 0;
 				}
 				/*
 				 * Ignore volume labels and Win95 entries
 				 */
 				if (dentp->deAttributes & ATTR_VOLUME)
 					continue;
 				if (!bcmp(dentp->deName, cp, 11)) {
 					error = EEXIST;
 					break;
 				}
 			}
 			brelse(bp);
 		}
 	}
 }
diff --git a/usr.sbin/makefs/msdos/msdosfs_vfsops.c b/usr.sbin/makefs/msdos/msdosfs_vfsops.c
index 07fc91cccd4a..b6788f6876f9 100644
--- a/usr.sbin/makefs/msdos/msdosfs_vfsops.c
+++ b/usr.sbin/makefs/msdos/msdosfs_vfsops.c
@@ -1,392 +1,391 @@
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
  * All rights reserved.
  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by TooLs GmbH.
  * 4. The name of TooLs GmbH may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*-
  * Written by Paul Popelka (paulp@uts.amdahl.com)
  *
  * You can do anything you want with this software, just don't say you wrote
  * it, and don't remove this notice.
  *
  * This software is provided "as is".
  *
  * The author supplies this software to be publicly redistributed on the
  * understanding that the author is not responsible for the correct
  * functioning of this software in any circumstances and is not liable for
  * any damages caused by this software.
  *
  * October 1992
  */
 
 #include <sys/cdefs.h>
 /* $NetBSD: msdosfs_vfsops.c,v 1.10 2016/01/30 09:59:27 mlelstv Exp $ */
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/mount.h>
 
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <util.h>
 
-#include "ffs/buf.h"
 #include <fs/msdosfs/bootsect.h>
 #include <fs/msdosfs/bpb.h>
 #include "msdos/direntry.h"
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
 #include <mkfs_msdos.h>
 
+#undef clrbuf
+#include "ffs/buf.h"
 #include "makefs.h"
 #include "msdos.h"
 
-
-
 struct msdosfsmount *
-msdosfs_mount(struct vnode *devvp)
+m_msdosfs_mount(struct m_vnode *devvp)
 {
 	struct msdosfsmount *pmp = NULL;
-	struct buf *bp;
+	struct m_buf *bp;
 	union bootsector *bsp;
 	struct byte_bpb33 *b33;
 	struct byte_bpb50 *b50;
 	struct byte_bpb710 *b710;
 	uint8_t SecPerClust;
 	int	ronly = 0, error;
 	int	bsize;
 	unsigned secsize = 512;
 
 	MSDOSFS_DPRINTF(("%s(bread 0)\n", __func__));
-	if ((error = bread(devvp, 0, secsize, 0, &bp)) != 0)
+	if ((error = bread((void *)devvp, 0, secsize, 0, &bp)) != 0)
 		goto error_exit;
 
 	bsp = (union bootsector *)bp->b_data;
 	b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
 	b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
 	b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
 
 	if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 ||
 	    bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
 		MSDOSFS_DPRINTF(("bootsig0 %d bootsig1 %d\n",
 		    bsp->bs50.bsBootSectSig0,
 		    bsp->bs50.bsBootSectSig1));
 		error = EINVAL;
 		goto error_exit;
 	}
 	bsize = 0;
 
 	pmp = ecalloc(1, sizeof(*pmp));
 	/*
 	 * Compute several useful quantities from the bpb in the
 	 * bootsector.  Copy in the dos 5 variant of the bpb then fix up
 	 * the fields that are different between dos 5 and dos 3.3.
 	 */
 	SecPerClust = b50->bpbSecPerClust;
 	pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
 	pmp->pm_ResSectors = getushort(b50->bpbResSectors);
 	pmp->pm_FATs = b50->bpbFATs;
 	pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
 	pmp->pm_Sectors = getushort(b50->bpbSectors);
 	pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
 	pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
 	pmp->pm_Heads = getushort(b50->bpbHeads);
 	pmp->pm_Media = b50->bpbMedia;
 
 	MSDOSFS_DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, "
 	    "RootDirEnts=%u, Sectors=%u, FATsecs=%lu, SecPerTrack=%u, "
 	    "Heads=%u, Media=%u)\n",
 	    __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors,
 	    pmp->pm_FATs, pmp->pm_RootDirEnts, pmp->pm_Sectors,
 	    pmp->pm_FATsecs, pmp->pm_SecPerTrack, pmp->pm_Heads,
 	    pmp->pm_Media));
 
 	/* XXX - We should probably check more values here */
 	if (!pmp->pm_BytesPerSec || !SecPerClust
 		|| pmp->pm_SecPerTrack > 63) {
 		MSDOSFS_DPRINTF(("bytespersec %d secperclust %d "
 		    "secpertrack %d\n", pmp->pm_BytesPerSec,
 		    SecPerClust, pmp->pm_SecPerTrack));
 		error = EINVAL;
 		goto error_exit;
 	}
 
 	if (pmp->pm_Sectors == 0) {
 		pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
 		pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
 	} else {
 		pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
 		pmp->pm_HugeSectors = pmp->pm_Sectors;
 	}
 
 	pmp->pm_flags = 0;
 	if (pmp->pm_RootDirEnts == 0) {
 		unsigned short vers = getushort(b710->bpbFSVers);
 		/*
 		 * Some say that bsBootSectSig[23] must be zero, but
 		 * Windows does not require this and some digital cameras
 		 * do not set these to zero.  Therefore, do not insist.
 		 */
 		if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) {
 			MSDOSFS_DPRINTF(("sectors %d fatsecs %lu vers %d\n",
 			    pmp->pm_Sectors, pmp->pm_FATsecs, vers));
 			error = EINVAL;
 			goto error_exit;
 		}
 		pmp->pm_fatmask = FAT32_MASK;
 		pmp->pm_fatmult = 4;
 		pmp->pm_fatdiv = 1;
 		pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
 
 		/* mirrorring is enabled if the FATMIRROR bit is not set */
 		if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0)
 			pmp->pm_flags |= MSDOSFS_FATMIRROR;
 		else
 			pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
 	} else
 		pmp->pm_flags |= MSDOSFS_FATMIRROR;
 
 	/* Check that fs has nonzero FAT size */
 	if (pmp->pm_FATsecs == 0) {
 		MSDOSFS_DPRINTF(("FATsecs is 0\n"));
 		error = EINVAL;
 		goto error_exit;
 	}
 
 	pmp->pm_fatblk = pmp->pm_ResSectors;
 	if (FAT32(pmp)) {
 		pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
 		pmp->pm_firstcluster = pmp->pm_fatblk
 			+ (pmp->pm_FATs * pmp->pm_FATsecs);
 		pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
 	} else {
 		pmp->pm_rootdirblk = pmp->pm_fatblk +
 			(pmp->pm_FATs * pmp->pm_FATsecs);
 		pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
 				       + pmp->pm_BytesPerSec - 1)
 			/ pmp->pm_BytesPerSec;/* in sectors */
 		pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
 	}
 
 	pmp->pm_maxcluster = ((pmp->pm_HugeSectors - pmp->pm_firstcluster) /
 	    SecPerClust) + 1;
 	pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
 
 	if (pmp->pm_fatmask == 0) {
 		if (pmp->pm_maxcluster
 		    <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
 			/*
 			 * This will usually be a floppy disk. This size makes
 			 * sure that one FAT entry will not be split across
 			 * multiple blocks.
 			 */
 			pmp->pm_fatmask = FAT12_MASK;
 			pmp->pm_fatmult = 3;
 			pmp->pm_fatdiv = 2;
 		} else {
 			pmp->pm_fatmask = FAT16_MASK;
 			pmp->pm_fatmult = 2;
 			pmp->pm_fatdiv = 1;
 		}
 	}
 	if (FAT12(pmp))
 		pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
 	else
 		pmp->pm_fatblocksize = MAXBSIZE;
 
 	pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
 	pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
 
 	/*
 	 * Compute mask and shift value for isolating cluster relative byte
 	 * offsets and cluster numbers from a file offset.
 	 */
 	pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
 	pmp->pm_crbomask = pmp->pm_bpcluster - 1;
 	pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
 
 	MSDOSFS_DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, "
 	    "fatblocksize=%lu, fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, "
 	    "crbomask=%lu, cnshift=%lu)\n",
 	    __func__, (unsigned long)pmp->pm_fatmask, pmp->pm_fatmult,
 	    pmp->pm_fatdiv, pmp->pm_fatblocksize, pmp->pm_fatblocksec,
 	    pmp->pm_bnshift, pmp->pm_bpcluster, pmp->pm_crbomask,
 	    pmp->pm_cnshift));
 	/*
 	 * Check for valid cluster size
 	 * must be a power of 2
 	 */
 	if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
 		MSDOSFS_DPRINTF(("bpcluster %lu cnshift %lu\n",
 		    pmp->pm_bpcluster, pmp->pm_cnshift));
 		error = EINVAL;
 		goto error_exit;
 	}
 
 	/*
 	 * Release the bootsector buffer.
 	 */
 	brelse(bp);
 	bp = NULL;
 
 	/*
 	 * Check FSInfo.
 	 */
 	if (pmp->pm_fsinfo) {
 		struct fsinfo *fp;
 
 		/*
 		 * XXX	If the fsinfo block is stored on media with
 		 *	2KB or larger sectors, is the fsinfo structure
 		 *	padded at the end or in the middle?
 		 */
-		if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec,
-		    0, &bp)) != 0)
+		if ((error = bread((void *)devvp, pmp->pm_fsinfo,
+		    pmp->pm_BytesPerSec, 0, &bp)) != 0)
 			goto error_exit;
 		fp = (struct fsinfo *)bp->b_data;
 		if (!memcmp(fp->fsisig1, "RRaA", 4)
 		    && !memcmp(fp->fsisig2, "rrAa", 4)
 		    && !memcmp(fp->fsisig3, "\0\0\125\252", 4))
 			pmp->pm_nxtfree = getulong(fp->fsinxtfree);
 		else
 			pmp->pm_fsinfo = 0;
 		brelse(bp);
 		bp = NULL;
 	}
 
 	/*
 	 * Check and validate (or perhaps invalidate?) the fsinfo structure?
 	 * XXX
 	 */
 	if (pmp->pm_fsinfo) {
 		if ((pmp->pm_nxtfree == 0xffffffffUL) ||
 		    (pmp->pm_nxtfree > pmp->pm_maxcluster))
 			pmp->pm_fsinfo = 0;
 	}
 
 	/*
 	 * Allocate memory for the bitmap of allocated clusters, and then
 	 * fill it in.
 	 */
 	pmp->pm_inusemap = ecalloc(sizeof(*pmp->pm_inusemap),
 	    ((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS));
 	/*
 	 * fillinusemap() needs pm_devvp.
 	 */
 	pmp->pm_dev = 0;
-	pmp->pm_devvp = devvp;
+	pmp->pm_devvp = (void *)devvp;
 
 	/*
 	 * Have the inuse map filled in.
 	 */
 	if ((error = fillinusemap(pmp)) != 0) {
 		MSDOSFS_DPRINTF(("fillinusemap %d\n", error));
 		goto error_exit;
 	}
 
 	/*
 	 * Finish up.
 	 */
 	if (ronly)
 		pmp->pm_flags |= MSDOSFSMNT_RONLY;
 	else
 		pmp->pm_fmod = 1;
 
 	/*
 	 * If we ever do quotas for DOS filesystems this would be a place
 	 * to fill in the info in the msdosfsmount structure. You dolt,
 	 * quotas on dos filesystems make no sense because files have no
 	 * owners on dos filesystems. of course there is some empty space
 	 * in the directory entry where we could put uid's and gid's.
 	 */
 
 	return pmp;
 
 error_exit:
 	if (bp)
 		brelse(bp);
 	if (pmp) {
 		if (pmp->pm_inusemap)
 			free(pmp->pm_inusemap);
 		free(pmp);
 	}
 	errno = error;
 	return NULL;
 }
 
 int
-msdosfs_root(struct msdosfsmount *pmp, struct vnode *vp) {
+msdosfs_root(struct msdosfsmount *pmp, struct m_vnode *vp) {
 	struct denode *ndep;
 	int error;
 
-	*vp = *pmp->pm_devvp;
+	*vp = *(struct m_vnode *)pmp->pm_devvp;
 	if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) {
 		errno = error;
 		return -1;
 	}
 	vp->v_data = ndep;
 	return 0;
 }
 
 /*
  * If we have an FSInfo block, update it.
  */
 int
 msdosfs_fsiflush(struct msdosfsmount *pmp)
 {
 	struct fsinfo *fp;
-	struct buf *bp;
+	struct m_buf *bp;
 	int error;
 
 	if (pmp->pm_fsinfo == 0 || (pmp->pm_flags & MSDOSFS_FSIMOD) == 0) {
 		error = 0;
 		goto out;
 	}
-	error = bread(pmp->pm_devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec,
-	    NOCRED, &bp);
+	error = bread((void *)pmp->pm_devvp, pmp->pm_fsinfo,
+	    pmp->pm_BytesPerSec, NOCRED, &bp);
 	if (error != 0) {
 		brelse(bp);
 		goto out;
 	}
 	fp = (struct fsinfo *)bp->b_data;
 	putulong(fp->fsinfree, pmp->pm_freeclustercount);
 	putulong(fp->fsinxtfree, pmp->pm_nxtfree);
 	pmp->pm_flags &= ~MSDOSFS_FSIMOD;
 	error = bwrite(bp);
 
 out:
 	return (error);
 }
diff --git a/usr.sbin/makefs/msdos/msdosfs_vnops.c b/usr.sbin/makefs/msdos/msdosfs_vnops.c
index 8bd4d3d498d8..2233c4b35eb2 100644
--- a/usr.sbin/makefs/msdos/msdosfs_vnops.c
+++ b/usr.sbin/makefs/msdos/msdosfs_vnops.c
@@ -1,644 +1,646 @@
 /*	$NetBSD: msdosfs_vnops.c,v 1.19 2017/04/13 17:10:12 christos Exp $ */
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
  *
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
  * All rights reserved.
  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
  *	This product includes software developed by TooLs GmbH.
  * 4. The name of TooLs GmbH may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 /*-
  * Written by Paul Popelka (paulp@uts.amdahl.com)
  *
  * You can do anything you want with this software, just don't say you wrote
  * it, and don't remove this notice.
  *
  * This software is provided "as is".
  *
  * The author supplies this software to be publicly redistributed on the
  * understanding that the author is not responsible for the correct
  * functioning of this software in any circumstances and is not liable for
  * any damages caused by this software.
  *
  * October 1992
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <sys/mman.h>
 #include <sys/time.h>
 
 #include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
-#include "ffs/buf.h"
 #include <fs/msdosfs/bpb.h>
 #include "msdos/direntry.h"
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+#undef clrbuf
+#include "ffs/buf.h"
 #include "makefs.h"
 #include "msdos.h"
 
 /*
  * Some general notes:
  *
  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
  * read/written using the vnode for the filesystem. Blocks that represent
  * the contents of a file are read/written using the vnode for the file
  * (including directories when they are read/written as files). This
  * presents problems for the dos filesystem because data that should be in
  * an inode (if dos had them) resides in the directory itself.	Since we
  * must update directory entries without the benefit of having the vnode
  * for the directory we must use the vnode for the filesystem.	This means
  * that when a directory is actually read/written (via read, write, or
  * readdir, or seek) we must use the vnode for the filesystem instead of
  * the vnode for the directory as would happen in ufs. This is to insure we
  * retrieve the correct block from the buffer cache since the hash value is
  * based upon the vnode address and the desired block number.
  */
 
 static int msdosfs_wfile(const char *, struct denode *, fsnode *);
 static void unix2fattime(const struct timespec *tsp, uint16_t *ddp,
     uint16_t *dtp);
 
 static void
 msdosfs_times(struct denode *dep, const struct stat *st)
 {
 	if (stampst.st_ino)
 		st = &stampst;
 
 #ifdef HAVE_STRUCT_STAT_BIRTHTIME
 	unix2fattime(&st->st_birthtim, &dep->de_CDate, &dep->de_CTime);
 #else
 	unix2fattime(&st->st_ctim, &dep->de_CDate, &dep->de_CTime);
 #endif
 	unix2fattime(&st->st_atim, &dep->de_ADate, NULL);
 	unix2fattime(&st->st_mtim, &dep->de_MDate, &dep->de_MTime);
 }
 
 static void
 unix2fattime(const struct timespec *tsp, uint16_t *ddp, uint16_t *dtp)
 {
 	time_t t1;
 	struct tm lt = {0};
 
 	t1 = tsp->tv_sec;
 	localtime_r(&t1, &lt);
 
 	unsigned long fat_time = ((lt.tm_year - 80) << 25) |
             ((lt.tm_mon + 1) << 21) |
             (lt.tm_mday << 16) |
             (lt.tm_hour << 11) |
             (lt.tm_min << 5) |
             (lt.tm_sec >> 1);
 
 	if (ddp != NULL)
 		*ddp = (uint16_t)(fat_time >> 16);
 	if (dtp != NULL)
 		*dtp = (uint16_t)fat_time;
 }
 
 /*
  * When we search a directory the blocks containing directory entries are
  * read and examined.  The directory entries contain information that would
  * normally be in the inode of a unix filesystem.  This means that some of
  * a directory's contents may also be in memory resident denodes (sort of
  * an inode).  This can cause problems if we are searching while some other
  * process is modifying a directory.  To prevent one process from accessing
  * incompletely modified directory information we depend upon being the
  * sole owner of a directory block.  bread/brelse provide this service.
  * This being the case, when a process modifies a directory it must first
  * acquire the disk block that contains the directory entry to be modified.
  * Then update the disk block and the denode, and then write the disk block
  * out to disk.	 This way disk blocks containing directory entries and in
  * memory denode's will be in synch.
  */
 static int
 msdosfs_findslot(struct denode *dp, struct componentname *cnp)
 {
 	daddr_t bn;
 	int error;
 	int slotcount;
 	int slotoffset = 0;
 	int frcn;
 	u_long cluster;
 	int blkoff;
 	u_int diroff;
 	int blsize;
 	struct msdosfsmount *pmp;
-	struct buf *bp = 0;
+	struct m_buf *bp = 0;
 	struct direntry *dep;
 	u_char dosfilename[12];
 	int wincnt = 1;
 	int chksum = -1, chksum_ok;
 	int olddos = 1;
 
 	pmp = dp->de_pmp;
 
 	switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
 	    cnp->cn_namelen, 0)) {
 	case 0:
 		return (EINVAL);
 	case 1:
 		break;
 	case 2:
 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
 		    cnp->cn_namelen) + 1;
 		break;
 	case 3:
 		olddos = 0;
 		wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
 		    cnp->cn_namelen) + 1;
 		break;
 	}
 
 	if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 		wincnt = 1;
 
 	/*
 	 * Suppress search for slots unless creating
 	 * file and at end of pathname, in which case
 	 * we watch for a place to put the new file in
 	 * case it doesn't already exist.
 	 */
 	slotcount = 0;
 	MSDOSFS_DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename));
 	/*
 	 * Search the directory pointed at by vdp for the name pointed at
 	 * by cnp->cn_nameptr.
 	 */
 	/*
 	 * The outer loop ranges over the clusters that make up the
 	 * directory.  Note that the root directory is different from all
 	 * other directories.  It has a fixed number of blocks that are not
 	 * part of the pool of allocatable clusters.  So, we treat it a
 	 * little differently. The root directory starts at "cluster" 0.
 	 */
 	diroff = 0;
 	for (frcn = 0; diroff < dp->de_FileSize; frcn++) {
 		if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
 			if (error == E2BIG)
 				break;
 			return (error);
 		}
-		error = bread(pmp->pm_devvp, bn, blsize, 0, &bp);
+		error = bread((void *)pmp->pm_devvp, bn, blsize, 0, &bp);
 		if (error) {
 			return (error);
 		}
 		for (blkoff = 0; blkoff < blsize;
 		     blkoff += sizeof(struct direntry),
 		     diroff += sizeof(struct direntry)) {
 			dep = (struct direntry *)(bp->b_data + blkoff);
 			/*
 			 * If the slot is empty and we are still looking
 			 * for an empty then remember this one.	 If the
 			 * slot is not empty then check to see if it
 			 * matches what we are looking for.  If the slot
 			 * has never been filled with anything, then the
 			 * remainder of the directory has never been used,
 			 * so there is no point in searching it.
 			 */
 			if (dep->deName[0] == SLOT_EMPTY ||
 			    dep->deName[0] == SLOT_DELETED) {
 				/*
 				 * Drop memory of previous long matches
 				 */
 				chksum = -1;
 
 				if (slotcount < wincnt) {
 					slotcount++;
 					slotoffset = diroff;
 				}
 				if (dep->deName[0] == SLOT_EMPTY) {
 					brelse(bp);
 					goto notfound;
 				}
 			} else {
 				/*
 				 * If there wasn't enough space for our
 				 * winentries, forget about the empty space
 				 */
 				if (slotcount < wincnt)
 					slotcount = 0;
 
 				/*
 				 * Check for Win95 long filename entry
 				 */
 				if (dep->deAttributes == ATTR_WIN95) {
 					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 						continue;
 
 					chksum = winChkName(
 					    (const u_char *)cnp->cn_nameptr,
 					    cnp->cn_namelen,
 					    (struct winentry *)dep, chksum);
 					continue;
 				}
 
 				/*
 				 * Ignore volume labels (anywhere, not just
 				 * the root directory).
 				 */
 				if (dep->deAttributes & ATTR_VOLUME) {
 					chksum = -1;
 					continue;
 				}
 
 				/*
 				 * Check for a checksum or name match
 				 */
 				chksum_ok = (chksum == winChksum(dep->deName));
 				if (!chksum_ok
 				    && (!olddos || memcmp(dosfilename, dep->deName, 11))) {
 					chksum = -1;
 					continue;
 				}
 				MSDOSFS_DPRINTF(("%s(): match blkoff %d, diroff %u\n",
 				    __func__, blkoff, diroff));
 				/*
 				 * Remember where this directory
 				 * entry came from for whoever did
 				 * this lookup.
 				 */
 				dp->de_fndoffset = diroff;
 				dp->de_fndcnt = 0;
 
 				return EEXIST;
 			}
 		}	/* for (blkoff = 0; .... */
 		/*
 		 * Release the buffer holding the directory cluster just
 		 * searched.
 		 */
 		brelse(bp);
 	}	/* for (frcn = 0; ; frcn++) */
 
 notfound:
 	/*
 	 * We hold no disk buffers at this point.
 	 */
 
 	/*
 	 * If we get here we didn't find the entry we were looking for. But
 	 * that's ok if we are creating or renaming and are at the end of
 	 * the pathname and the directory hasn't been removed.
 	 */
 	MSDOSFS_DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n",
 	    __func__, dp->de_refcnt, slotcount, slotoffset));
 	/*
 	 * Fixup the slot description to point to the place where
 	 * we might put the new DOS direntry (putting the Win95
 	 * long name entries before that)
 	 */
 	if (!slotcount) {
 		slotcount = 1;
 		slotoffset = diroff;
 	}
 	if (wincnt > slotcount) {
 		slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
 	}
 
 	/*
 	 * Return an indication of where the new directory
 	 * entry should be put.
 	 */
 	dp->de_fndoffset = slotoffset;
 	dp->de_fndcnt = wincnt - 1;
 
 	/*
 	 * We return with the directory locked, so that
 	 * the parameters we set up above will still be
 	 * valid if we actually decide to do a direnter().
 	 * We return ni_vp == NULL to indicate that the entry
 	 * does not currently exist; we leave a pointer to
 	 * the (locked) directory inode in ndp->ni_dvp.
 	 *
 	 * NB - if the directory is unlocked, then this
 	 * information cannot be used.
 	 */
 	return 0;
 }
 
 /*
  * Create a regular file. On entry the directory to contain the file being
  * created is locked.  We must release before we return.
  */
 struct denode *
 msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
 {
 	struct componentname cn;
 	struct denode ndirent;
 	struct denode *dep;
 	int error;
 	struct stat *st = &node->inode->st;
 
 	cn.cn_nameptr = node->name;
 	cn.cn_namelen = strlen(node->name);
 
 	MSDOSFS_DPRINTF(("%s(name %s, mode 0%o size %zu)\n",
 	    __func__, node->name, st->st_mode, (size_t)st->st_size));
 
 	/*
 	 * If this is the root directory and there is no space left we
 	 * can't do anything.  This is because the root directory can not
 	 * change size.
 	 */
 	if (pdep->de_StartCluster == MSDOSFSROOT
 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
 		error = ENOSPC;
 		goto bad;
 	}
 
 	/*
 	 * Create a directory entry for the file, then call createde() to
 	 * have it installed. NOTE: DOS files are always executable.  We
 	 * use the absence of the owner write bit to make the file
 	 * readonly.
 	 */
 	memset(&ndirent, 0, sizeof(ndirent));
 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
 		goto bad;
 
 	ndirent.de_Attributes = (st->st_mode & S_IWUSR) ?
 				ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
 	ndirent.de_StartCluster = 0;
 	ndirent.de_FileSize = 0;
 	ndirent.de_pmp = pdep->de_pmp;
 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
 	msdosfs_times(&ndirent, &node->inode->st);
 
 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
 		goto bad;
 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
 		goto bad;
 	if ((error = msdosfs_wfile(path, dep, node)) != 0)
 		goto bad;
 	return dep;
 
 bad:
 	errno = error;
 	return NULL;
 }
 static int
 msdosfs_updatede(struct denode *dep)
 {
-	struct buf *bp;
+	struct m_buf *bp;
 	struct direntry *dirp;
 	int error;
 
 	dep->de_flag &= ~DE_MODIFIED;
-	error = readde(dep, &bp, &dirp);
+	error = m_readde(dep, &bp, &dirp);
 	if (error)
 		return error;
 	DE_EXTERNALIZE(dirp, dep);
 	error = bwrite(bp);
 	return error;
 }
 
 /*
  * Write data to a file or directory.
  */
 static int
 msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
 {
 	int error, fd;
 	size_t osize = dep->de_FileSize;
 	struct stat *st = &node->inode->st;
 	size_t nsize, offs;
 	struct msdosfsmount *pmp = dep->de_pmp;
-	struct buf *bp;
+	struct m_buf *bp;
 	char *dat;
 	u_long cn = 0;
 
 	error = 0;	/* XXX: gcc/vax */
 	MSDOSFS_DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n",
 	    __func__, dep->de_diroffset, dep->de_dirclust,
 	    dep->de_StartCluster));
 	if (st->st_size == 0)
 		return 0;
 
 	/* Don't bother to try to write files larger than the fs limit */
 	if (st->st_size > MSDOSFS_FILESIZE_MAX)
 		return EFBIG;
 
 	nsize = st->st_size;
 	MSDOSFS_DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize));
 	if (nsize > osize) {
 		if ((error = deextend(dep, nsize, NULL)) != 0)
 			return error;
 		if ((error = msdosfs_updatede(dep)) != 0)
 			return error;
 	}
 
 	if ((fd = open(path, O_RDONLY)) == -1) {
 		error = errno;
 		fprintf(stderr, "open %s: %s\n", path, strerror(error));
 		return error;
 	}
 
 	if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0))
 	    == MAP_FAILED) {
 		error = errno;
 		fprintf(stderr, "%s: mmap %s: %s\n", __func__, node->name,
 		    strerror(error));
 		close(fd);
 		goto out;
 	}
 	close(fd);
 
 	for (offs = 0; offs < nsize;) {
 		int blsize, cpsize;
 		daddr_t bn;
 		u_long on = offs & pmp->pm_crbomask;
 
 		if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) {
 			MSDOSFS_DPRINTF(("%s: pcbmap %lu",
 			    __func__, (unsigned long)bn));
 			goto out;
 		}
 
 		MSDOSFS_DPRINTF(("%s(cn=%lu, bn=%llu, blsize=%d)\n",
 		    __func__, cn, (unsigned long long)bn, blsize));
-		if ((error = bread(pmp->pm_devvp, bn, blsize, 0, &bp)) != 0) {
+		if ((error = bread((void *)pmp->pm_devvp, bn, blsize, 0,
+		    &bp)) != 0) {
 			MSDOSFS_DPRINTF(("bread %d\n", error));
 			goto out;
 		}
 		cpsize = MIN((nsize - offs), blsize - on);
 		memcpy(bp->b_data + on, dat + offs, cpsize);
 		bwrite(bp);
 		offs += cpsize;
 	}
 
 	munmap(dat, nsize);
 	return 0;
 out:
 	munmap(dat, nsize);
 	return error;
 }
 
 static const struct {
 	struct direntry dot;
 	struct direntry dotdot;
 } dosdirtemplate = {
 	{	".          ",				/* the . entry */
 		ATTR_DIRECTORY,				/* file attribute */
 		0,					/* reserved */
 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
 		{ 0, 0 },				/* access date */
 		{ 0, 0 },				/* high bits of start cluster */
 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
 		{ 0, 0 },				/* startcluster */
 		{ 0, 0, 0, 0 }				/* filesize */
 	},
 	{	"..         ",				/* the .. entry */
 		ATTR_DIRECTORY,				/* file attribute */
 		0,					/* reserved */
 		0, { 0, 0 }, { 0, 0 },			/* create time & date */
 		{ 0, 0 },				/* access date */
 		{ 0, 0 },				/* high bits of start cluster */
 		{ 210, 4 }, { 210, 4 },			/* modify time & date */
 		{ 0, 0 },				/* startcluster */
 		{ 0, 0, 0, 0 }				/* filesize */
 	}
 };
 
 struct denode *
 msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
 	struct denode ndirent;
 	struct denode *dep;
 	struct componentname cn;
 	struct msdosfsmount *pmp = pdep->de_pmp;
 	int error;
 	u_long newcluster, pcl, bn;
 	struct direntry *denp;
-	struct buf *bp;
+	struct m_buf *bp;
 
 	cn.cn_nameptr = node->name;
 	cn.cn_namelen = strlen(node->name);
 	/*
 	 * If this is the root directory and there is no space left we
 	 * can't do anything.  This is because the root directory can not
 	 * change size.
 	 */
 	if (pdep->de_StartCluster == MSDOSFSROOT
 	    && pdep->de_fndoffset >= pdep->de_FileSize) {
 		error = ENOSPC;
 		goto bad2;
 	}
 
 	/*
 	 * Allocate a cluster to hold the about to be created directory.
 	 */
 	error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
 	if (error)
 		goto bad2;
 
 	memset(&ndirent, 0, sizeof(ndirent));
 	ndirent.de_pmp = pmp;
 	ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
 	msdosfs_times(&ndirent, &node->inode->st);
 
 	/*
 	 * Now fill the cluster with the "." and ".." entries. And write
 	 * the cluster to disk.	 This way it is there for the parent
 	 * directory to be pointing at if there were a crash.
 	 */
 	bn = cntobn(pmp, newcluster);
 	MSDOSFS_DPRINTF(("%s(newcluster %lu, bn=%lu)\n",
 	    __func__, newcluster, bn));
 	/* always succeeds */
-	bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, 0);
+	bp = getblk((void *)pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, 0);
 	memset(bp->b_data, 0, pmp->pm_bpcluster);
 	memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
 	denp = (struct direntry *)bp->b_data;
 	putushort(denp[0].deStartCluster, newcluster);
 	putushort(denp[0].deCDate, ndirent.de_CDate);
 	putushort(denp[0].deCTime, ndirent.de_CTime);
 	denp[0].deCHundredth = ndirent.de_CHun;
 	putushort(denp[0].deADate, ndirent.de_ADate);
 	putushort(denp[0].deMDate, ndirent.de_MDate);
 	putushort(denp[0].deMTime, ndirent.de_MTime);
 	pcl = pdep->de_StartCluster;
 	MSDOSFS_DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl,
 	    pmp->pm_rootdirblk));
 	if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
 		pcl = 0;
 	putushort(denp[1].deStartCluster, pcl);
 	putushort(denp[1].deCDate, ndirent.de_CDate);
 	putushort(denp[1].deCTime, ndirent.de_CTime);
 	denp[1].deCHundredth = ndirent.de_CHun;
 	putushort(denp[1].deADate, ndirent.de_ADate);
 	putushort(denp[1].deMDate, ndirent.de_MDate);
 	putushort(denp[1].deMTime, ndirent.de_MTime);
 	if (FAT32(pmp)) {
 		putushort(denp[0].deHighClust, newcluster >> 16);
 		putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
 	} else {
 		putushort(denp[0].deHighClust, 0);
 		putushort(denp[1].deHighClust, 0);
 	}
 
 	if ((error = bwrite(bp)) != 0)
 		goto bad;
 
 	/*
 	 * Now build up a directory entry pointing to the newly allocated
 	 * cluster.  This will be written to an empty slot in the parent
 	 * directory.
 	 */
 	if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0)
 		goto bad;
 
 	ndirent.de_Attributes = ATTR_DIRECTORY;
 	ndirent.de_StartCluster = newcluster;
 	ndirent.de_FileSize = 0;
 	ndirent.de_pmp = pdep->de_pmp;
 	if ((error = msdosfs_findslot(pdep, &cn)) != 0)
 		goto bad;
 	if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0)
 		goto bad;
 	if ((error = msdosfs_updatede(dep)) != 0)
 		goto bad;
 	return dep;
 
 bad:
 	clusterfree(pmp, newcluster, NULL);
 bad2:
 	errno = error;
 	return NULL;
 }