xref: /freebsd/sys/ufs/ffs/ffs_vfsops.c (revision 2f9bae59d66ce0d8d74807af1036164af819f415)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1989, 1991, 1993, 1994
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33df8bae1dSRodney W. Grimes  *	@(#)ffs_vfsops.c	8.8 (Berkeley) 4/18/94
342f9bae59SDavid Greenman  * $Id: ffs_vfsops.c,v 1.38 1996/03/02 22:18:34 dyson Exp $
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
3701733a9bSGarrett Wollman #include "opt_quota.h"
3801733a9bSGarrett Wollman 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
40df8bae1dSRodney W. Grimes #include <sys/systm.h>
41df8bae1dSRodney W. Grimes #include <sys/namei.h>
42df8bae1dSRodney W. Grimes #include <sys/proc.h>
43df8bae1dSRodney W. Grimes #include <sys/kernel.h>
44df8bae1dSRodney W. Grimes #include <sys/vnode.h>
45df8bae1dSRodney W. Grimes #include <sys/socket.h>
46df8bae1dSRodney W. Grimes #include <sys/mount.h>
47df8bae1dSRodney W. Grimes #include <sys/buf.h>
48df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
49df8bae1dSRodney W. Grimes #include <sys/file.h>
50df8bae1dSRodney W. Grimes #include <sys/disklabel.h>
51df8bae1dSRodney W. Grimes #include <sys/ioctl.h>
52df8bae1dSRodney W. Grimes #include <sys/errno.h>
53df8bae1dSRodney W. Grimes #include <sys/malloc.h>
54df8bae1dSRodney W. Grimes 
55df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h>
56df8bae1dSRodney W. Grimes 
57df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h>
58df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h>
59df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h>
60df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h>
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h>
63df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h>
64df8bae1dSRodney W. Grimes 
65f6b04d2bSDavid Greenman #include <vm/vm.h>
66efeaf95aSDavid Greenman #include <vm/vm_param.h>
67efeaf95aSDavid Greenman #include <vm/vm_prot.h>
68f6b04d2bSDavid Greenman #include <vm/vm_page.h>
69f6b04d2bSDavid Greenman #include <vm/vm_object.h>
70f6b04d2bSDavid Greenman 
71b8dce649SPoul-Henning Kamp static int	ffs_sbupdate __P((struct ufsmount *, int));
72b8dce649SPoul-Henning Kamp static int	ffs_reload __P((struct mount *,struct ucred *,struct proc *));
73b8dce649SPoul-Henning Kamp static int	ffs_oldfscompat __P((struct fs *));
74b8dce649SPoul-Henning Kamp static int	ffs_mount __P((struct mount *,
75b8dce649SPoul-Henning Kamp 	    char *, caddr_t, struct nameidata *, struct proc *));
76df8bae1dSRodney W. Grimes 
77df8bae1dSRodney W. Grimes struct vfsops ufs_vfsops = {
78df8bae1dSRodney W. Grimes 	ffs_mount,
79df8bae1dSRodney W. Grimes 	ufs_start,
80df8bae1dSRodney W. Grimes 	ffs_unmount,
81df8bae1dSRodney W. Grimes 	ufs_root,
82df8bae1dSRodney W. Grimes 	ufs_quotactl,
83df8bae1dSRodney W. Grimes 	ffs_statfs,
84df8bae1dSRodney W. Grimes 	ffs_sync,
85df8bae1dSRodney W. Grimes 	ffs_vget,
86df8bae1dSRodney W. Grimes 	ffs_fhtovp,
87df8bae1dSRodney W. Grimes 	ffs_vptofh,
88df8bae1dSRodney W. Grimes 	ffs_init,
89df8bae1dSRodney W. Grimes };
90df8bae1dSRodney W. Grimes 
91862cdb8eSGarrett Wollman VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0);
92c901836cSGarrett Wollman 
93df8bae1dSRodney W. Grimes extern u_long nextgennumber;
94df8bae1dSRodney W. Grimes 
952b14f991SJulian Elischer 
96df8bae1dSRodney W. Grimes /*
972b14f991SJulian Elischer  * ffs_mount
98df8bae1dSRodney W. Grimes  *
992b14f991SJulian Elischer  * Called when mounting local physical media
100df8bae1dSRodney W. Grimes  *
1012b14f991SJulian Elischer  * PARAMETERS:
1022b14f991SJulian Elischer  *		mountroot
1032b14f991SJulian Elischer  *			mp	mount point structure
1042b14f991SJulian Elischer  *			path	NULL (flag for root mount!!!)
1052b14f991SJulian Elischer  *			data	<unused>
1062b14f991SJulian Elischer  *			ndp	<unused>
1072b14f991SJulian Elischer  *			p	process (user credentials check [statfs])
1082b14f991SJulian Elischer  *
1092b14f991SJulian Elischer  *		mount
1102b14f991SJulian Elischer  *			mp	mount point structure
1112b14f991SJulian Elischer  *			path	path to mount point
1122b14f991SJulian Elischer  *			data	pointer to argument struct in user space
1132b14f991SJulian Elischer  *			ndp	mount point namei() return (used for
1142b14f991SJulian Elischer  *				credentials on reload), reused to look
1152b14f991SJulian Elischer  *				up block device.
1162b14f991SJulian Elischer  *			p	process (user credentials check)
1172b14f991SJulian Elischer  *
1182b14f991SJulian Elischer  * RETURNS:	0	Success
1192b14f991SJulian Elischer  *		!0	error number (errno.h)
1202b14f991SJulian Elischer  *
1212b14f991SJulian Elischer  * LOCK STATE:
1222b14f991SJulian Elischer  *
1232b14f991SJulian Elischer  *		ENTRY
1242b14f991SJulian Elischer  *			mount point is locked
1252b14f991SJulian Elischer  *		EXIT
1262b14f991SJulian Elischer  *			mount point is locked
1272b14f991SJulian Elischer  *
1282b14f991SJulian Elischer  * NOTES:
1292b14f991SJulian Elischer  *		A NULL path can be used for a flag since the mount
1302b14f991SJulian Elischer  *		system call will fail with EFAULT in copyinstr in
1312b14f991SJulian Elischer  *		namei() if it is a genuine NULL from the user.
132df8bae1dSRodney W. Grimes  */
133b8dce649SPoul-Henning Kamp static int
134df8bae1dSRodney W. Grimes ffs_mount( mp, path, data, ndp, p)
1352b14f991SJulian Elischer         register struct mount	*mp;	/* mount struct pointer*/
1362b14f991SJulian Elischer         char			*path;	/* path to mount point*/
1372b14f991SJulian Elischer         caddr_t			data;	/* arguments to FS specific mount*/
1382b14f991SJulian Elischer         struct nameidata	*ndp;	/* mount point credentials*/
1392b14f991SJulian Elischer         struct proc		*p;	/* process requesting mount*/
140df8bae1dSRodney W. Grimes {
1412b14f991SJulian Elischer 	u_int		size;
1422b14f991SJulian Elischer 	int		err = 0;
143df8bae1dSRodney W. Grimes 	struct vnode	*devvp;
1442b14f991SJulian Elischer 
145df8bae1dSRodney W. Grimes 	struct ufs_args args;
14626f9a767SRodney W. Grimes 	struct ufsmount *ump = 0;
147df8bae1dSRodney W. Grimes 	register struct fs *fs;
1482b14f991SJulian Elischer 	int flags;
149df8bae1dSRodney W. Grimes 
1502b14f991SJulian Elischer 	/*
1512b14f991SJulian Elischer 	 * Use NULL path to flag a root mount
1522b14f991SJulian Elischer 	 */
1532b14f991SJulian Elischer 	if( path == NULL) {
1542b14f991SJulian Elischer 		/*
1552b14f991SJulian Elischer 		 ***
1562b14f991SJulian Elischer 		 * Mounting root file system
1572b14f991SJulian Elischer 		 ***
1582b14f991SJulian Elischer 		 */
1592b14f991SJulian Elischer 
1602b14f991SJulian Elischer 		/* Get vnode for root device*/
1612b14f991SJulian Elischer 		if( bdevvp( rootdev, &rootvp))
1622b14f991SJulian Elischer 			panic("ffs_mountroot: can't setup bdevvp for root");
1632b14f991SJulian Elischer 
1642b14f991SJulian Elischer 		/*
1652b14f991SJulian Elischer 		 * FS specific handling
1662b14f991SJulian Elischer 		 */
1672b14f991SJulian Elischer 		mp->mnt_flag |= MNT_RDONLY;	/* XXX globally applicable?*/
1682b14f991SJulian Elischer 
1692b14f991SJulian Elischer 		/*
1702b14f991SJulian Elischer 		 * Attempt mount
1712b14f991SJulian Elischer 		 */
1722b14f991SJulian Elischer 		if( ( err = ffs_mountfs(rootvp, mp, p)) != 0) {
1732b14f991SJulian Elischer 			/* fs specific cleanup (if any)*/
1742b14f991SJulian Elischer 			goto error_1;
1752b14f991SJulian Elischer 		}
1762b14f991SJulian Elischer 
1772b14f991SJulian Elischer 		goto dostatfs;		/* success*/
1782b14f991SJulian Elischer 
1792b14f991SJulian Elischer 	}
1802b14f991SJulian Elischer 
1812b14f991SJulian Elischer 	/*
1822b14f991SJulian Elischer 	 ***
1832b14f991SJulian Elischer 	 * Mounting non-root file system or updating a file system
1842b14f991SJulian Elischer 	 ***
1852b14f991SJulian Elischer 	 */
1862b14f991SJulian Elischer 
1872b14f991SJulian Elischer 	/* copy in user arguments*/
1882b14f991SJulian Elischer 	err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
1892b14f991SJulian Elischer 	if (err)
1902b14f991SJulian Elischer 		goto error_1;		/* can't get arguments*/
1912b14f991SJulian Elischer 
192df8bae1dSRodney W. Grimes 	/*
193df8bae1dSRodney W. Grimes 	 * If updating, check whether changing from read-only to
194df8bae1dSRodney W. Grimes 	 * read/write; if there is no device name, that's all we do.
195df8bae1dSRodney W. Grimes 	 */
196df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_UPDATE) {
197df8bae1dSRodney W. Grimes 		ump = VFSTOUFS(mp);
198df8bae1dSRodney W. Grimes 		fs = ump->um_fs;
1992b14f991SJulian Elischer 		err = 0;
200df8bae1dSRodney W. Grimes 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
201df8bae1dSRodney W. Grimes 			flags = WRITECLOSE;
202df8bae1dSRodney W. Grimes 			if (mp->mnt_flag & MNT_FORCE)
203df8bae1dSRodney W. Grimes 				flags |= FORCECLOSE;
2042b14f991SJulian Elischer 			if (vfs_busy(mp)) {
2052b14f991SJulian Elischer 				err = EBUSY;
2062b14f991SJulian Elischer 				goto error_1;
2072b14f991SJulian Elischer 			}
2082b14f991SJulian Elischer 			err = ffs_flushfiles(mp, flags, p);
209df8bae1dSRodney W. Grimes 			vfs_unbusy(mp);
210df8bae1dSRodney W. Grimes 		}
2112b14f991SJulian Elischer 		if (!err && (mp->mnt_flag & MNT_RELOAD))
2122b14f991SJulian Elischer 			err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
2132b14f991SJulian Elischer 		if (err) {
2142b14f991SJulian Elischer 			goto error_1;
2152b14f991SJulian Elischer 		}
2161469eec8SDavid Greenman 		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
2171469eec8SDavid Greenman 			if (!fs->fs_clean) {
2181469eec8SDavid Greenman 				if (mp->mnt_flag & MNT_FORCE) {
2191469eec8SDavid Greenman 					printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt);
2201469eec8SDavid Greenman 				} else {
2211469eec8SDavid Greenman 					printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n",
2221469eec8SDavid Greenman 					    fs->fs_fsmnt);
2232b14f991SJulian Elischer 					err = EPERM;
2242b14f991SJulian Elischer 					goto error_1;
2251469eec8SDavid Greenman 				}
2261469eec8SDavid Greenman 			}
227df8bae1dSRodney W. Grimes 			fs->fs_ronly = 0;
2281469eec8SDavid Greenman 		}
229e0e9c421SDavid Greenman 		if (fs->fs_ronly == 0) {
230e0e9c421SDavid Greenman 			fs->fs_clean = 0;
231e0e9c421SDavid Greenman 			ffs_sbupdate(ump, MNT_WAIT);
232e0e9c421SDavid Greenman 		}
2332b14f991SJulian Elischer 		/* if not updating name...*/
234df8bae1dSRodney W. Grimes 		if (args.fspec == 0) {
235df8bae1dSRodney W. Grimes 			/*
2362b14f991SJulian Elischer 			 * Process export requests.  Jumping to "success"
2372b14f991SJulian Elischer 			 * will return the vfs_export() error code.
238df8bae1dSRodney W. Grimes 			 */
2392b14f991SJulian Elischer 			err = vfs_export(mp, &ump->um_export, &args.export);
2402b14f991SJulian Elischer 			goto success;
241df8bae1dSRodney W. Grimes 		}
242df8bae1dSRodney W. Grimes 	}
2432b14f991SJulian Elischer 
244df8bae1dSRodney W. Grimes 	/*
245df8bae1dSRodney W. Grimes 	 * Not an update, or updating the name: look up the name
246df8bae1dSRodney W. Grimes 	 * and verify that it refers to a sensible block device.
247df8bae1dSRodney W. Grimes 	 */
248df8bae1dSRodney W. Grimes 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
2492b14f991SJulian Elischer 	err = namei(ndp);
2502b14f991SJulian Elischer 	if (err) {
2512b14f991SJulian Elischer 		/* can't get devvp!*/
2522b14f991SJulian Elischer 		goto error_1;
2532b14f991SJulian Elischer 	}
2542b14f991SJulian Elischer 
255df8bae1dSRodney W. Grimes 	devvp = ndp->ni_vp;
256df8bae1dSRodney W. Grimes 
257df8bae1dSRodney W. Grimes 	if (devvp->v_type != VBLK) {
2582b14f991SJulian Elischer 		err = ENOTBLK;
2592b14f991SJulian Elischer 		goto error_2;
260df8bae1dSRodney W. Grimes 	}
261df8bae1dSRodney W. Grimes 	if (major(devvp->v_rdev) >= nblkdev) {
2622b14f991SJulian Elischer 		err = ENXIO;
2632b14f991SJulian Elischer 		goto error_2;
264df8bae1dSRodney W. Grimes 	}
2652b14f991SJulian Elischer 	if (mp->mnt_flag & MNT_UPDATE) {
2662b14f991SJulian Elischer 		/*
2672b14f991SJulian Elischer 		 ********************
2682b14f991SJulian Elischer 		 * UPDATE
2692b14f991SJulian Elischer 		 ********************
2702b14f991SJulian Elischer 		 */
2712b14f991SJulian Elischer 
272df8bae1dSRodney W. Grimes 		if (devvp != ump->um_devvp)
2732b14f991SJulian Elischer 			err = EINVAL;	/* needs translation */
274df8bae1dSRodney W. Grimes 		else
275df8bae1dSRodney W. Grimes 			vrele(devvp);
2762b14f991SJulian Elischer 		/*
2772b14f991SJulian Elischer 		 * Update device name only on success
2782b14f991SJulian Elischer 		 */
2792b14f991SJulian Elischer 		if( !err) {
2802b14f991SJulian Elischer 			/* Save "mounted from" info for mount point (NULL pad)*/
2812b14f991SJulian Elischer 			copyinstr(	args.fspec,
2822b14f991SJulian Elischer 					mp->mnt_stat.f_mntfromname,
2832b14f991SJulian Elischer 					MNAMELEN - 1,
284df8bae1dSRodney W. Grimes 					&size);
285df8bae1dSRodney W. Grimes 			bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
286df8bae1dSRodney W. Grimes 		}
2872b14f991SJulian Elischer 	} else {
2882b14f991SJulian Elischer 		/*
2892b14f991SJulian Elischer 		 ********************
2902b14f991SJulian Elischer 		 * NEW MOUNT
2912b14f991SJulian Elischer 		 ********************
2922b14f991SJulian Elischer 		 */
2932b14f991SJulian Elischer 
2942b14f991SJulian Elischer 		/*
2952b14f991SJulian Elischer 		 * Since this is a new mount, we want the names for
2962b14f991SJulian Elischer 		 * the device and the mount point copied in.  If an
2972b14f991SJulian Elischer 		 * error occurs,  the mountpoint is discarded by the
2982b14f991SJulian Elischer 		 * upper level code.
2992b14f991SJulian Elischer 		 */
3002b14f991SJulian Elischer 		/* Save "last mounted on" info for mount point (NULL pad)*/
3012b14f991SJulian Elischer 		copyinstr(	path,				/* mount point*/
3022b14f991SJulian Elischer 				mp->mnt_stat.f_mntonname,	/* save area*/
3032b14f991SJulian Elischer 				MNAMELEN - 1,			/* max size*/
3042b14f991SJulian Elischer 				&size);				/* real size*/
3052b14f991SJulian Elischer 		bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
3062b14f991SJulian Elischer 
3072b14f991SJulian Elischer 		/* Save "mounted from" info for mount point (NULL pad)*/
3082b14f991SJulian Elischer 		copyinstr(	args.fspec,			/* device name*/
3092b14f991SJulian Elischer 				mp->mnt_stat.f_mntfromname,	/* save area*/
3102b14f991SJulian Elischer 				MNAMELEN - 1,			/* max size*/
3112b14f991SJulian Elischer 				&size);				/* real size*/
3122b14f991SJulian Elischer 		bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
3132b14f991SJulian Elischer 
3142b14f991SJulian Elischer 		err = ffs_mountfs(devvp, mp, p);
3152b14f991SJulian Elischer 	}
3162b14f991SJulian Elischer 	if (err) {
3172b14f991SJulian Elischer 		goto error_2;
3182b14f991SJulian Elischer 	}
3192b14f991SJulian Elischer 
3202b14f991SJulian Elischer dostatfs:
3212b14f991SJulian Elischer 	/*
3222b14f991SJulian Elischer 	 * Initialize FS stat information in mount struct; uses both
3232b14f991SJulian Elischer 	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
3242b14f991SJulian Elischer 	 *
3252b14f991SJulian Elischer 	 * This code is common to root and non-root mounts
3262b14f991SJulian Elischer 	 */
3272b14f991SJulian Elischer 	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
3282b14f991SJulian Elischer 
3292b14f991SJulian Elischer 	goto success;
3302b14f991SJulian Elischer 
3312b14f991SJulian Elischer 
3322b14f991SJulian Elischer error_2:	/* error with devvp held*/
3332b14f991SJulian Elischer 
3342b14f991SJulian Elischer 	/* release devvp before failing*/
3352b14f991SJulian Elischer 	vrele(devvp);
3362b14f991SJulian Elischer 
3372b14f991SJulian Elischer error_1:	/* no state to back out*/
3382b14f991SJulian Elischer 
3392b14f991SJulian Elischer success:
3402b14f991SJulian Elischer 	return( err);
3412b14f991SJulian Elischer }
3422b14f991SJulian Elischer 
343df8bae1dSRodney W. Grimes 
344df8bae1dSRodney W. Grimes /*
345df8bae1dSRodney W. Grimes  * Reload all incore data for a filesystem (used after running fsck on
346df8bae1dSRodney W. Grimes  * the root filesystem and finding things to fix). The filesystem must
347df8bae1dSRodney W. Grimes  * be mounted read-only.
348df8bae1dSRodney W. Grimes  *
349df8bae1dSRodney W. Grimes  * Things to do to update the mount:
350df8bae1dSRodney W. Grimes  *	1) invalidate all cached meta-data.
351df8bae1dSRodney W. Grimes  *	2) re-read superblock from disk.
352df8bae1dSRodney W. Grimes  *	3) re-read summary information from disk.
353df8bae1dSRodney W. Grimes  *	4) invalidate all inactive vnodes.
354df8bae1dSRodney W. Grimes  *	5) invalidate all cached file data.
355df8bae1dSRodney W. Grimes  *	6) re-read inode data for all active vnodes.
356df8bae1dSRodney W. Grimes  */
357b8dce649SPoul-Henning Kamp static int
3582b14f991SJulian Elischer ffs_reload(mp, cred, p)
3592b14f991SJulian Elischer 	register struct mount *mp;
360df8bae1dSRodney W. Grimes 	struct ucred *cred;
361df8bae1dSRodney W. Grimes 	struct proc *p;
362df8bae1dSRodney W. Grimes {
363df8bae1dSRodney W. Grimes 	register struct vnode *vp, *nvp, *devvp;
364df8bae1dSRodney W. Grimes 	struct inode *ip;
365df8bae1dSRodney W. Grimes 	struct csum *space;
366df8bae1dSRodney W. Grimes 	struct buf *bp;
367df8bae1dSRodney W. Grimes 	struct fs *fs;
368df8bae1dSRodney W. Grimes 	int i, blks, size, error;
369df8bae1dSRodney W. Grimes 
3702b14f991SJulian Elischer 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
371df8bae1dSRodney W. Grimes 		return (EINVAL);
372df8bae1dSRodney W. Grimes 	/*
373df8bae1dSRodney W. Grimes 	 * Step 1: invalidate all cached meta-data.
374df8bae1dSRodney W. Grimes 	 */
3752b14f991SJulian Elischer 	devvp = VFSTOUFS(mp)->um_devvp;
376df8bae1dSRodney W. Grimes 	if (vinvalbuf(devvp, 0, cred, p, 0, 0))
377df8bae1dSRodney W. Grimes 		panic("ffs_reload: dirty1");
378df8bae1dSRodney W. Grimes 	/*
379df8bae1dSRodney W. Grimes 	 * Step 2: re-read superblock from disk.
380df8bae1dSRodney W. Grimes 	 */
381c9671602SPoul-Henning Kamp 	error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp);
382c9671602SPoul-Henning Kamp 	if (error)
383df8bae1dSRodney W. Grimes 		return (error);
384df8bae1dSRodney W. Grimes 	fs = (struct fs *)bp->b_data;
385df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
386df8bae1dSRodney W. Grimes 	    fs->fs_bsize < sizeof(struct fs)) {
387df8bae1dSRodney W. Grimes 		brelse(bp);
388df8bae1dSRodney W. Grimes 		return (EIO);		/* XXX needs translation */
389df8bae1dSRodney W. Grimes 	}
3902b14f991SJulian Elischer 	fs = VFSTOUFS(mp)->um_fs;
391df8bae1dSRodney W. Grimes 	bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0],
392df8bae1dSRodney W. Grimes 	    sizeof(fs->fs_csp));
393df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize);
394df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
395df8bae1dSRodney W. Grimes 		bp->b_flags |= B_INVAL;
396df8bae1dSRodney W. Grimes 	brelse(bp);
397df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
398df8bae1dSRodney W. Grimes 	/*
399df8bae1dSRodney W. Grimes 	 * Step 3: re-read summary information from disk.
400df8bae1dSRodney W. Grimes 	 */
401df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
402df8bae1dSRodney W. Grimes 	space = fs->fs_csp[0];
403df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
404df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
405df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
406df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
407c9671602SPoul-Henning Kamp 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
408c9671602SPoul-Henning Kamp 		    NOCRED, &bp);
409c9671602SPoul-Henning Kamp 		if (error)
410df8bae1dSRodney W. Grimes 			return (error);
411df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
412df8bae1dSRodney W. Grimes 		brelse(bp);
413df8bae1dSRodney W. Grimes 	}
414df8bae1dSRodney W. Grimes loop:
4152b14f991SJulian Elischer 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
416df8bae1dSRodney W. Grimes 		nvp = vp->v_mntvnodes.le_next;
417df8bae1dSRodney W. Grimes 		/*
418df8bae1dSRodney W. Grimes 		 * Step 4: invalidate all inactive vnodes.
419df8bae1dSRodney W. Grimes 		 */
420df8bae1dSRodney W. Grimes 		if (vp->v_usecount == 0) {
421df8bae1dSRodney W. Grimes 			vgone(vp);
422df8bae1dSRodney W. Grimes 			continue;
423df8bae1dSRodney W. Grimes 		}
424df8bae1dSRodney W. Grimes 		/*
425df8bae1dSRodney W. Grimes 		 * Step 5: invalidate all cached file data.
426df8bae1dSRodney W. Grimes 		 */
427df8bae1dSRodney W. Grimes 		if (vget(vp, 1))
428df8bae1dSRodney W. Grimes 			goto loop;
429df8bae1dSRodney W. Grimes 		if (vinvalbuf(vp, 0, cred, p, 0, 0))
430df8bae1dSRodney W. Grimes 			panic("ffs_reload: dirty2");
431df8bae1dSRodney W. Grimes 		/*
432df8bae1dSRodney W. Grimes 		 * Step 6: re-read inode data for all active vnodes.
433df8bae1dSRodney W. Grimes 		 */
434df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
435c9671602SPoul-Henning Kamp 		error =
436df8bae1dSRodney W. Grimes 		    bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
437c9671602SPoul-Henning Kamp 		    (int)fs->fs_bsize, NOCRED, &bp);
438c9671602SPoul-Henning Kamp 		if (error) {
439df8bae1dSRodney W. Grimes 			vput(vp);
440df8bae1dSRodney W. Grimes 			return (error);
441df8bae1dSRodney W. Grimes 		}
442df8bae1dSRodney W. Grimes 		ip->i_din = *((struct dinode *)bp->b_data +
443df8bae1dSRodney W. Grimes 		    ino_to_fsbo(fs, ip->i_number));
444df8bae1dSRodney W. Grimes 		brelse(bp);
445df8bae1dSRodney W. Grimes 		vput(vp);
4462b14f991SJulian Elischer 		if (vp->v_mount != mp)
447df8bae1dSRodney W. Grimes 			goto loop;
448df8bae1dSRodney W. Grimes 	}
449df8bae1dSRodney W. Grimes 	return (0);
450df8bae1dSRodney W. Grimes }
451df8bae1dSRodney W. Grimes 
452df8bae1dSRodney W. Grimes /*
453df8bae1dSRodney W. Grimes  * Common code for mount and mountroot
454df8bae1dSRodney W. Grimes  */
455df8bae1dSRodney W. Grimes int
456df8bae1dSRodney W. Grimes ffs_mountfs(devvp, mp, p)
457df8bae1dSRodney W. Grimes 	register struct vnode *devvp;
458df8bae1dSRodney W. Grimes 	struct mount *mp;
459df8bae1dSRodney W. Grimes 	struct proc *p;
460df8bae1dSRodney W. Grimes {
461df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
462df8bae1dSRodney W. Grimes 	struct buf *bp;
463df8bae1dSRodney W. Grimes 	register struct fs *fs;
464df8bae1dSRodney W. Grimes 	dev_t dev = devvp->v_rdev;
465df8bae1dSRodney W. Grimes 	struct partinfo dpart;
466df8bae1dSRodney W. Grimes 	caddr_t base, space;
467df8bae1dSRodney W. Grimes 	int havepart = 0, blks;
468df8bae1dSRodney W. Grimes 	int error, i, size;
469df8bae1dSRodney W. Grimes 	int ronly;
4702b14f991SJulian Elischer 	u_int strsize;
471df8bae1dSRodney W. Grimes 
472df8bae1dSRodney W. Grimes 	/*
473df8bae1dSRodney W. Grimes 	 * Disallow multiple mounts of the same device.
474df8bae1dSRodney W. Grimes 	 * Disallow mounting of a device that is currently in use
475df8bae1dSRodney W. Grimes 	 * (except for root, which might share swap device for miniroot).
476df8bae1dSRodney W. Grimes 	 * Flush out any old buffers remaining from a previous use.
477df8bae1dSRodney W. Grimes 	 */
478c9671602SPoul-Henning Kamp 	error = vfs_mountedon(devvp);
479c9671602SPoul-Henning Kamp 	if (error)
480df8bae1dSRodney W. Grimes 		return (error);
481df8bae1dSRodney W. Grimes 	if (vcount(devvp) > 1 && devvp != rootvp)
482df8bae1dSRodney W. Grimes 		return (EBUSY);
483c9671602SPoul-Henning Kamp 	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
484c9671602SPoul-Henning Kamp 	if (error)
485df8bae1dSRodney W. Grimes 		return (error);
486df8bae1dSRodney W. Grimes 
487df8bae1dSRodney W. Grimes 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
488c9671602SPoul-Henning Kamp 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
489c9671602SPoul-Henning Kamp 	if (error)
490df8bae1dSRodney W. Grimes 		return (error);
491df8bae1dSRodney W. Grimes 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
492df8bae1dSRodney W. Grimes 		size = DEV_BSIZE;
493df8bae1dSRodney W. Grimes 	else {
494df8bae1dSRodney W. Grimes 		havepart = 1;
495df8bae1dSRodney W. Grimes 		size = dpart.disklab->d_secsize;
496df8bae1dSRodney W. Grimes 	}
497df8bae1dSRodney W. Grimes 
498df8bae1dSRodney W. Grimes 	bp = NULL;
499df8bae1dSRodney W. Grimes 	ump = NULL;
500c9671602SPoul-Henning Kamp 	error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp);
501c9671602SPoul-Henning Kamp 	if (error)
502df8bae1dSRodney W. Grimes 		goto out;
503df8bae1dSRodney W. Grimes 	fs = (struct fs *)bp->b_data;
504df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
505df8bae1dSRodney W. Grimes 	    fs->fs_bsize < sizeof(struct fs)) {
506df8bae1dSRodney W. Grimes 		error = EINVAL;		/* XXX needs translation */
507df8bae1dSRodney W. Grimes 		goto out;
508df8bae1dSRodney W. Grimes 	}
5091469eec8SDavid Greenman 	if (!fs->fs_clean) {
5101469eec8SDavid Greenman 		if (ronly || (mp->mnt_flag & MNT_FORCE)) {
5111469eec8SDavid Greenman 			printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt);
5121469eec8SDavid Greenman 		} else {
5131469eec8SDavid Greenman 			printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n",fs->fs_fsmnt);
5141469eec8SDavid Greenman 			error = EPERM;
5151469eec8SDavid Greenman 			goto out;
5161469eec8SDavid Greenman 		}
5171469eec8SDavid Greenman 	}
518df8bae1dSRodney W. Grimes 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
519df8bae1dSRodney W. Grimes 	bzero((caddr_t)ump, sizeof *ump);
520df8bae1dSRodney W. Grimes 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
521df8bae1dSRodney W. Grimes 	    M_WAITOK);
522df8bae1dSRodney W. Grimes 	bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
523df8bae1dSRodney W. Grimes 	if (fs->fs_sbsize < SBSIZE)
524df8bae1dSRodney W. Grimes 		bp->b_flags |= B_INVAL;
525df8bae1dSRodney W. Grimes 	brelse(bp);
526df8bae1dSRodney W. Grimes 	bp = NULL;
527df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
528df8bae1dSRodney W. Grimes 	fs->fs_ronly = ronly;
529e0e9c421SDavid Greenman 	if (ronly == 0) {
530df8bae1dSRodney W. Grimes 		fs->fs_fmod = 1;
531e0e9c421SDavid Greenman 		fs->fs_clean = 0;
532e0e9c421SDavid Greenman 	}
533df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
534df8bae1dSRodney W. Grimes 	base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
535df8bae1dSRodney W. Grimes 	    M_WAITOK);
536df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
537df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
538df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
539df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
540df8bae1dSRodney W. Grimes 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
541df8bae1dSRodney W. Grimes 			NOCRED, &bp);
542df8bae1dSRodney W. Grimes 		if (error) {
543df8bae1dSRodney W. Grimes 			free(base, M_UFSMNT);
544df8bae1dSRodney W. Grimes 			goto out;
545df8bae1dSRodney W. Grimes 		}
546df8bae1dSRodney W. Grimes 		bcopy(bp->b_data, space, (u_int)size);
547df8bae1dSRodney W. Grimes 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
548df8bae1dSRodney W. Grimes 		space += size;
549df8bae1dSRodney W. Grimes 		brelse(bp);
550df8bae1dSRodney W. Grimes 		bp = NULL;
551df8bae1dSRodney W. Grimes 	}
552df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)ump;
553df8bae1dSRodney W. Grimes 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
554df8bae1dSRodney W. Grimes 	mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
555df8bae1dSRodney W. Grimes 	mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
556df8bae1dSRodney W. Grimes 	mp->mnt_flag |= MNT_LOCAL;
557df8bae1dSRodney W. Grimes 	ump->um_mountp = mp;
558df8bae1dSRodney W. Grimes 	ump->um_dev = dev;
559df8bae1dSRodney W. Grimes 	ump->um_devvp = devvp;
560df8bae1dSRodney W. Grimes 	ump->um_nindir = fs->fs_nindir;
561df8bae1dSRodney W. Grimes 	ump->um_bptrtodb = fs->fs_fsbtodb;
562df8bae1dSRodney W. Grimes 	ump->um_seqinc = fs->fs_frag;
563df8bae1dSRodney W. Grimes 	for (i = 0; i < MAXQUOTAS; i++)
564df8bae1dSRodney W. Grimes 		ump->um_quotas[i] = NULLVP;
565df8bae1dSRodney W. Grimes 	devvp->v_specflags |= SI_MOUNTEDON;
566df8bae1dSRodney W. Grimes 	ffs_oldfscompat(fs);
5672b14f991SJulian Elischer 
5682b14f991SJulian Elischer 	/*
5692b14f991SJulian Elischer 	 * Set FS local "last mounted on" information (NULL pad)
5702b14f991SJulian Elischer 	 */
5712b14f991SJulian Elischer 	copystr(	mp->mnt_stat.f_mntonname,	/* mount point*/
5722b14f991SJulian Elischer 			fs->fs_fsmnt,			/* copy area*/
5732b14f991SJulian Elischer 			sizeof(fs->fs_fsmnt) - 1,	/* max size*/
5742b14f991SJulian Elischer 			&strsize);			/* real size*/
5752b14f991SJulian Elischer 	bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize);
5762b14f991SJulian Elischer 
5772b14f991SJulian Elischer 	if( mp->mnt_flag & MNT_ROOTFS) {
5782b14f991SJulian Elischer 		/*
5792b14f991SJulian Elischer 		 * Root mount; update timestamp in mount structure.
5802b14f991SJulian Elischer 		 * this will be used by the common root mount code
5812b14f991SJulian Elischer 		 * to update the system clock.
5822b14f991SJulian Elischer 		 */
5832b14f991SJulian Elischer 		mp->mnt_time = fs->fs_time;
5842b14f991SJulian Elischer 	}
585e0e9c421SDavid Greenman 	if (ronly == 0)
586e0e9c421SDavid Greenman 		ffs_sbupdate(ump, MNT_WAIT);
587847a3ba7SJohn Dyson 	/*
588847a3ba7SJohn Dyson 	 * Only VMIO the backing device if the backing device is a real
589847a3ba7SJohn Dyson 	 * block device.  This excludes the original MFS implementation.
590847a3ba7SJohn Dyson 	 */
591847a3ba7SJohn Dyson 	if ((devvp->v_type == VBLK) && (major(devvp->v_rdev) < nblkdev)) {
59291477adcSJohn Dyson 		vn_vmio_open(devvp, p, p->p_ucred);
593847a3ba7SJohn Dyson 	}
594df8bae1dSRodney W. Grimes 	return (0);
595df8bae1dSRodney W. Grimes out:
596df8bae1dSRodney W. Grimes 	if (bp)
597df8bae1dSRodney W. Grimes 		brelse(bp);
598df8bae1dSRodney W. Grimes 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
599df8bae1dSRodney W. Grimes 	if (ump) {
600df8bae1dSRodney W. Grimes 		free(ump->um_fs, M_UFSMNT);
601df8bae1dSRodney W. Grimes 		free(ump, M_UFSMNT);
602df8bae1dSRodney W. Grimes 		mp->mnt_data = (qaddr_t)0;
603df8bae1dSRodney W. Grimes 	}
604df8bae1dSRodney W. Grimes 	return (error);
605df8bae1dSRodney W. Grimes }
606df8bae1dSRodney W. Grimes 
607df8bae1dSRodney W. Grimes /*
608df8bae1dSRodney W. Grimes  * Sanity checks for old file systems.
609df8bae1dSRodney W. Grimes  *
610df8bae1dSRodney W. Grimes  * XXX - goes away some day.
611df8bae1dSRodney W. Grimes  */
612b8dce649SPoul-Henning Kamp static int
613df8bae1dSRodney W. Grimes ffs_oldfscompat(fs)
614df8bae1dSRodney W. Grimes 	struct fs *fs;
615df8bae1dSRodney W. Grimes {
616df8bae1dSRodney W. Grimes 
617df8bae1dSRodney W. Grimes 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
618df8bae1dSRodney W. Grimes 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
619df8bae1dSRodney W. Grimes 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
620df8bae1dSRodney W. Grimes 		fs->fs_nrpos = 8;				/* XXX */
621df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
622c03020b2SPoul-Henning Kamp #if 0
623c03020b2SPoul-Henning Kamp 		int i;						/* XXX */
624df8bae1dSRodney W. Grimes 		quad_t sizepb = fs->fs_bsize;			/* XXX */
625df8bae1dSRodney W. Grimes 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
626df8bae1dSRodney W. Grimes 		for (i = 0; i < NIADDR; i++) {			/* XXX */
627df8bae1dSRodney W. Grimes 			sizepb *= NINDIR(fs);			/* XXX */
628df8bae1dSRodney W. Grimes 			fs->fs_maxfilesize += sizepb;		/* XXX */
629df8bae1dSRodney W. Grimes 		}						/* XXX */
630901ba606SDavid Greenman #endif
631a316d390SJohn Dyson 		fs->fs_maxfilesize = (u_quad_t) 1LL << 39;
632df8bae1dSRodney W. Grimes 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
633df8bae1dSRodney W. Grimes 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
634df8bae1dSRodney W. Grimes 	}							/* XXX */
635df8bae1dSRodney W. Grimes 	return (0);
636df8bae1dSRodney W. Grimes }
637df8bae1dSRodney W. Grimes 
638df8bae1dSRodney W. Grimes /*
639df8bae1dSRodney W. Grimes  * unmount system call
640df8bae1dSRodney W. Grimes  */
641df8bae1dSRodney W. Grimes int
642df8bae1dSRodney W. Grimes ffs_unmount(mp, mntflags, p)
643df8bae1dSRodney W. Grimes 	struct mount *mp;
644df8bae1dSRodney W. Grimes 	int mntflags;
645df8bae1dSRodney W. Grimes 	struct proc *p;
646df8bae1dSRodney W. Grimes {
647df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
648df8bae1dSRodney W. Grimes 	register struct fs *fs;
649df8bae1dSRodney W. Grimes 	int error, flags, ronly;
650df8bae1dSRodney W. Grimes 
651df8bae1dSRodney W. Grimes 	flags = 0;
652df8bae1dSRodney W. Grimes 	if (mntflags & MNT_FORCE) {
653df8bae1dSRodney W. Grimes 		flags |= FORCECLOSE;
654df8bae1dSRodney W. Grimes 	}
655c9671602SPoul-Henning Kamp 	error = ffs_flushfiles(mp, flags, p);
656c9671602SPoul-Henning Kamp 	if (error)
657df8bae1dSRodney W. Grimes 		return (error);
658df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
659df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
660e0e9c421SDavid Greenman 	ronly = fs->fs_ronly;
661e0e9c421SDavid Greenman 	if (!ronly) {
662e0e9c421SDavid Greenman 		fs->fs_clean = 1;
663e0e9c421SDavid Greenman 		ffs_sbupdate(ump, MNT_WAIT);
664e0e9c421SDavid Greenman 	}
665df8bae1dSRodney W. Grimes 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
666df8bae1dSRodney W. Grimes 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
667df8bae1dSRodney W. Grimes 		NOCRED, p);
668a316d390SJohn Dyson 	vn_vmio_close(ump->um_devvp);
669df8bae1dSRodney W. Grimes 	free(fs->fs_csp[0], M_UFSMNT);
670df8bae1dSRodney W. Grimes 	free(fs, M_UFSMNT);
671df8bae1dSRodney W. Grimes 	free(ump, M_UFSMNT);
672df8bae1dSRodney W. Grimes 	mp->mnt_data = (qaddr_t)0;
673df8bae1dSRodney W. Grimes 	mp->mnt_flag &= ~MNT_LOCAL;
674df8bae1dSRodney W. Grimes 	return (error);
675df8bae1dSRodney W. Grimes }
676df8bae1dSRodney W. Grimes 
677df8bae1dSRodney W. Grimes /*
678df8bae1dSRodney W. Grimes  * Flush out all the files in a filesystem.
679df8bae1dSRodney W. Grimes  */
68026f9a767SRodney W. Grimes int
681df8bae1dSRodney W. Grimes ffs_flushfiles(mp, flags, p)
682df8bae1dSRodney W. Grimes 	register struct mount *mp;
683df8bae1dSRodney W. Grimes 	int flags;
684df8bae1dSRodney W. Grimes 	struct proc *p;
685df8bae1dSRodney W. Grimes {
686df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
687c9671602SPoul-Henning Kamp 	int error;
688df8bae1dSRodney W. Grimes 
689df8bae1dSRodney W. Grimes 	if (!doforce)
690df8bae1dSRodney W. Grimes 		flags &= ~FORCECLOSE;
691df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
692df8bae1dSRodney W. Grimes #ifdef QUOTA
693df8bae1dSRodney W. Grimes 	if (mp->mnt_flag & MNT_QUOTA) {
694c1d9efcbSPoul-Henning Kamp 		int i;
695c1d9efcbSPoul-Henning Kamp 		error = vflush(mp, NULLVP, SKIPSYSTEM|flags);
696c1d9efcbSPoul-Henning Kamp 		if (error)
697df8bae1dSRodney W. Grimes 			return (error);
698df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++) {
699df8bae1dSRodney W. Grimes 			if (ump->um_quotas[i] == NULLVP)
700df8bae1dSRodney W. Grimes 				continue;
701df8bae1dSRodney W. Grimes 			quotaoff(p, mp, i);
702df8bae1dSRodney W. Grimes 		}
703df8bae1dSRodney W. Grimes 		/*
704df8bae1dSRodney W. Grimes 		 * Here we fall through to vflush again to ensure
705df8bae1dSRodney W. Grimes 		 * that we have gotten rid of all the system vnodes.
706df8bae1dSRodney W. Grimes 		 */
707df8bae1dSRodney W. Grimes 	}
708df8bae1dSRodney W. Grimes #endif
709df8bae1dSRodney W. Grimes 	error = vflush(mp, NULLVP, flags);
710df8bae1dSRodney W. Grimes 	return (error);
711df8bae1dSRodney W. Grimes }
712df8bae1dSRodney W. Grimes 
713df8bae1dSRodney W. Grimes /*
714df8bae1dSRodney W. Grimes  * Get file system statistics.
715df8bae1dSRodney W. Grimes  */
716df8bae1dSRodney W. Grimes int
717df8bae1dSRodney W. Grimes ffs_statfs(mp, sbp, p)
718df8bae1dSRodney W. Grimes 	struct mount *mp;
719df8bae1dSRodney W. Grimes 	register struct statfs *sbp;
720df8bae1dSRodney W. Grimes 	struct proc *p;
721df8bae1dSRodney W. Grimes {
722df8bae1dSRodney W. Grimes 	register struct ufsmount *ump;
723df8bae1dSRodney W. Grimes 	register struct fs *fs;
724df8bae1dSRodney W. Grimes 
725df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
726df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
727df8bae1dSRodney W. Grimes 	if (fs->fs_magic != FS_MAGIC)
728df8bae1dSRodney W. Grimes 		panic("ffs_statfs");
729df8bae1dSRodney W. Grimes 	sbp->f_type = MOUNT_UFS;
730df8bae1dSRodney W. Grimes 	sbp->f_bsize = fs->fs_fsize;
731df8bae1dSRodney W. Grimes 	sbp->f_iosize = fs->fs_bsize;
732df8bae1dSRodney W. Grimes 	sbp->f_blocks = fs->fs_dsize;
733df8bae1dSRodney W. Grimes 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
734df8bae1dSRodney W. Grimes 		fs->fs_cstotal.cs_nffree;
73551ea8b57SBruce Evans 	sbp->f_bavail = freespace(fs, fs->fs_minfree);
736df8bae1dSRodney W. Grimes 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
737df8bae1dSRodney W. Grimes 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
738df8bae1dSRodney W. Grimes 	if (sbp != &mp->mnt_stat) {
739df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
740df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
741df8bae1dSRodney W. Grimes 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
742df8bae1dSRodney W. Grimes 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
743df8bae1dSRodney W. Grimes 	}
744df8bae1dSRodney W. Grimes 	return (0);
745df8bae1dSRodney W. Grimes }
746df8bae1dSRodney W. Grimes 
747df8bae1dSRodney W. Grimes /*
748df8bae1dSRodney W. Grimes  * Go through the disk queues to initiate sandbagged IO;
749df8bae1dSRodney W. Grimes  * go through the inodes to write those that have been modified;
750df8bae1dSRodney W. Grimes  * initiate the writing of the super block if it has been modified.
751df8bae1dSRodney W. Grimes  *
752df8bae1dSRodney W. Grimes  * Note: we are always called with the filesystem marked `MPBUSY'.
753df8bae1dSRodney W. Grimes  */
754df8bae1dSRodney W. Grimes int
755df8bae1dSRodney W. Grimes ffs_sync(mp, waitfor, cred, p)
756df8bae1dSRodney W. Grimes 	struct mount *mp;
757df8bae1dSRodney W. Grimes 	int waitfor;
758df8bae1dSRodney W. Grimes 	struct ucred *cred;
759df8bae1dSRodney W. Grimes 	struct proc *p;
760df8bae1dSRodney W. Grimes {
761a316d390SJohn Dyson 	register struct vnode *vp, *nvp;
762df8bae1dSRodney W. Grimes 	register struct inode *ip;
763df8bae1dSRodney W. Grimes 	register struct ufsmount *ump = VFSTOUFS(mp);
764df8bae1dSRodney W. Grimes 	register struct fs *fs;
76581c6e3e5SDavid Greenman 	struct timeval tv;
766df8bae1dSRodney W. Grimes 	int error, allerror = 0;
767df8bae1dSRodney W. Grimes 
768df8bae1dSRodney W. Grimes 	fs = ump->um_fs;
769df8bae1dSRodney W. Grimes 	/*
770df8bae1dSRodney W. Grimes 	 * Write back modified superblock.
771df8bae1dSRodney W. Grimes 	 * Consistency check that the superblock
772df8bae1dSRodney W. Grimes 	 * is still in the buffer cache.
773df8bae1dSRodney W. Grimes 	 */
774df8bae1dSRodney W. Grimes 	if (fs->fs_fmod != 0) {
775df8bae1dSRodney W. Grimes 		if (fs->fs_ronly != 0) {		/* XXX */
776df8bae1dSRodney W. Grimes 			printf("fs = %s\n", fs->fs_fsmnt);
777df8bae1dSRodney W. Grimes 			panic("update: rofs mod");
778df8bae1dSRodney W. Grimes 		}
779df8bae1dSRodney W. Grimes 		fs->fs_fmod = 0;
780df8bae1dSRodney W. Grimes 		fs->fs_time = time.tv_sec;
781df8bae1dSRodney W. Grimes 		allerror = ffs_sbupdate(ump, waitfor);
782df8bae1dSRodney W. Grimes 	}
783df8bae1dSRodney W. Grimes 	/*
784df8bae1dSRodney W. Grimes 	 * Write back each (modified) inode.
785df8bae1dSRodney W. Grimes 	 */
786df8bae1dSRodney W. Grimes loop:
787a316d390SJohn Dyson 	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
788df8bae1dSRodney W. Grimes 		/*
789df8bae1dSRodney W. Grimes 		 * If the vnode that we are about to sync is no longer
790df8bae1dSRodney W. Grimes 		 * associated with this mount point, start over.
791df8bae1dSRodney W. Grimes 		 */
792df8bae1dSRodney W. Grimes 		if (vp->v_mount != mp)
793df8bae1dSRodney W. Grimes 			goto loop;
794a316d390SJohn Dyson 		nvp = vp->v_mntvnodes.le_next;
795df8bae1dSRodney W. Grimes 		if (VOP_ISLOCKED(vp))
796df8bae1dSRodney W. Grimes 			continue;
797df8bae1dSRodney W. Grimes 		ip = VTOI(vp);
79881c6e3e5SDavid Greenman 		if ((((ip->i_flag &
7994e83f749SDavid Greenman 		    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)) &&
800df8bae1dSRodney W. Grimes 		    vp->v_dirtyblkhd.lh_first == NULL)
801df8bae1dSRodney W. Grimes 			continue;
80281c6e3e5SDavid Greenman 		if (vp->v_type != VCHR) {
803df8bae1dSRodney W. Grimes 			if (vget(vp, 1))
804df8bae1dSRodney W. Grimes 				goto loop;
805c9671602SPoul-Henning Kamp 			error = VOP_FSYNC(vp, cred, waitfor, p);
806c9671602SPoul-Henning Kamp 			if (error)
807df8bae1dSRodney W. Grimes 				allerror = error;
808df8bae1dSRodney W. Grimes 			vput(vp);
80981c6e3e5SDavid Greenman 		} else {
81081c6e3e5SDavid Greenman 			tv = time;
811a316d390SJohn Dyson 			/* VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT); */
812a316d390SJohn Dyson 			VOP_UPDATE(vp, &tv, &tv, 0);
81381c6e3e5SDavid Greenman 		}
814df8bae1dSRodney W. Grimes 	}
815df8bae1dSRodney W. Grimes 	/*
816df8bae1dSRodney W. Grimes 	 * Force stale file system control information to be flushed.
817df8bae1dSRodney W. Grimes 	 */
818c9671602SPoul-Henning Kamp 	error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p);
819c9671602SPoul-Henning Kamp 	if (error)
820df8bae1dSRodney W. Grimes 		allerror = error;
821df8bae1dSRodney W. Grimes #ifdef QUOTA
822df8bae1dSRodney W. Grimes 	qsync(mp);
823df8bae1dSRodney W. Grimes #endif
824df8bae1dSRodney W. Grimes 	return (allerror);
825df8bae1dSRodney W. Grimes }
826df8bae1dSRodney W. Grimes 
827df8bae1dSRodney W. Grimes /*
828df8bae1dSRodney W. Grimes  * Look up a FFS dinode number to find its incore vnode, otherwise read it
829df8bae1dSRodney W. Grimes  * in from disk.  If it is in core, wait for the lock bit to clear, then
830df8bae1dSRodney W. Grimes  * return the inode locked.  Detection and handling of mount points must be
831df8bae1dSRodney W. Grimes  * done by the calling routine.
832df8bae1dSRodney W. Grimes  */
833b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock;
8342094ddb6SDavid Greenman 
835df8bae1dSRodney W. Grimes int
836df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp)
837df8bae1dSRodney W. Grimes 	struct mount *mp;
838df8bae1dSRodney W. Grimes 	ino_t ino;
839df8bae1dSRodney W. Grimes 	struct vnode **vpp;
840df8bae1dSRodney W. Grimes {
841df8bae1dSRodney W. Grimes 	register struct fs *fs;
842df8bae1dSRodney W. Grimes 	register struct inode *ip;
843df8bae1dSRodney W. Grimes 	struct ufsmount *ump;
844df8bae1dSRodney W. Grimes 	struct buf *bp;
845df8bae1dSRodney W. Grimes 	struct vnode *vp;
846df8bae1dSRodney W. Grimes 	dev_t dev;
847c9671602SPoul-Henning Kamp 	int type, error;
848df8bae1dSRodney W. Grimes 
849df8bae1dSRodney W. Grimes 	ump = VFSTOUFS(mp);
850df8bae1dSRodney W. Grimes 	dev = ump->um_dev;
8518997d94fSDavid Greenman restart:
852df8bae1dSRodney W. Grimes 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
853df8bae1dSRodney W. Grimes 		return (0);
854df8bae1dSRodney W. Grimes 
8552094ddb6SDavid Greenman 	/*
8568997d94fSDavid Greenman 	 * Lock out the creation of new entries in the FFS hash table in
8578997d94fSDavid Greenman 	 * case getnewvnode() or MALLOC() blocks, otherwise a duplicate
8582094ddb6SDavid Greenman 	 * may occur!
8592094ddb6SDavid Greenman 	 */
8602094ddb6SDavid Greenman 	if (ffs_inode_hash_lock) {
8612094ddb6SDavid Greenman 		while (ffs_inode_hash_lock) {
8622094ddb6SDavid Greenman 			ffs_inode_hash_lock = -1;
8632094ddb6SDavid Greenman 			tsleep(&ffs_inode_hash_lock, PVM, "ffsvgt", 0);
8642094ddb6SDavid Greenman 		}
8658997d94fSDavid Greenman 		goto restart;
8662094ddb6SDavid Greenman 	}
8672094ddb6SDavid Greenman 	ffs_inode_hash_lock = 1;
8682094ddb6SDavid Greenman 
8692f9bae59SDavid Greenman 	/*
8702f9bae59SDavid Greenman 	 * If this MALLOC() is performed after the getnewvnode()
8712f9bae59SDavid Greenman 	 * it might block, leaving a vnode with a NULL v_data to be
8722f9bae59SDavid Greenman 	 * found by ffs_sync() if a sync happens to fire right then,
8732f9bae59SDavid Greenman 	 * which will cause a panic because ffs_sync() blindly
8742f9bae59SDavid Greenman 	 * dereferences vp->v_data (as well it should).
8752f9bae59SDavid Greenman 	 */
8762f9bae59SDavid Greenman 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
8772f9bae59SDavid Greenman 	MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
8782f9bae59SDavid Greenman 
879df8bae1dSRodney W. Grimes 	/* Allocate a new vnode/inode. */
880c9671602SPoul-Henning Kamp 	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp);
881c9671602SPoul-Henning Kamp 	if (error) {
8828997d94fSDavid Greenman 		if (ffs_inode_hash_lock < 0)
8832094ddb6SDavid Greenman 			wakeup(&ffs_inode_hash_lock);
8842094ddb6SDavid Greenman 		ffs_inode_hash_lock = 0;
885df8bae1dSRodney W. Grimes 		*vpp = NULL;
8862f9bae59SDavid Greenman 		FREE(ip, type);
887df8bae1dSRodney W. Grimes 		return (error);
888df8bae1dSRodney W. Grimes 	}
889df8bae1dSRodney W. Grimes 	bzero((caddr_t)ip, sizeof(struct inode));
890df8bae1dSRodney W. Grimes 	vp->v_data = ip;
891df8bae1dSRodney W. Grimes 	ip->i_vnode = vp;
892df8bae1dSRodney W. Grimes 	ip->i_fs = fs = ump->um_fs;
893df8bae1dSRodney W. Grimes 	ip->i_dev = dev;
894df8bae1dSRodney W. Grimes 	ip->i_number = ino;
895df8bae1dSRodney W. Grimes #ifdef QUOTA
896c1d9efcbSPoul-Henning Kamp 	{
897c1d9efcbSPoul-Henning Kamp 		int i;
898df8bae1dSRodney W. Grimes 		for (i = 0; i < MAXQUOTAS; i++)
899df8bae1dSRodney W. Grimes 			ip->i_dquot[i] = NODQUOT;
900c1d9efcbSPoul-Henning Kamp 	}
901df8bae1dSRodney W. Grimes #endif
902df8bae1dSRodney W. Grimes 	/*
903df8bae1dSRodney W. Grimes 	 * Put it onto its hash chain and lock it so that other requests for
904df8bae1dSRodney W. Grimes 	 * this inode will block if they arrive while we are sleeping waiting
905df8bae1dSRodney W. Grimes 	 * for old data structures to be purged or for the contents of the
906df8bae1dSRodney W. Grimes 	 * disk portion of this inode to be read.
907df8bae1dSRodney W. Grimes 	 */
908df8bae1dSRodney W. Grimes 	ufs_ihashins(ip);
909df8bae1dSRodney W. Grimes 
9108997d94fSDavid Greenman 	if (ffs_inode_hash_lock < 0)
9112094ddb6SDavid Greenman 		wakeup(&ffs_inode_hash_lock);
9122094ddb6SDavid Greenman 	ffs_inode_hash_lock = 0;
9132094ddb6SDavid Greenman 
914df8bae1dSRodney W. Grimes 	/* Read in the disk contents for the inode, copy into the inode. */
915c9671602SPoul-Henning Kamp 	error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
916c9671602SPoul-Henning Kamp 	    (int)fs->fs_bsize, NOCRED, &bp);
917c9671602SPoul-Henning Kamp 	if (error) {
918df8bae1dSRodney W. Grimes 		/*
919df8bae1dSRodney W. Grimes 		 * The inode does not contain anything useful, so it would
920df8bae1dSRodney W. Grimes 		 * be misleading to leave it on its hash chain. With mode
921df8bae1dSRodney W. Grimes 		 * still zero, it will be unlinked and returned to the free
922df8bae1dSRodney W. Grimes 		 * list by vput().
923df8bae1dSRodney W. Grimes 		 */
924df8bae1dSRodney W. Grimes 		brelse(bp);
925bd7e5f99SJohn Dyson 		vput(vp);
926df8bae1dSRodney W. Grimes 		*vpp = NULL;
927df8bae1dSRodney W. Grimes 		return (error);
928df8bae1dSRodney W. Grimes 	}
929df8bae1dSRodney W. Grimes 	ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
930bd7e5f99SJohn Dyson 	bqrelse(bp);
931df8bae1dSRodney W. Grimes 
932df8bae1dSRodney W. Grimes 	/*
933df8bae1dSRodney W. Grimes 	 * Initialize the vnode from the inode, check for aliases.
934df8bae1dSRodney W. Grimes 	 * Note that the underlying vnode may have changed.
935df8bae1dSRodney W. Grimes 	 */
936e6302eabSBruce Evans 	error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
937c9671602SPoul-Henning Kamp 	if (error) {
938df8bae1dSRodney W. Grimes 		vput(vp);
939df8bae1dSRodney W. Grimes 		*vpp = NULL;
940df8bae1dSRodney W. Grimes 		return (error);
941df8bae1dSRodney W. Grimes 	}
942df8bae1dSRodney W. Grimes 	/*
943df8bae1dSRodney W. Grimes 	 * Finish inode initialization now that aliasing has been resolved.
944df8bae1dSRodney W. Grimes 	 */
945df8bae1dSRodney W. Grimes 	ip->i_devvp = ump->um_devvp;
946df8bae1dSRodney W. Grimes 	VREF(ip->i_devvp);
947df8bae1dSRodney W. Grimes 	/*
948df8bae1dSRodney W. Grimes 	 * Set up a generation number for this inode if it does not
949df8bae1dSRodney W. Grimes 	 * already have one. This should only happen on old filesystems.
950df8bae1dSRodney W. Grimes 	 */
951df8bae1dSRodney W. Grimes 	if (ip->i_gen == 0) {
952df8bae1dSRodney W. Grimes 		if (++nextgennumber < (u_long)time.tv_sec)
953df8bae1dSRodney W. Grimes 			nextgennumber = time.tv_sec;
954df8bae1dSRodney W. Grimes 		ip->i_gen = nextgennumber;
955df8bae1dSRodney W. Grimes 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
956df8bae1dSRodney W. Grimes 			ip->i_flag |= IN_MODIFIED;
957df8bae1dSRodney W. Grimes 	}
958df8bae1dSRodney W. Grimes 	/*
959df8bae1dSRodney W. Grimes 	 * Ensure that uid and gid are correct. This is a temporary
960df8bae1dSRodney W. Grimes 	 * fix until fsck has been changed to do the update.
961df8bae1dSRodney W. Grimes 	 */
962df8bae1dSRodney W. Grimes 	if (fs->fs_inodefmt < FS_44INODEFMT) {		/* XXX */
963df8bae1dSRodney W. Grimes 		ip->i_uid = ip->i_din.di_ouid;		/* XXX */
964df8bae1dSRodney W. Grimes 		ip->i_gid = ip->i_din.di_ogid;		/* XXX */
965df8bae1dSRodney W. Grimes 	}						/* XXX */
966df8bae1dSRodney W. Grimes 
967df8bae1dSRodney W. Grimes 	*vpp = vp;
968df8bae1dSRodney W. Grimes 	return (0);
969df8bae1dSRodney W. Grimes }
970df8bae1dSRodney W. Grimes 
971df8bae1dSRodney W. Grimes /*
972df8bae1dSRodney W. Grimes  * File handle to vnode
973df8bae1dSRodney W. Grimes  *
974df8bae1dSRodney W. Grimes  * Have to be really careful about stale file handles:
975df8bae1dSRodney W. Grimes  * - check that the inode number is valid
976df8bae1dSRodney W. Grimes  * - call ffs_vget() to get the locked inode
977df8bae1dSRodney W. Grimes  * - check for an unallocated inode (i_mode == 0)
978df8bae1dSRodney W. Grimes  * - check that the given client host has export rights and return
979df8bae1dSRodney W. Grimes  *   those rights via. exflagsp and credanonp
980df8bae1dSRodney W. Grimes  */
981df8bae1dSRodney W. Grimes int
982df8bae1dSRodney W. Grimes ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
983df8bae1dSRodney W. Grimes 	register struct mount *mp;
984df8bae1dSRodney W. Grimes 	struct fid *fhp;
985df8bae1dSRodney W. Grimes 	struct mbuf *nam;
986df8bae1dSRodney W. Grimes 	struct vnode **vpp;
987df8bae1dSRodney W. Grimes 	int *exflagsp;
988df8bae1dSRodney W. Grimes 	struct ucred **credanonp;
989df8bae1dSRodney W. Grimes {
990df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
991df8bae1dSRodney W. Grimes 	struct fs *fs;
992df8bae1dSRodney W. Grimes 
993df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
994df8bae1dSRodney W. Grimes 	fs = VFSTOUFS(mp)->um_fs;
995df8bae1dSRodney W. Grimes 	if (ufhp->ufid_ino < ROOTINO ||
996df8bae1dSRodney W. Grimes 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
997df8bae1dSRodney W. Grimes 		return (ESTALE);
998df8bae1dSRodney W. Grimes 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
999df8bae1dSRodney W. Grimes }
1000df8bae1dSRodney W. Grimes 
1001df8bae1dSRodney W. Grimes /*
1002df8bae1dSRodney W. Grimes  * Vnode pointer to File handle
1003df8bae1dSRodney W. Grimes  */
1004df8bae1dSRodney W. Grimes /* ARGSUSED */
100526f9a767SRodney W. Grimes int
1006df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp)
1007df8bae1dSRodney W. Grimes 	struct vnode *vp;
1008df8bae1dSRodney W. Grimes 	struct fid *fhp;
1009df8bae1dSRodney W. Grimes {
1010df8bae1dSRodney W. Grimes 	register struct inode *ip;
1011df8bae1dSRodney W. Grimes 	register struct ufid *ufhp;
1012df8bae1dSRodney W. Grimes 
1013df8bae1dSRodney W. Grimes 	ip = VTOI(vp);
1014df8bae1dSRodney W. Grimes 	ufhp = (struct ufid *)fhp;
1015df8bae1dSRodney W. Grimes 	ufhp->ufid_len = sizeof(struct ufid);
1016df8bae1dSRodney W. Grimes 	ufhp->ufid_ino = ip->i_number;
1017df8bae1dSRodney W. Grimes 	ufhp->ufid_gen = ip->i_gen;
1018df8bae1dSRodney W. Grimes 	return (0);
1019df8bae1dSRodney W. Grimes }
1020df8bae1dSRodney W. Grimes 
1021df8bae1dSRodney W. Grimes /*
1022df8bae1dSRodney W. Grimes  * Write a superblock and associated information back to disk.
1023df8bae1dSRodney W. Grimes  */
1024b8dce649SPoul-Henning Kamp static int
1025df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor)
1026df8bae1dSRodney W. Grimes 	struct ufsmount *mp;
1027df8bae1dSRodney W. Grimes 	int waitfor;
1028df8bae1dSRodney W. Grimes {
1029df8bae1dSRodney W. Grimes 	register struct fs *fs = mp->um_fs;
1030df8bae1dSRodney W. Grimes 	register struct buf *bp;
1031df8bae1dSRodney W. Grimes 	int blks;
1032df8bae1dSRodney W. Grimes 	caddr_t space;
1033df8bae1dSRodney W. Grimes 	int i, size, error = 0;
1034df8bae1dSRodney W. Grimes 
1035df8bae1dSRodney W. Grimes 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0);
1036df8bae1dSRodney W. Grimes 	bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
1037df8bae1dSRodney W. Grimes 	/* Restore compatibility to old file systems.		   XXX */
1038df8bae1dSRodney W. Grimes 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
1039df8bae1dSRodney W. Grimes 		((struct fs *)bp->b_data)->fs_nrpos = -1;	/* XXX */
1040df8bae1dSRodney W. Grimes 	if (waitfor == MNT_WAIT)
1041df8bae1dSRodney W. Grimes 		error = bwrite(bp);
1042df8bae1dSRodney W. Grimes 	else
1043df8bae1dSRodney W. Grimes 		bawrite(bp);
1044df8bae1dSRodney W. Grimes 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
1045df8bae1dSRodney W. Grimes 	space = (caddr_t)fs->fs_csp[0];
1046df8bae1dSRodney W. Grimes 	for (i = 0; i < blks; i += fs->fs_frag) {
1047df8bae1dSRodney W. Grimes 		size = fs->fs_bsize;
1048df8bae1dSRodney W. Grimes 		if (i + fs->fs_frag > blks)
1049df8bae1dSRodney W. Grimes 			size = (blks - i) * fs->fs_fsize;
1050df8bae1dSRodney W. Grimes 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1051df8bae1dSRodney W. Grimes 		    size, 0, 0);
1052df8bae1dSRodney W. Grimes 		bcopy(space, bp->b_data, (u_int)size);
1053df8bae1dSRodney W. Grimes 		space += size;
1054df8bae1dSRodney W. Grimes 		if (waitfor == MNT_WAIT)
1055df8bae1dSRodney W. Grimes 			error = bwrite(bp);
1056df8bae1dSRodney W. Grimes 		else
1057df8bae1dSRodney W. Grimes 			bawrite(bp);
1058df8bae1dSRodney W. Grimes 	}
1059df8bae1dSRodney W. Grimes 	return (error);
1060df8bae1dSRodney W. Grimes }
1061