*
* @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@
*/
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/ubc.h>
+#include <sys/quota.h>
#include <miscfs/specfs/specdev.h>
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;
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);
}
{
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);
* 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)
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)
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 */
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;
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) {
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);
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;
}
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 */
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;
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);
}
/*
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);
}
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.
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);
}
/* 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)) {
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
* 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)
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))