X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..d7e50217d7adf6e52786a38bcaa4cd698cb9a79e:/bsd/ufs/ffs/ffs_vfsops.c

diff --git a/bsd/ufs/ffs/ffs_vfsops.c b/bsd/ufs/ffs/ffs_vfsops.c
index 10c78d5fb..6e58add47 100644
--- a/bsd/ufs/ffs/ffs_vfsops.c
+++ b/bsd/ufs/ffs/ffs_vfsops.c
@@ -3,19 +3,22 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
@@ -72,6 +75,7 @@
 #include <sys/errno.h>
 #include <sys/malloc.h>
 #include <sys/ubc.h>
+#include <sys/quota.h>
 
 #include <miscfs/specfs/specdev.h>
 
@@ -126,8 +130,10 @@ ffs_mountroot()
 		printf("ffs_mountroot: can't setup bdevvp");
 		return (error);
 	}
-	if (error = vfs_rootmountalloc("ufs", "root_device", &mp))
+	if (error = vfs_rootmountalloc("ufs", "root_device", &mp)) {
+		vrele(rootvp); /* release the reference from bdevvp() */
 		return (error);
+	}
 
 	/* Must set the MNT_ROOTFS flag before doing the actual mount */
 	mp->mnt_flag |= MNT_ROOTFS;
@@ -135,6 +141,7 @@ ffs_mountroot()
 	if (error = ffs_mountfs(rootvp, mp, p)) {
 		mp->mnt_vfc->vfc_refcount--;
 		vfs_unbusy(mp, p);
+		vrele(rootvp); /* release the reference from bdevvp() */
 		_FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
 		return (error);
 	}
@@ -325,10 +332,11 @@ ffs_reload(mountp, cred, p)
 {
 	register struct vnode *vp, *nvp, *devvp;
 	struct inode *ip;
-	struct csum *space;
+	void *space;
 	struct buf *bp;
 	struct fs *fs, *newfs;
 	int i, blks, size, error;
+	u_int64_t maxfilesize;					/* XXX */
 	int32_t *lp;
 #if REV_ENDIAN_FS
 	int rev_endian = (mountp->mnt_flag & MNT_REVEND);
@@ -373,7 +381,7 @@ ffs_reload(mountp, cred, p)
 	 * new superblock. These should really be in the ufsmount.	XXX
 	 * Note that important parameters (eg fs_ncg) are unchanged.
 	 */
-	bcopy(&fs->fs_csp[0], &newfs->fs_csp[0], sizeof(fs->fs_csp));
+	newfs->fs_csp = fs->fs_csp;
 	newfs->fs_maxcluster = fs->fs_maxcluster;
 	bcopy(newfs, fs, (u_int)fs->fs_sbsize);
 	if (fs->fs_sbsize < SBSIZE)
@@ -385,11 +393,14 @@ ffs_reload(mountp, cred, p)
 	brelse(bp);
 	mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
 	ffs_oldfscompat(fs);
+	maxfilesize = (u_int64_t)0x100000000;                  /* 4GB */
+	if (fs->fs_maxfilesize > maxfilesize)			/* XXX */
+		fs->fs_maxfilesize = maxfilesize;		/* XXX */
 	/*
 	 * Step 3: re-read summary information from disk.
 	 */
 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
-	space = fs->fs_csp[0];
+	space = fs->fs_csp;
 	for (i = 0; i < blks; i += fs->fs_frag) {
 		size = fs->fs_bsize;
 		if (i + fs->fs_frag > blks)
@@ -405,7 +416,7 @@ ffs_reload(mountp, cred, p)
 			byte_swap_ints((int *)bp->b_data, size / sizeof(int));
 		}
 #endif /* REV_ENDIAN_FS */
-		bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
+		bcopy(bp->b_data, space, (u_int)size);
 #if REV_ENDIAN_FS
 		if (rev_endian) {
 			/* csum swaps */
@@ -492,7 +503,7 @@ ffs_mountfs(devvp, mp, p)
 	struct buf *cgbp;
 	struct cg *cgp;
 	int32_t clustersumoff;
-	caddr_t base, space;
+	void *space;
 	int error, i, blks, size, ronly;
 	int32_t *lp;
 	struct ucred *cred;
@@ -600,6 +611,13 @@ ffs_mountfs(devvp, mp, p)
 		set_fsblocksize(devvp);
         } 
 
+	/* cache the IO attributes */
+	error = vfs_init_io_attributes(devvp, mp);
+	if (error) {
+		printf("ffs_mountfs: vfs_init_io_attributes returned %d\n",
+			error);
+		goto out;
+	}
 
 	/* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
 	if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
@@ -672,15 +690,15 @@ ffs_mountfs(devvp, mp, p)
 	blks = howmany(size, fs->fs_fsize);
 	if (fs->fs_contigsumsize > 0)
 		size += fs->fs_ncg * sizeof(int32_t);
-	base = space = _MALLOC((u_long)size, M_UFSMNT, M_WAITOK);
-	base = space;
+	space = _MALLOC((u_long)size, M_UFSMNT, M_WAITOK);
+	fs->fs_csp = space;
 	for (i = 0; i < blks; i += fs->fs_frag) {
 		size = fs->fs_bsize;
 		if (i + fs->fs_frag > blks)
 			size = (blks - i) * fs->fs_fsize;
 		if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
 		    cred, &bp)) {
-			_FREE(base, M_UFSMNT);
+			_FREE(fs->fs_csp, M_UFSMNT);
 			goto out;
 		}
 		bcopy(bp->b_data, space, (u_int)size);
@@ -688,13 +706,12 @@ ffs_mountfs(devvp, mp, p)
 		if (rev_endian)
 			byte_swap_ints((int *) space, size / sizeof(int));
 #endif /* REV_ENDIAN_FS */
-		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
-		space += size;
+		space = (char *)space + size;
 		brelse(bp);
 		bp = NULL;
 	}
 	if (fs->fs_contigsumsize > 0) {
-		fs->fs_maxcluster = lp = (int32_t *)space;
+		fs->fs_maxcluster = lp = space;
 		for (i = 0; i < fs->fs_ncg; i++)
 			*lp++ = fs->fs_contigsumsize;
 	}
@@ -714,7 +731,7 @@ ffs_mountfs(devvp, mp, p)
 	ump->um_bptrtodb = fs->fs_fsbtodb;
 	ump->um_seqinc = fs->fs_frag;
 	for (i = 0; i < MAXQUOTAS; i++)
-		ump->um_quotas[i] = NULLVP;
+		ump->um_qfiles[i].qf_vp = NULLVP;
 	devvp->v_specflags |= SI_MOUNTEDON;
 	ffs_oldfscompat(fs);
 	ump->um_savedmaxfilesize = fs->fs_maxfilesize;		/* XXX */
@@ -781,10 +798,15 @@ ffs_unmount(mp, mntflags, p)
 	register struct ufsmount *ump;
 	register struct fs *fs;
 	int error, flags;
+	int force;
+
 	flags = 0;
-	if (mntflags & MNT_FORCE)
+	force = 0;
+	if (mntflags & MNT_FORCE) {
 		flags |= FORCECLOSE;
-	if (error = ffs_flushfiles(mp, flags, p))
+		force = 1;
+	}
+	if ( (error = ffs_flushfiles(mp, flags, p)) && !force )
 		return (error);
 	ump = VFSTOUFS(mp);
 	fs = ump->um_fs;
@@ -805,16 +827,18 @@ ffs_unmount(mp, mntflags, p)
 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
 		NOCRED, p);
+	if (error && !force)
+		return (error);
 	vrele(ump->um_devvp);
 
-	_FREE(fs->fs_csp[0], M_UFSMNT);
+	_FREE(fs->fs_csp, M_UFSMNT);
 	_FREE(fs, M_UFSMNT);
 	_FREE(ump, M_UFSMNT);
 	mp->mnt_data = (qaddr_t)0;
 #if REV_ENDIAN_FS
 	mp->mnt_flag &= ~MNT_REVEND;
 #endif /* REV_ENDIAN_FS */
-	return (error);
+	return (0);
 }
 
 /*
@@ -834,7 +858,7 @@ ffs_flushfiles(mp, flags, p)
 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
 			return (error);
 		for (i = 0; i < MAXQUOTAS; i++) {
-			if (ump->um_quotas[i] == NULLVP)
+			if (ump->um_qfiles[i].qf_vp == NULLVP)
 				continue;
 			quotaoff(p, mp, i);
 		}
@@ -916,6 +940,8 @@ loop:
 	for (vp = mp->mnt_vnodelist.lh_first;
 	     vp != NULL;
 	     vp = nvp) {
+		int didhold = 0;
+
 		/*
 		 * If the vnode that we are about to sync is no longer
 		 * associated with this mount point, start over.
@@ -939,9 +965,12 @@ loop:
 				goto loop;
 			continue;
 		}
+		didhold = ubc_hold(vp);
 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
 			allerror = error;
 		VOP_UNLOCK(vp, 0, p);
+		if (didhold)
+			ubc_rele(vp);
 		vrele(vp);
 		simple_lock(&mntvnode_slock);
 	}
@@ -1004,30 +1033,58 @@ ffs_vget(mp, ino, vpp)
 	/* Allocate a new vnode/inode. */
 	type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
 	MALLOC_ZONE(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
-	if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
-		FREE_ZONE(ip, sizeof(struct inode), type);
-		*vpp = NULL;
-		return (error);
-	}
 	bzero((caddr_t)ip, sizeof(struct inode));
 	lockinit(&ip->i_lock, PINOD, "inode", 0, 0);
-	vp->v_data = ip;
-	ip->i_vnode = vp;
+	/* lock the inode */
+	lockmgr(&ip->i_lock, LK_EXCLUSIVE, (struct slock *)0, p);
+
 	ip->i_fs = fs = ump->um_fs;
 	ip->i_dev = dev;
 	ip->i_number = ino;
+	ip->i_flag |= IN_ALLOC;
 #if QUOTA
 	for (i = 0; i < MAXQUOTAS; i++)
 		ip->i_dquot[i] = NODQUOT;
 #endif
+
+	/*
+	 * MALLOC_ZONE is blocking call. Check for race.
+	 */
+	if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
+		/* Clean up */
+		FREE_ZONE(ip, sizeof(struct inode), type);
+		vp = *vpp;
+		UBCINFOCHECK("ffs_vget", vp);
+		return (0);
+	}
+
 	/*
-	 * Put it onto its hash chain and lock it so that other requests for
+	 * Put it onto its hash chain locked so that other requests for
 	 * this inode will block if they arrive while we are sleeping waiting
 	 * for old data structures to be purged or for the contents of the
 	 * disk portion of this inode to be read.
 	 */
 	ufs_ihashins(ip);
 
+	if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
+		ufs_ihashrem(ip);
+		if (ISSET(ip->i_flag, IN_WALLOC))
+			wakeup(ip);
+		FREE_ZONE(ip, sizeof(struct inode), type);
+		*vpp = NULL;
+		return (error);
+	}
+	vp->v_data = ip;
+	ip->i_vnode = vp;
+
+	/*
+	 * A vnode is associated with the inode now,
+	 * vget() can deal with the serialization.
+	 */
+	CLR(ip->i_flag, IN_ALLOC);
+	if (ISSET(ip->i_flag, IN_WALLOC))
+		wakeup(ip);
+
 	/* Read in the disk contents for the inode, copy into the inode. */
 	if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
 	    (int)fs->fs_bsize, NOCRED, &bp)) {
@@ -1200,7 +1257,7 @@ ffs_sbupdate(mp, waitfor)
 	register struct fs *dfs, *fs = mp->um_fs;
 	register struct buf *bp;
 	int blks;
-	caddr_t space;
+	void *space;
 	int i, size, error, allerror = 0;
 	int devBlockSize=0;
 #if REV_ENDIAN_FS
@@ -1211,7 +1268,7 @@ ffs_sbupdate(mp, waitfor)
 	 * First write back the summary information.
 	 */
 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
-	space = (caddr_t)fs->fs_csp[0];
+	space = fs->fs_csp;
 	for (i = 0; i < blks; i += fs->fs_frag) {
 		size = fs->fs_bsize;
 		if (i + fs->fs_frag > blks)
@@ -1224,7 +1281,7 @@ ffs_sbupdate(mp, waitfor)
 			byte_swap_ints((int *)bp->b_data, size / sizeof(int));
 		}
 #endif /* REV_ENDIAN_FS */
-		space += size;
+		space = (char *)space + size;
 		if (waitfor != MNT_WAIT)
 			bawrite(bp);
 		else if (error = bwrite(bp))