diff options
author | dyson <dyson@FreeBSD.org> | 1997-02-10 02:22:35 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1997-02-10 02:22:35 +0000 |
commit | 10f666af84d48e89e4e2960415c9b616fce4077f (patch) | |
tree | 88a944de263165091f0a18abeedbaaccec532407 /sys/ufs/ffs | |
parent | 0960d7e91af3428ffba89b42228d82d8afaa0389 (diff) | |
download | FreeBSD-src-10f666af84d48e89e4e2960415c9b616fce4077f.zip FreeBSD-src-10f666af84d48e89e4e2960415c9b616fce4077f.tar.gz |
This is the kernel Lite/2 commit. There are some requisite userland
changes, so don't expect to be able to run the kernel as-is (very well)
without the appropriate Lite/2 userland changes.
The system boots and can mount UFS filesystems.
Untested: ext2fs, msdosfs, NFS
Known problems: Incorrect Berkeley ID strings in some files.
Mount_std mounts will not work until the getfsent
library routine is changed.
Reviewed by: various people
Submitted by: Jeffery Hsu <hsu@freebsd.org>
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 244 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_balloc.c | 116 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 41 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_inode.c | 50 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_subr.c | 27 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 314 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 51 | ||||
-rw-r--r-- | sys/ufs/ffs/fs.h | 288 |
8 files changed, 706 insertions, 425 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index e1272ab..4787c1c 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94 + * @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95 * $FreeBSD$ */ @@ -57,23 +57,23 @@ extern u_long nextgennumber; -typedef daddr_t allocfcn_t __P((struct inode *ip, int cg, daddr_t bpref, - int size)); +typedef ufs_daddr_t allocfcn_t __P((struct inode *ip, int cg, ufs_daddr_t bpref, + int size)); -static daddr_t ffs_alloccg __P((struct inode *, int, daddr_t, int)); -static daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, daddr_t)); -#ifdef notyet -static daddr_t ffs_clusteralloc __P((struct inode *, int, daddr_t, int)); -#endif +static ufs_daddr_t ffs_alloccg __P((struct inode *, int, ufs_daddr_t, int)); +static ufs_daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, ufs_daddr_t)); +static void ffs_clusteracct __P((struct fs *, struct cg *, ufs_daddr_t, + int)); +static ufs_daddr_t ffs_clusteralloc __P((struct inode *, int, ufs_daddr_t, + int)); static ino_t ffs_dirpref __P((struct fs *)); -static daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); +static ufs_daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); static void ffs_fserr __P((struct fs *, u_int, char *)); static u_long ffs_hashalloc __P((struct inode *, int, long, int, allocfcn_t *)); -static ino_t ffs_nodealloccg __P((struct inode *, int, daddr_t, int)); -static daddr_t ffs_mapsearch __P((struct fs *, struct cg *, daddr_t, int)); - -static void ffs_clusteracct __P((struct fs *, struct cg *, daddr_t, int)); +static ino_t ffs_nodealloccg __P((struct inode *, int, ufs_daddr_t, int)); +static ufs_daddr_t ffs_mapsearch __P((struct fs *, struct cg *, ufs_daddr_t, + int)); /* * Allocate a block in the file system. @@ -97,19 +97,18 @@ static void ffs_clusteracct __P((struct fs *, struct cg *, daddr_t, int)); int ffs_alloc(ip, lbn, bpref, size, cred, bnp) register struct inode *ip; - daddr_t lbn, bpref; + ufs_daddr_t lbn, bpref; int size; struct ucred *cred; - daddr_t *bnp; + ufs_daddr_t *bnp; { register struct fs *fs; - daddr_t bno; + ufs_daddr_t bno; int cg; #ifdef QUOTA int error; #endif - *bnp = 0; fs = ip->i_fs; #ifdef DIAGNOSTIC @@ -136,7 +135,8 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) cg = ino_to_cg(fs, ip->i_number); else cg = dtog(fs, bpref); - bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, ffs_alloccg); + bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, + ffs_alloccg); if (bno > 0) { ip->i_blocks += btodb(size); ip->i_flag |= IN_CHANGE | IN_UPDATE; @@ -166,8 +166,8 @@ nospace: int ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) register struct inode *ip; - daddr_t lbprev; - daddr_t bpref; + ufs_daddr_t lbprev; + ufs_daddr_t bpref; int osize, nsize; struct ucred *cred; struct buf **bpp; @@ -175,7 +175,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) register struct fs *fs; struct buf *bp; int cg, request, error; - daddr_t bprev, bno; + ufs_daddr_t bprev, bno; *bpp = 0; fs = ip->i_fs; @@ -285,7 +285,8 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) panic("ffs_realloccg: bad optim"); /* NOTREACHED */ } - bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, ffs_alloccg); + bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, + ffs_alloccg); if (bno > 0) { bp->b_blkno = fsbtodb(fs, bno); ffs_blkfree(ip, bprev, (long)osize); @@ -331,7 +332,13 @@ nospace: * the previous block allocation will be used. */ static int doasyncfree = 1; -SYSCTL_INT(_debug, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); +SYSCTL_INT(_vfs_ffs, FFS_ASYNCFREE, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); + +int doreallocblks = 1; +SYSCTL_INT(_vfs_ffs, FFS_REALLOCBLKS, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); + +static int prtrealloc = 0; + int ffs_reallocblks(ap) struct vop_reallocblks_args /* { @@ -346,13 +353,15 @@ ffs_reallocblks(ap) struct inode *ip; struct vnode *vp; struct buf *sbp, *ebp; - daddr_t *bap, *sbap, *ebap = 0; + ufs_daddr_t *bap, *sbap, *ebap = 0; struct cluster_save *buflist; - daddr_t start_lbn, end_lbn, soff, newblk, blkno; + ufs_daddr_t start_lbn, end_lbn, soff, newblk, blkno; struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; int i, len, start_lvl, end_lvl, pref, ssize; struct timeval tv; + if (doreallocblks == 0) + return (ENOSPC); vp = ap->a_vp; ip = VTOI(vp); fs = ip->i_fs; @@ -363,9 +372,18 @@ ffs_reallocblks(ap) start_lbn = buflist->bs_children[0]->b_lblkno; end_lbn = start_lbn + len - 1; #ifdef DIAGNOSTIC + for (i = 0; i < len; i++) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 1"); for (i = 1; i < len; i++) if (buflist->bs_children[i]->b_lblkno != start_lbn + i) - panic("ffs_reallocblks: non-cluster"); + panic("ffs_reallocblks: non-logical cluster"); + blkno = buflist->bs_children[0]->b_blkno; + ssize = fsbtodb(fs, fs->fs_frag); + for (i = 1; i < len - 1; i++) + if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) + panic("ffs_reallocblks: non-physical cluster %d", i); #endif /* * If the latest allocation is in a new cylinder group, assume that @@ -390,7 +408,7 @@ ffs_reallocblks(ap) brelse(sbp); return (ENOSPC); } - sbap = (daddr_t *)sbp->b_data; + sbap = (ufs_daddr_t *)sbp->b_data; soff = idp->in_off; } /* @@ -410,12 +428,12 @@ ffs_reallocblks(ap) ssize = len - (idp->in_off + 1); if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) goto fail; - ebap = (daddr_t *)ebp->b_data; + ebap = (ufs_daddr_t *)ebp->b_data; } /* * Search the block map looking for an allocation of the desired size. */ - if ((newblk = (daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, + if ((newblk = (ufs_daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, len, ffs_clusteralloc)) == 0) goto fail; /* @@ -425,14 +443,26 @@ ffs_reallocblks(ap) * block pointers in the inode and indirect blocks associated * with the file. */ +#ifdef DEBUG + if (prtrealloc) + printf("realloc: ino %d, lbns %d-%d\n\told:", ip->i_number, + start_lbn, end_lbn); +#endif blkno = newblk; for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { if (i == ssize) bap = ebap; #ifdef DIAGNOSTIC - if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 2"); + if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) panic("ffs_reallocblks: alloc mismatch"); #endif +#ifdef DEBUG + if (prtrealloc) + printf(" %d,", *bap); +#endif *bap++ = blkno; } /* @@ -469,11 +499,28 @@ ffs_reallocblks(ap) /* * Last, free the old blocks and assign the new blocks to the buffers. */ +#ifdef DEBUG + if (prtrealloc) + printf("\n\tnew:"); +#endif for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { ffs_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize); buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); +#ifdef DEBUG + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 3"); + if (prtrealloc) + printf(" %d,", blkno); +#endif + } +#ifdef DEBUG + if (prtrealloc) { + prtrealloc--; + printf("\n"); } +#endif return (0); fail: @@ -615,17 +662,17 @@ ffs_dirpref(fs) * fs_rotdelay milliseconds. This is to allow time for the processor to * schedule another I/O transfer. */ -daddr_t +ufs_daddr_t ffs_blkpref(ip, lbn, indx, bap) struct inode *ip; - daddr_t lbn; + ufs_daddr_t lbn; int indx; - daddr_t *bap; + ufs_daddr_t *bap; { register struct fs *fs; register int cg; int avgbfree, startcg; - daddr_t nextblk; + ufs_daddr_t nextblk; fs = ip->i_fs; if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { @@ -740,7 +787,7 @@ ffs_hashalloc(ip, cg, pref, size, allocator) * Check to see if the necessary fragments are available, and * if they are, allocate them. */ -static daddr_t +static ufs_daddr_t ffs_fragextend(ip, cg, bprev, osize, nsize) struct inode *ip; int cg; @@ -810,11 +857,11 @@ ffs_fragextend(ip, cg, bprev, osize, nsize) * Check to see if a block of the appropriate size is available, * and if it is, allocate it. */ -static daddr_t +static ufs_daddr_t ffs_alloccg(ip, cg, bpref, size) struct inode *ip; int cg; - daddr_t bpref; + ufs_daddr_t bpref; int size; { register struct fs *fs; @@ -904,13 +951,13 @@ ffs_alloccg(ip, cg, bpref, size) * Note that this routine only allocates fs_bsize blocks; these * blocks may be fragmented by the routine that allocates them. */ -static daddr_t +static ufs_daddr_t ffs_alloccgblk(fs, cgp, bpref) register struct fs *fs; register struct cg *cgp; - daddr_t bpref; + ufs_daddr_t bpref; { - daddr_t bno, blkno; + ufs_daddr_t bno, blkno; int cylno, pos, delta; short *cylbp; register int i; @@ -1016,21 +1063,22 @@ gotit: * are multiple choices in the same cylinder group. Instead we just * take the first one that we find following bpref. */ -static daddr_t +static ufs_daddr_t ffs_clusteralloc(ip, cg, bpref, len) struct inode *ip; int cg; - daddr_t bpref; + ufs_daddr_t bpref; int len; { register struct fs *fs; register struct cg *cgp; struct buf *bp; - int i, run, bno, bit, map; + int i, got, run, bno, bit, map; u_char *mapp; + int32_t *lp; fs = ip->i_fs; - if (fs->fs_cs(fs, cg).cs_nbfree < len) + if (fs->fs_maxcluster[cg] < len) return (NULL); if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, NOCRED, &bp)) @@ -1042,11 +1090,25 @@ ffs_clusteralloc(ip, cg, bpref, len) * Check to see if a cluster of the needed size (or bigger) is * available in this cylinder group. */ + lp = &cg_clustersum(cgp)[len]; for (i = len; i <= fs->fs_contigsumsize; i++) - if (cg_clustersum(cgp)[i] > 0) + if (*lp++ > 0) break; - if (i > fs->fs_contigsumsize) + if (i > fs->fs_contigsumsize) { + /* + * This is the first time looking for a cluster in this + * cylinder group. Update the cluster summary information + * to reflect the true maximum sized cluster so that + * future cluster allocation requests can avoid reading + * the cylinder group map only to find no clusters. + */ + lp = &cg_clustersum(cgp)[len - 1]; + for (i = len - 1; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cg] = i; goto fail; + } /* * Search the cluster map to find a big enough cluster. * We take the first one that we find, even if it is larger @@ -1065,7 +1127,7 @@ ffs_clusteralloc(ip, cg, bpref, len) mapp = &cg_clustersfree(cgp)[bpref / NBBY]; map = *mapp++; bit = 1 << (bpref % NBBY); - for (run = 0, i = bpref; i < cgp->cg_nclusterblks; i++) { + for (run = 0, got = bpref; got < cgp->cg_nclusterblks; got++) { if ((map & bit) == 0) { run = 0; } else { @@ -1073,22 +1135,27 @@ ffs_clusteralloc(ip, cg, bpref, len) if (run == len) break; } - if ((i & (NBBY - 1)) != (NBBY - 1)) { + if ((got & (NBBY - 1)) != (NBBY - 1)) { bit <<= 1; } else { map = *mapp++; bit = 1; } } - if (i == cgp->cg_nclusterblks) + if (got == cgp->cg_nclusterblks) goto fail; /* * Allocate the cluster that we have found. */ - bno = cg * fs->fs_fpg + blkstofrags(fs, i - run + 1); + for (i = 1; i <= len; i++) + if (!ffs_isblock(fs, cg_blksfree(cgp), got - run + i)) + panic("ffs_clusteralloc: map mismatch"); + bno = cg * fs->fs_fpg + blkstofrags(fs, got - run + 1); + if (dtog(fs, bno) != cg) + panic("ffs_clusteralloc: allocated out of group"); len = blkstofrags(fs, len); for (i = 0; i < len; i += fs->fs_frag) - if (ffs_alloccgblk(fs, cgp, bno + i) != bno + i) + if ((got = ffs_alloccgblk(fs, cgp, bno + i)) != bno + i) panic("ffs_clusteralloc: lost block"); bdwrite(bp); return (bno); @@ -1112,7 +1179,7 @@ static ino_t ffs_nodealloccg(ip, cg, ipref, mode) struct inode *ip; int cg; - daddr_t ipref; + ufs_daddr_t ipref; int mode; { register struct fs *fs; @@ -1191,13 +1258,13 @@ gotit: void ffs_blkfree(ip, bno, size) register struct inode *ip; - daddr_t bno; + ufs_daddr_t bno; long size; { register struct fs *fs; register struct cg *cgp; struct buf *bp; - daddr_t blkno; + ufs_daddr_t blkno; int i, error, cg, blk, frags, bbase; fs = ip->i_fs; @@ -1288,6 +1355,56 @@ ffs_blkfree(ip, bno, size) bdwrite(bp); } +#ifdef DIAGNOSTIC +/* + * Verify allocation of a block or fragment. Returns true if block or + * fragment is allocated, false if it is free. + */ +ffs_checkblk(ip, bno, size) + struct inode *ip; + ufs_daddr_t bno; + long size; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + int i, error, frags, free; + + fs = ip->i_fs; + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("bsize = %d, size = %d, fs = %s\n", + fs->fs_bsize, size, fs->fs_fsmnt); + panic("checkblk: bad size"); + } + if ((u_int)bno >= fs->fs_size) + panic("checkblk: bad block %d", bno); + error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, dtog(fs, bno))), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) { + brelse(bp); + return; + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return; + } + bno = dtogd(fs, bno); + if (size == fs->fs_bsize) { + free = ffs_isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno)); + } else { + frags = numfrags(fs, size); + for (free = 0, i = 0; i < frags; i++) + if (isset(cg_blksfree(cgp), bno + i)) + free++; + if (free != 0 && free != frags) + panic("checkblk: partially free fragment"); + } + brelse(bp); + return (!free); +} +#endif /* DIAGNOSTIC */ + /* * Free an inode. * @@ -1355,14 +1472,14 @@ ffs_vfree(ap) * It is a panic if a request is made to find a block if none are * available. */ -static daddr_t +static ufs_daddr_t ffs_mapsearch(fs, cgp, bpref, allocsiz) register struct fs *fs; register struct cg *cgp; - daddr_t bpref; + ufs_daddr_t bpref; int allocsiz; { - daddr_t bno; + ufs_daddr_t bno; int start, len, loc, i; int blk, field, subfield, pos; @@ -1423,10 +1540,11 @@ static void ffs_clusteracct(fs, cgp, blkno, cnt) struct fs *fs; struct cg *cgp; - daddr_t blkno; + ufs_daddr_t blkno; int cnt; { - long *sump; + int32_t *sump; + int32_t *lp; u_char *freemapp, *mapp; int i, start, end, forw, back, map, bit; @@ -1495,6 +1613,14 @@ ffs_clusteracct(fs, cgp, blkno, cnt) sump[back] -= cnt; if (forw > 0) sump[forw] -= cnt; + /* + * Update cluster summary information. + */ + lp = &sump[fs->fs_contigsumsize]; + for (i = fs->fs_contigsumsize; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cgp->cg_cgx] = i; } /* diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index 4d382fa..5d7d798 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 + * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 * $FreeBSD$ */ @@ -56,27 +56,27 @@ * the inode and the logical block number in a file. */ int -ffs_balloc(ip, bn, size, cred, bpp, flags) +ffs_balloc(ip, lbn, size, cred, bpp, flags) register struct inode *ip; - register daddr_t bn; + register ufs_daddr_t lbn; int size; struct ucred *cred; struct buf **bpp; int flags; { register struct fs *fs; - register daddr_t nb; + register ufs_daddr_t nb; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[NIADDR + 2]; - daddr_t newb, lbn, *bap, pref; - int osize, nsize, num, i, error; + ufs_daddr_t newb, *bap, pref; + int deallocated, osize, nsize, num, i, error; + ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; *bpp = NULL; - if (bn < 0) + if (lbn < 0) return (EFBIG); fs = ip->i_fs; - lbn = bn; /* * If the next write will extend the file into a new block, @@ -84,7 +84,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * this fragment has to be extended to be a full block. */ nb = lblkno(fs, ip->i_size); - if (nb < NDADDR && nb < bn) { + if (nb < NDADDR && nb < lbn) { osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { error = ffs_realloccg(ip, nb, @@ -104,10 +104,10 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) /* * The first NDADDR blocks are direct blocks */ - if (bn < NDADDR) { - nb = ip->i_db[bn]; - if (nb != 0 && ip->i_size >= (bn + 1) * fs->fs_bsize) { - error = bread(vp, bn, fs->fs_bsize, NOCRED, &bp); + if (lbn < NDADDR) { + nb = ip->i_db[lbn]; + if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) { + error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); return (error); @@ -123,35 +123,35 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { - error = bread(vp, bn, osize, NOCRED, &bp); + error = bread(vp, lbn, osize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); } else { - error = ffs_realloccg(ip, bn, - ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), - osize, nsize, cred, &bp); + error = ffs_realloccg(ip, lbn, + ffs_blkpref(ip, lbn, (int)lbn, + &ip->i_db[0]), osize, nsize, cred, &bp); if (error) return (error); } } else { - if (ip->i_size < (bn + 1) * fs->fs_bsize) + if (ip->i_size < (lbn + 1) * fs->fs_bsize) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; - error = ffs_alloc(ip, bn, - ffs_blkpref(ip, bn, (int)bn, &ip->i_db[0]), + error = ffs_alloc(ip, lbn, + ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), nsize, cred, &newb); if (error) return (error); - bp = getblk(vp, bn, nsize, 0, 0); + bp = getblk(vp, lbn, nsize, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) vfs_bio_clrbuf(bp); } - ip->i_db[bn] = dbtofsb(fs, bp->b_blkno); + ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); @@ -160,8 +160,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * Determine the number of levels of indirection. */ pref = 0; - error = ufs_getlbns(vp, bn, indirs, &num); - if (error) + if (error = ufs_getlbns(vp, lbn, indirs, &num)) return(error); #ifdef DIAGNOSTIC if (num < 1) @@ -172,26 +171,26 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) */ --num; nb = ip->i_ib[indirs[0].in_off]; + allocib = NULL; + allocblk = allociblk; if (nb == 0) { - pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); - error = ffs_alloc(ip, lbn, pref, - (int)fs->fs_bsize, cred, &newb); - if (error) + pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + cred, &newb)) return (error); nb = newb; + *allocblk++ = nb; bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); - bp->b_blkno = fsbtodb(fs, newb); + bp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(bp); /* * Write synchronously so that indirect blocks * never point at garbage. */ - error = bwrite(bp); - if (error) { - ffs_blkfree(ip, nb, fs->fs_bsize); - return (error); - } - ip->i_ib[indirs[0].in_off] = newb; + if (error = bwrite(bp)) + goto fail; + allocib = &ip->i_ib[indirs[0].in_off]; + *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* @@ -202,9 +201,9 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); - return (error); + goto fail; } - bap = (daddr_t *)bp->b_data; + bap = (ufs_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; @@ -214,14 +213,14 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) continue; } if (pref == 0) - pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); - error = - ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb); - if (error) { + pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); + if (error = + ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { brelse(bp); - return (error); + goto fail; } nb = newb; + *allocblk++ = nb; nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); @@ -229,11 +228,9 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) * Write synchronously so that indirect blocks * never point at garbage. */ - error = bwrite(nbp); - if (error) { - ffs_blkfree(ip, nb, fs->fs_bsize); + if (error = bwrite(nbp)) { brelse(bp); - return (error); + goto fail; } bap[indirs[i - 1].in_off] = nb; /* @@ -255,9 +252,10 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) lbn, pref, (int)fs->fs_bsize, cred, &newb); if (error) { brelse(bp); - return (error); + goto fail; } nb = newb; + *allocblk++ = nb; nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); if (flags & B_CLRBUF) @@ -280,7 +278,7 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); if (error) { brelse(nbp); - return (error); + goto fail; } } else { nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); @@ -288,4 +286,26 @@ ffs_balloc(ip, bn, size, cred, bpp, flags) } *bpp = nbp; return (0); +fail: + /* + * If we have failed part way through block allocation, we + * have to deallocate any indirect blocks that we have allocated. + */ + for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { + ffs_blkfree(ip, *blkp, fs->fs_bsize); + deallocated += fs->fs_bsize; + } + if (allocib != NULL) + *allocib = 0; + if (deallocated) { +#ifdef QUOTA + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); +#endif + ip->i_blocks -= btodb(deallocated); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + return (error); } diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index c0ef7c4..f168d01 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -30,13 +30,31 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_extern.h 8.3 (Berkeley) 4/16/94 + * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 * $FreeBSD$ */ #ifndef _UFS_FFS_EXTERN_H #define _UFS_FFS_EXTERN_H +/* + * Sysctl values for the fast filesystem. + */ +#define FFS_CLUSTERREAD 1 /* cluster reading enabled */ +#define FFS_CLUSTERWRITE 2 /* cluster writing enabled */ +#define FFS_REALLOCBLKS 3 /* block reallocation enabled */ +#define FFS_ASYNCFREE 4 /* asynchronous block freeing enabled */ +#define FFS_MAXID 5 /* number of valid ffs ids */ + +#define FFS_NAMES { \ + { 0, 0 }, \ + { "doclusterread", CTLTYPE_INT }, \ + { "doclusterwrite", CTLTYPE_INT }, \ + { "doreallocblks", CTLTYPE_INT }, \ + { "doasyncfree", CTLTYPE_INT }, \ +} + +struct buf; struct fid; struct fs; struct inode; @@ -44,29 +62,28 @@ struct mbuf; struct mount; struct statfs; struct vnode; +struct mbuf; int ffs_alloc __P((struct inode *, - daddr_t, daddr_t, int, struct ucred *, daddr_t *)); + ufs_daddr_t, ufs_daddr_t, int, struct ucred *, ufs_daddr_t *)); int ffs_balloc __P((struct inode *, - daddr_t, int, struct ucred *, struct buf **, int)); + ufs_daddr_t, int, struct ucred *, struct buf **, int)); int ffs_blkatoff __P((struct vop_blkatoff_args *)); -void ffs_blkfree __P((struct inode *, daddr_t, long)); -daddr_t ffs_blkpref __P((struct inode *, daddr_t, int, daddr_t *)); +void ffs_blkfree __P((struct inode *, ufs_daddr_t, long)); +ufs_daddr_t ffs_blkpref __P((struct inode *, ufs_daddr_t, int, ufs_daddr_t *)); int ffs_bmap __P((struct vop_bmap_args *)); -void ffs_clrblock __P((struct fs *, u_char *, daddr_t)); +void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_fhtovp __P((struct mount *, struct fid *, struct mbuf *, struct vnode **, int *, struct ucred **)); -int ffs_flushfiles __P((struct mount *, int, struct proc *)); -void ffs_fragacct __P((struct fs *, int, long [], int)); -int ffs_init __P((void)); -int ffs_isblock __P((struct fs *, u_char *, daddr_t)); +void ffs_fragacct __P((struct fs *, int, int32_t [], int)); +int ffs_isblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_mountfs __P((struct vnode *, struct mount *, struct proc *)); int ffs_mountroot __P((void)); int ffs_reallocblks __P((struct vop_reallocblks_args *)); int ffs_realloccg __P((struct inode *, - daddr_t, daddr_t, int, int, struct ucred *, struct buf **)); + ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **)); int ffs_reclaim __P((struct vop_reclaim_args *)); -void ffs_setblock __P((struct fs *, u_char *, daddr_t)); +void ffs_setblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_statfs __P((struct mount *, struct statfs *, struct proc *)); int ffs_sync __P((struct mount *, int, struct ucred *, struct proc *)); int ffs_truncate __P((struct vop_truncate_args *)); diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index ba3e82a..f7af3f3 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_inode.c 8.5 (Berkeley) 12/30/93 + * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95 * $FreeBSD$ */ @@ -59,14 +59,8 @@ #include <ufs/ffs/fs.h> #include <ufs/ffs/ffs_extern.h> -static int ffs_indirtrunc __P((struct inode *, daddr_t, daddr_t, daddr_t, int, - long *)); - -int -ffs_init() -{ - return (ufs_init()); -} +static int ffs_indirtrunc __P((struct inode *, ufs_daddr_t, ufs_daddr_t, + ufs_daddr_t, int, long *)); /* * Update the access, modified, and inode change times as specified by the @@ -115,15 +109,15 @@ ffs_update(ap) */ tv_sec = time.tv_sec; if (ip->i_flag & IN_ACCESS) - ip->i_atime.tv_sec = + ip->i_atime = (ap->a_access == &time ? tv_sec : ap->a_access->tv_sec); if (ip->i_flag & IN_UPDATE) { - ip->i_mtime.tv_sec = + ip->i_mtime = (ap->a_modify == &time ? tv_sec : ap->a_modify->tv_sec); ip->i_modrev++; } if (ip->i_flag & IN_CHANGE) - ip->i_ctime.tv_sec = tv_sec; + ip->i_ctime = tv_sec; ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); fs = ip->i_fs; /* @@ -169,10 +163,10 @@ ffs_truncate(ap) } */ *ap; { register struct vnode *ovp = ap->a_vp; - register daddr_t lastblock; + ufs_daddr_t lastblock; register struct inode *oip; - daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; - daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; + ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; + ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; off_t length = ap->a_length; register struct fs *fs; struct buf *bp; @@ -185,8 +179,10 @@ ffs_truncate(ap) oip = VTOI(ovp); fs = oip->i_fs; - if (length < 0 || length > fs->fs_maxfilesize) + if (length < 0) return (EINVAL); + if (length > fs->fs_maxfilesize) + return (EFBIG); tv = time; if (ovp->v_type == VLNK && (oip->i_size < ovp->v_mount->mnt_maxsymlinklen || oip->i_din.di_blocks == 0)) { @@ -220,12 +216,12 @@ ffs_truncate(ap) aflags = B_CLRBUF; if (ap->a_flags & IO_SYNC) aflags |= B_SYNC; - vnode_pager_setsize(ovp, length); error = ffs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp, aflags); if (error) return (error); oip->i_size = length; + vnode_pager_setsize(ovp, length); if (aflags & B_SYNC) bwrite(bp); else if (ovp->v_mount->mnt_flag & MNT_ASYNC) @@ -264,6 +260,7 @@ ffs_truncate(ap) else bawrite(bp); } + vnode_pager_setsize(ovp, length); /* * Calculate index into inode's block list of * last direct and indirect blocks (if any) @@ -413,17 +410,17 @@ done: static int ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) register struct inode *ip; - daddr_t lbn, lastbn; - daddr_t dbn; + ufs_daddr_t lbn, lastbn; + ufs_daddr_t dbn; int level; long *countp; { register int i; struct buf *bp; register struct fs *fs = ip->i_fs; - register daddr_t *bap; + register ufs_daddr_t *bap; struct vnode *vp; - daddr_t *copy = NULL, nb, nlbn, last; + ufs_daddr_t *copy = NULL, nb, nlbn, last; long blkcount, factor; int nblocks, blocksreleased = 0; int error = 0, allerror = 0; @@ -466,12 +463,12 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) return (error); } - bap = (daddr_t *)bp->b_data; + bap = (ufs_daddr_t *)bp->b_data; if (lastbn != -1) { - MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); + MALLOC(copy, ufs_daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); bzero((caddr_t)&bap[last + 1], - (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); + (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t)); if ((vp->v_mount->mnt_flag & MNT_ASYNC) == 0) { error = bwrite(bp); if (error) @@ -491,9 +488,8 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) if (nb == 0) continue; if (level > SINGLE) { - error = ffs_indirtrunc(ip, nlbn, - fsbtodb(fs, nb), (daddr_t)-1, level - 1, &blkcount); - if (error) + if (error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), + (ufs_daddr_t)-1, level - 1, &blkcount)) allerror = error; blocksreleased += blkcount; } diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 1cb9f3f..629a228 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -30,22 +30,26 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_subr.c 8.2 (Berkeley) 9/21/93 + * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 * $FreeBSD$ */ #include <sys/param.h> -#include <ufs/ffs/fs.h> -#ifdef KERNEL +#ifndef KERNEL +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> +#else #include "opt_ddb.h" #include <sys/systm.h> #include <sys/vnode.h> -#include <ufs/ffs/ffs_extern.h> #include <sys/buf.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> +#include <ufs/ffs/ffs_extern.h> /* * Return buffer with the contents of block "offset" from the beginning of @@ -64,7 +68,7 @@ ffs_blkatoff(ap) struct inode *ip; register struct fs *fs; struct buf *bp; - daddr_t lbn; + ufs_daddr_t lbn; int bsize, error; ip = VTOI(ap->a_vp); @@ -93,7 +97,7 @@ void ffs_fragacct(fs, fragmap, fraglist, cnt) struct fs *fs; int fragmap; - long fraglist[]; + int32_t fraglist[]; int cnt; { int inblk; @@ -127,7 +131,7 @@ ffs_checkoverlap(bp, ip) struct inode *ip; { register struct buf *ebp, *ep; - register daddr_t start, last; + register ufs_daddr_t start, last; struct vnode *vp; ebp = &buf[nbuf]; @@ -137,7 +141,8 @@ ffs_checkoverlap(bp, ip) if (ep == bp || (ep->b_flags & B_INVAL) || ep->b_vp == NULLVP) continue; - if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0, NULL, NULL)) + if (VOP_BMAP(ep->b_vp, (ufs_daddr_t)0, &vp, (ufs_daddr_t)0, + NULL)) continue; if (vp != ip->i_devvp) continue; @@ -163,7 +168,7 @@ int ffs_isblock(fs, cp, h) struct fs *fs; unsigned char *cp; - daddr_t h; + ufs_daddr_t h; { unsigned char mask; @@ -191,7 +196,7 @@ void ffs_clrblock(fs, cp, h) struct fs *fs; u_char *cp; - daddr_t h; + ufs_daddr_t h; { switch ((int)fs->fs_frag) { @@ -219,7 +224,7 @@ void ffs_setblock(fs, cp, h) struct fs *fs; unsigned char *cp; - daddr_t h; + ufs_daddr_t h; { switch ((int)fs->fs_frag) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 4b86cb0..c8b8959 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 + * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 * $FreeBSD$ */ @@ -72,8 +72,9 @@ static int ffs_sbupdate __P((struct ufsmount *, int)); static int ffs_reload __P((struct mount *,struct ucred *,struct proc *)); static int ffs_oldfscompat __P((struct fs *)); -static int ffs_mount __P((struct mount *, - char *, caddr_t, struct nameidata *, struct proc *)); +static int ffs_mount __P((struct mount *, char *, caddr_t, + struct nameidata *, struct proc *)); +static int ffs_init __P((struct vfsconf *)); struct vfsops ufs_vfsops = { ffs_mount, @@ -93,7 +94,6 @@ VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0); extern u_long nextgennumber; - /* * ffs_mount * @@ -133,7 +133,7 @@ extern u_long nextgennumber; */ static int ffs_mount( mp, path, data, ndp, p) - register struct mount *mp; /* mount struct pointer*/ + struct mount *mp; /* mount struct pointer*/ char *path; /* path to mount point*/ caddr_t data; /* arguments to FS specific mount*/ struct nameidata *ndp; /* mount point credentials*/ @@ -159,13 +159,10 @@ ffs_mount( mp, path, data, ndp, p) */ /* Get vnode for root device*/ - if( bdevvp( rootdev, &rootvp)) - panic("ffs_mountroot: can't setup bdevvp for root"); - - /* - * FS specific handling - */ - mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ + if ((err = bdevvp( rootdev, &rootvp))) { + printf("ffs_mountroot: can't setup bdevvp for root"); + return (err); + } /* * Attempt mount @@ -202,12 +199,7 @@ ffs_mount( mp, path, data, ndp, p) flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - if (vfs_busy(mp)) { - err = EBUSY; - goto error_1; - } err = ffs_flushfiles(mp, flags, p); - vfs_unbusy(mp); } if (!err && (mp->mnt_flag & MNT_RELOAD)) err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); @@ -341,7 +333,6 @@ success: return( err); } - /* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must @@ -365,8 +356,10 @@ ffs_reload(mp, cred, p) struct inode *ip; struct csum *space; struct buf *bp; - struct fs *fs; + struct fs *fs, *newfs; + struct partinfo dpart; int i, blks, size, error; + int32_t *lp; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -379,24 +372,33 @@ ffs_reload(mp, cred, p) /* * Step 2: re-read superblock from disk. */ - error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); - if (error) + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) + size = DEV_BSIZE; + else + size = dpart.disklab->d_secsize; + if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) return (error); - fs = (struct fs *)bp->b_data; - fs->fs_fmod = 0; - if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || - fs->fs_bsize < sizeof(struct fs)) { - brelse(bp); - return (EIO); /* XXX needs translation */ + newfs = (struct fs *)bp->b_data; + if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE || + newfs->fs_bsize < sizeof(struct fs)) { + brelse(bp); + return (EIO); /* XXX needs translation */ } fs = VFSTOUFS(mp)->um_fs; - bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0], - sizeof(fs->fs_csp)); - bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize); + /* + * Copy pointer fields back into superblock before copying in XXX + * 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_maxcluster = fs->fs_maxcluster; + bcopy(newfs, fs, (u_int)fs->fs_sbsize); if (fs->fs_sbsize < SBSIZE) bp->b_flags |= B_INVAL; brelse(bp); + mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; ffs_oldfscompat(fs); + /* * Step 3: re-read summary information from disk. */ @@ -413,21 +415,36 @@ ffs_reload(mp, cred, p) bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); brelse(bp); } + /* + * We no longer know anything about clusters per cylinder group. + */ + if (fs->fs_contigsumsize > 0) { + lp = fs->fs_maxcluster; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } + loop: + simple_lock(&mntvnode_slock); for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { + if (vp->v_mount != mp) { + simple_unlock(&mntvnode_slock); + goto loop; + } nvp = vp->v_mntvnodes.le_next; /* * Step 4: invalidate all inactive vnodes. */ - if (vp->v_usecount == 0) { - vgone(vp); - continue; - } + if (vrecycle(vp, &mntvnode_slock, p)) + goto loop; /* * Step 5: invalidate all cached file data. */ - if (vget(vp, 1)) + simple_lock(&vp->v_interlock); + simple_unlock(&mntvnode_slock); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) { goto loop; + } if (vinvalbuf(vp, 0, cred, p, 0, 0)) panic("ffs_reload: dirty2"); /* @@ -445,9 +462,9 @@ loop: ino_to_fsbo(fs, ip->i_number)); brelse(bp); vput(vp); - if (vp->v_mount != mp) - goto loop; + simple_lock(&mntvnode_slock); } + simple_unlock(&mntvnode_slock); return (0); } @@ -463,15 +480,18 @@ ffs_mountfs(devvp, mp, p) register struct ufsmount *ump; struct buf *bp; register struct fs *fs; - dev_t dev = devvp->v_rdev; + dev_t dev; struct partinfo dpart; caddr_t base, space; - int havepart = 0, blks; - int error, i, size; - int ronly; + int error, i, blks, size, ronly; + int32_t *lp; + struct ucred *cred; + u_int64_t maxfilesize; /* XXX */ u_int strsize; int ncount; + dev = devvp->v_rdev; + cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use @@ -486,25 +506,21 @@ ffs_mountfs(devvp, mp, p) ncount -= 1; if (ncount > 1 && devvp != rootvp) return (EBUSY); - error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); - if (error) + if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); - if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; - else { - havepart = 1; + else size = dpart.disklab->d_secsize; - } bp = NULL; ump = NULL; - error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); - if (error) + if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, cred, &bp)) goto out; fs = (struct fs *)bp->b_data; if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || @@ -522,6 +538,11 @@ ffs_mountfs(devvp, mp, p) goto out; } } + /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */ + if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) { + error = EROFS; /* needs translation */ + goto out; + } ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, @@ -537,16 +558,17 @@ ffs_mountfs(devvp, mp, p) fs->fs_fmod = 1; fs->fs_clean = 0; } - blks = howmany(fs->fs_cssize, fs->fs_fsize); - base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, - M_WAITOK); + size = fs->fs_cssize; + 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); 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; - error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, - NOCRED, &bp); - if (error) { + if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + cred, &bp)) { free(base, M_UFSMNT); goto out; } @@ -556,11 +578,15 @@ ffs_mountfs(devvp, mp, p) brelse(bp); bp = NULL; } + if (fs->fs_contigsumsize > 0) { + fs->fs_maxcluster = lp = (int32_t *)space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; - mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; + mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; - mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; @@ -589,8 +615,15 @@ ffs_mountfs(devvp, mp, p) */ mp->mnt_time = fs->fs_time; } - if (ronly == 0) - ffs_sbupdate(ump, MNT_WAIT); + + ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */ + maxfilesize = (u_int64_t)0x40000000 * fs->fs_bsize - 1; /* XXX */ + if (fs->fs_maxfilesize > maxfilesize) /* XXX */ + fs->fs_maxfilesize = maxfilesize; /* XXX */ + if (ronly == 0) { + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT); + } /* * Only VMIO the backing device if the backing device is a real * block device. This excludes the original MFS implementation. @@ -604,7 +637,7 @@ ffs_mountfs(devvp, mp, p) out: if (bp) brelse(bp); - (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); + (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); if (ump) { free(ump->um_fs, M_UFSMNT); free(ump, M_UFSMNT); @@ -630,7 +663,8 @@ ffs_oldfscompat(fs) if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ #if 0 int i; /* XXX */ - quad_t sizepb = fs->fs_bsize; /* XXX */ + u_int64_t sizepb = fs->fs_bsize; /* XXX */ + /* XXX */ fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ for (i = 0; i < NIADDR; i++) { /* XXX */ sizepb *= NINDIR(fs); /* XXX */ @@ -655,7 +689,7 @@ ffs_unmount(mp, mntflags, p) { register struct ufsmount *ump; register struct fs *fs; - int error, flags, ronly; + int error, flags; flags = 0; if (mntflags & MNT_FORCE) { @@ -666,18 +700,21 @@ ffs_unmount(mp, mntflags, p) return (error); ump = VFSTOUFS(mp); fs = ump->um_fs; - ronly = fs->fs_ronly; - if (!ronly) { + if (fs->fs_ronly == 0) { fs->fs_clean = 1; - ffs_sbupdate(ump, MNT_WAIT); + error = ffs_sbupdate(ump, MNT_WAIT); + if (error) { + fs->fs_clean = 0; + return (error); + } } ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; - VOP_LOCK(ump->um_devvp); - vnode_pager_uncache(ump->um_devvp); - VOP_UNLOCK(ump->um_devvp); + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); + vnode_pager_uncache(ump->um_devvp, p); + VOP_UNLOCK(ump->um_devvp, 0, p); - error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, + error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, NOCRED, p); vrele(ump->um_devvp); @@ -686,7 +723,6 @@ ffs_unmount(mp, mntflags, p) free(fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; - mp->mnt_flag &= ~MNT_LOCAL; return (error); } @@ -702,8 +738,6 @@ ffs_flushfiles(mp, flags, p) register struct ufsmount *ump; int error; - if (!doforce) - flags &= ~FORCECLOSE; ump = VFSTOUFS(mp); #ifdef QUOTA if (mp->mnt_flag & MNT_QUOTA) { @@ -742,7 +776,6 @@ ffs_statfs(mp, sbp, p) fs = ump->um_fs; if (fs->fs_magic != FS_MAGIC) panic("ffs_statfs"); - sbp->f_type = MOUNT_UFS; sbp->f_bsize = fs->fs_fsize; sbp->f_iosize = fs->fs_bsize; sbp->f_blocks = fs->fs_dsize; @@ -752,6 +785,7 @@ ffs_statfs(mp, sbp, p) sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; sbp->f_ffree = fs->fs_cstotal.cs_nifree; if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy((caddr_t)mp->mnt_stat.f_mntonname, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); bcopy((caddr_t)mp->mnt_stat.f_mntfromname, @@ -774,31 +808,22 @@ ffs_sync(mp, waitfor, cred, p) struct ucred *cred; struct proc *p; { - register struct vnode *vp, *nvp; - register struct inode *ip; - register struct ufsmount *ump = VFSTOUFS(mp); - register struct fs *fs; + struct vnode *nvp, *vp; + struct inode *ip; + struct ufsmount *ump = VFSTOUFS(mp); + struct fs *fs; struct timeval tv; int error, allerror = 0; fs = ump->um_fs; - /* - * Write back modified superblock. - * Consistency check that the superblock - * is still in the buffer cache. - */ - if (fs->fs_fmod != 0) { - if (fs->fs_ronly != 0) { /* XXX */ - printf("fs = %s\n", fs->fs_fsmnt); - panic("update: rofs mod"); - } - fs->fs_fmod = 0; - fs->fs_time = time.tv_sec; - allerror = ffs_sbupdate(ump, waitfor); + if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */ + printf("fs = %s\n", fs->fs_fsmnt); + panic("update: rofs mod"); } /* * Write back each (modified) inode. */ + simple_lock(&mntvnode_slock); loop: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { /* @@ -807,27 +832,40 @@ loop: */ if (vp->v_mount != mp) goto loop; + simple_lock(&vp->v_interlock); nvp = vp->v_mntvnodes.le_next; - if (VOP_ISLOCKED(vp)) - continue; ip = VTOI(vp); - if ((((ip->i_flag & - (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)) && - vp->v_dirtyblkhd.lh_first == NULL) + if (((ip->i_flag & + (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && + vp->v_dirtyblkhd.lh_first == NULL) { + simple_unlock(&vp->v_interlock); continue; + } if (vp->v_type != VCHR) { - if (vget(vp, 1)) - goto loop; - error = VOP_FSYNC(vp, cred, waitfor, p); - if (error) + simple_unlock(&mntvnode_slock); + error = + vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); + if (error) { + simple_lock(&mntvnode_slock); + if (error == ENOENT) + goto loop; + continue; + } + if (error = VOP_FSYNC(vp, cred, waitfor, p)) allerror = error; - vput(vp); + VOP_UNLOCK(vp, 0, p); + vrele(vp); + simple_lock(&mntvnode_slock); } else { + simple_unlock(&mntvnode_slock); + simple_unlock(&vp->v_interlock); tv = time; /* VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT); */ VOP_UPDATE(vp, &tv, &tv, 0); + simple_lock(&mntvnode_slock); } } + simple_unlock(&mntvnode_slock); /* * Force stale file system control information to be flushed. */ @@ -837,6 +875,15 @@ loop: #ifdef QUOTA qsync(mp); #endif + /* + * Write back modified superblock. + */ + if (fs->fs_fmod != 0) { + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; + if (error = ffs_sbupdate(ump, waitfor)) + allerror = error; + } return (allerror); } @@ -854,8 +901,8 @@ ffs_vget(mp, ino, vpp) ino_t ino; struct vnode **vpp; { - register struct fs *fs; - register struct inode *ip; + struct fs *fs; + struct inode *ip; struct ufsmount *ump; struct buf *bp; struct vnode *vp; @@ -903,6 +950,7 @@ restart: 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; ip->i_fs = fs = ump->um_fs; @@ -1035,6 +1083,17 @@ ffs_vptofh(vp, fhp) } /* + * Initialize the filesystem; just use ufs_init. + */ +static int +ffs_init(vfsp) + struct vfsconf *vfsp; +{ + + return (ufs_init(vfsp)); +} + +/* * Write a superblock and associated information back to disk. */ static int @@ -1042,21 +1101,15 @@ ffs_sbupdate(mp, waitfor) struct ufsmount *mp; int waitfor; { - register struct fs *fs = mp->um_fs; + register struct fs *dfs, *fs = mp->um_fs; register struct buf *bp; int blks; caddr_t space; - int i, size, error = 0; + int i, size, error, allerror = 0; - bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); - bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); - /* Restore compatibility to old file systems. XXX */ - if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ - ((struct fs *)bp->b_data)->fs_nrpos = -1; /* XXX */ - if (waitfor == MNT_WAIT) - error = bwrite(bp); - else - bawrite(bp); + /* + * First write back the summary information. + */ blks = howmany(fs->fs_cssize, fs->fs_fsize); space = (caddr_t)fs->fs_csp[0]; for (i = 0; i < blks; i += fs->fs_frag) { @@ -1067,10 +1120,37 @@ ffs_sbupdate(mp, waitfor) size, 0, 0); bcopy(space, bp->b_data, (u_int)size); space += size; - if (waitfor == MNT_WAIT) - error = bwrite(bp); - else + if (waitfor != MNT_WAIT) bawrite(bp); + else if (error = bwrite(bp)) + allerror = error; } - return (error); + /* + * Now write back the superblock itself. If any errors occurred + * up to this point, then fail so that the superblock avoids + * being written out as clean. + */ + if (allerror) + return (allerror); + bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); + bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); + /* Restore compatibility to old file systems. XXX */ + dfs = (struct fs *)bp->b_data; /* XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + dfs->fs_nrpos = -1; /* XXX */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + int32_t *lp, tmp; /* XXX */ + /* XXX */ + lp = (int32_t *)&dfs->fs_qbmask; /* XXX */ + tmp = lp[4]; /* XXX */ + for (i = 4; i > 0; i--) /* XXX */ + lp[i] = lp[i-1]; /* XXX */ + lp[0] = tmp; /* XXX */ + } /* XXX */ + dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ + if (waitfor != MNT_WAIT) + bawrite(bp); + else if (error = bwrite(bp)) + allerror = error; + return (allerror); } diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index c3f750b..ddce646 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_vnops.c 8.7 (Berkeley) 2/3/94 + * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 * $FreeBSD$ */ @@ -62,6 +62,7 @@ #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> +#include <ufs/ufs/ufsmount.h> #include <ufs/ufs/ufs_extern.h> #include <ufs/ffs/fs.h> @@ -78,6 +79,7 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_default_desc, (vop_t *)vn_default_error }, { &vop_lookup_desc, (vop_t *)ufs_lookup }, /* lookup */ { &vop_create_desc, (vop_t *)ufs_create }, /* create */ + { &vop_whiteout_desc, (vop_t *)ufs_whiteout }, /* whiteout */ { &vop_mknod_desc, (vop_t *)ufs_mknod }, /* mknod */ { &vop_open_desc, (vop_t *)ufs_open }, /* open */ { &vop_close_desc, (vop_t *)ufs_close }, /* close */ @@ -86,8 +88,10 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_setattr_desc, (vop_t *)ufs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)ffs_read }, /* read */ { &vop_write_desc, (vop_t *)ffs_write }, /* write */ + { &vop_lease_desc, (vop_t *)ufs_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)ufs_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)ufs_select }, /* select */ + { &vop_revoke_desc, (vop_t *)ufs_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)ufs_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)ffs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)ufs_seek }, /* seek */ @@ -101,7 +105,7 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_readlink_desc, (vop_t *)ufs_readlink }, /* readlink */ { &vop_abortop_desc, (vop_t *)ufs_abortop }, /* abortop */ { &vop_inactive_desc, (vop_t *)ufs_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)ufs_reclaim }, /* reclaim */ + { &vop_reclaim_desc, (vop_t *)ffs_reclaim }, /* reclaim */ { &vop_lock_desc, (vop_t *)ufs_lock }, /* lock */ { &vop_unlock_desc, (vop_t *)ufs_unlock }, /* unlock */ { &vop_bmap_desc, (vop_t *)ufs_bmap }, /* bmap */ @@ -136,8 +140,10 @@ static struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_setattr_desc, (vop_t *)ufs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)ufsspec_read }, /* read */ { &vop_write_desc, (vop_t *)ufsspec_write }, /* write */ + { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)spec_select }, /* select */ + { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)ffs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ @@ -151,7 +157,7 @@ static struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */ { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */ { &vop_inactive_desc, (vop_t *)ufs_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)ufs_reclaim }, /* reclaim */ + { &vop_reclaim_desc, (vop_t *)ffs_reclaim }, /* reclaim */ { &vop_lock_desc, (vop_t *)ufs_lock }, /* lock */ { &vop_unlock_desc, (vop_t *)ufs_unlock }, /* unlock */ { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */ @@ -186,8 +192,10 @@ static struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_setattr_desc, (vop_t *)ufs_setattr }, /* setattr */ { &vop_read_desc, (vop_t *)ufsfifo_read }, /* read */ { &vop_write_desc, (vop_t *)ufsfifo_write }, /* write */ + { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */ { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ { &vop_select_desc, (vop_t *)fifo_select }, /* select */ + { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */ { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ { &vop_fsync_desc, (vop_t *)ffs_fsync }, /* fsync */ { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ @@ -201,7 +209,7 @@ static struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */ { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */ { &vop_inactive_desc, (vop_t *)ufs_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *)ufs_reclaim }, /* reclaim */ + { &vop_reclaim_desc, (vop_t *)ffs_reclaim }, /* reclaim */ { &vop_lock_desc, (vop_t *)ufs_lock }, /* lock */ { &vop_unlock_desc, (vop_t *)ufs_unlock }, /* unlock */ { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */ @@ -226,20 +234,16 @@ VNODEOP_SET(ffs_vnodeop_opv_desc); VNODEOP_SET(ffs_specop_opv_desc); VNODEOP_SET(ffs_fifoop_opv_desc); -#ifdef DEBUG /* * Enabling cluster read/write operations. */ -#include <sys/sysctl.h> int doclusterread = 1; -SYSCTL_INT(_debug, 11, doclusterread, CTLFLAG_RW, &doclusterread, 0, ""); int doclusterwrite = 1; -SYSCTL_INT(_debug, 12, doclusterwrite, CTLFLAG_RW, &doclusterwrite, 0, ""); -#else -/* XXX for ufs_readwrite */ -#define doclusterread 1 -#define doclusterwrite 1 -#endif + +#include <sys/sysctl.h> +SYSCTL_NODE(_vfs_ffs, MOUNT_UFS, ffs, CTLFLAG_RW, 0, "FFS"); +SYSCTL_INT(_vfs_ffs, FFS_CLUSTERREAD, doclusterread, CTLFLAG_RW, &doclusterread, 0, ""); +SYSCTL_INT(_vfs_ffs, FFS_CLUSTERWRITE, doclusterwrite, CTLFLAG_RW, &doclusterwrite, 0, ""); #include <ufs/ufs/ufs_readwrite.c> @@ -320,3 +324,24 @@ loop: tv = time; return (VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT)); } + +/* + * Reclaim an inode so that it can be used for other purposes. + */ +int +ffs_reclaim(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct proc *a_p; + } */ *ap; +{ + register struct vnode *vp = ap->a_vp; + int error; + + if (error = ufs_reclaim(vp, ap->a_p)) + return (error); + FREE(vp->v_data, VFSTOUFS(vp->v_mount)->um_devvp->v_tag == VT_MFS ? + M_MFSNODE : M_FFSNODE); + vp->v_data = NULL; + return (0); +} diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 16862c4..02720da 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)fs.h 8.7 (Berkeley) 4/19/94 + * @(#)fs.h 8.13 (Berkeley) 3/21/95 * $FreeBSD$ */ @@ -65,8 +65,8 @@ #define SBSIZE 8192 #define BBOFF ((off_t)(0)) #define SBOFF ((off_t)(BBOFF + BBSIZE)) -#define BBLOCK ((daddr_t)(0)) -#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) +#define BBLOCK ((ufs_daddr_t)(0)) +#define SBLOCK ((ufs_daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) /* * Addresses stored in inodes are capable of addressing fragments @@ -102,12 +102,18 @@ * The path name on which the file system is mounted is maintained * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in * the super block for this name. + */ +#define MAXMNTLEN 512 + +/* * The limit on the amount of summary information per file system * is defined by MAXCSBUFS. It is currently parameterized for a - * maximum of two million cylinders. + * size of 128 bytes (2 million cylinder groups on machines with + * 32-bit pointers, and 1 million on 64-bit machines). One pointer + * is taken away to point to an array of cluster sizes that is + * computed as cylinder groups are inspected. */ -#define MAXMNTLEN 512 -#define MAXCSBUFS 32 +#define MAXCSBUFS ((128 / sizeof(void *)) - 1) /* * A summary of contiguous blocks of various sizes is maintained @@ -142,103 +148,105 @@ * the ``fs_cs'' macro to work (see below). */ struct csum { - long cs_ndir; /* number of directories */ - long cs_nbfree; /* number of free blocks */ - long cs_nifree; /* number of free inodes */ - long cs_nffree; /* number of free frags */ + int32_t cs_ndir; /* number of directories */ + int32_t cs_nbfree; /* number of free blocks */ + int32_t cs_nifree; /* number of free inodes */ + int32_t cs_nffree; /* number of free frags */ }; /* - * Super block for a file system. + * Super block for an FFS file system. */ struct fs { - struct fs *fs_link; /* linked list of file systems */ - struct fs *fs_rlink; /* used for incore super blocks */ - daddr_t fs_sblkno; /* addr of super-block in filesys */ - daddr_t fs_cblkno; /* offset of cyl-block in filesys */ - daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ - daddr_t fs_dblkno; /* offset of first data after cg */ - long fs_cgoffset; /* cylinder group offset in cylinder */ - long fs_cgmask; /* used to calc mod fs_ntrak */ - time_t fs_time; /* last time written */ - long fs_size; /* number of blocks in fs */ - long fs_dsize; /* number of data blocks in fs */ - long fs_ncg; /* number of cylinder groups */ - long fs_bsize; /* size of basic blocks in fs */ - long fs_fsize; /* size of frag blocks in fs */ - long fs_frag; /* number of frags in a block in fs */ + int32_t fs_firstfield; /* historic file system linked list, */ + int32_t fs_unused_1; /* used for incore super blocks */ + ufs_daddr_t fs_sblkno; /* addr of super-block in filesys */ + ufs_daddr_t fs_cblkno; /* offset of cyl-block in filesys */ + ufs_daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ + ufs_daddr_t fs_dblkno; /* offset of first data after cg */ + int32_t fs_cgoffset; /* cylinder group offset in cylinder */ + int32_t fs_cgmask; /* used to calc mod fs_ntrak */ + time_t fs_time; /* last time written */ + int32_t fs_size; /* number of blocks in fs */ + int32_t fs_dsize; /* number of data blocks in fs */ + int32_t fs_ncg; /* number of cylinder groups */ + int32_t fs_bsize; /* size of basic blocks in fs */ + int32_t fs_fsize; /* size of frag blocks in fs */ + int32_t fs_frag; /* number of frags in a block in fs */ /* these are configuration parameters */ - long fs_minfree; /* minimum percentage of free blocks */ - long fs_rotdelay; /* num of ms for optimal next block */ - long fs_rps; /* disk revolutions per second */ + int32_t fs_minfree; /* minimum percentage of free blocks */ + int32_t fs_rotdelay; /* num of ms for optimal next block */ + int32_t fs_rps; /* disk revolutions per second */ /* these fields can be computed from the others */ - long fs_bmask; /* ``blkoff'' calc of blk offsets */ - long fs_fmask; /* ``fragoff'' calc of frag offsets */ - long fs_bshift; /* ``lblkno'' calc of logical blkno */ - long fs_fshift; /* ``numfrags'' calc number of frags */ + int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ + int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ + int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ + int32_t fs_fshift; /* ``numfrags'' calc number of frags */ /* these are configuration parameters */ - long fs_maxcontig; /* max number of contiguous blks */ - long fs_maxbpg; /* max number of blks per cyl group */ + int32_t fs_maxcontig; /* max number of contiguous blks */ + int32_t fs_maxbpg; /* max number of blks per cyl group */ /* these fields can be computed from the others */ - long fs_fragshift; /* block to frag shift */ - long fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ - long fs_sbsize; /* actual size of super block */ - long fs_csmask; /* csum block offset */ - long fs_csshift; /* csum block number */ - long fs_nindir; /* value of NINDIR */ - long fs_inopb; /* value of INOPB */ - long fs_nspf; /* value of NSPF */ + int32_t fs_fragshift; /* block to frag shift */ + int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int32_t fs_sbsize; /* actual size of super block */ + int32_t fs_csmask; /* csum block offset */ + int32_t fs_csshift; /* csum block number */ + int32_t fs_nindir; /* value of NINDIR */ + int32_t fs_inopb; /* value of INOPB */ + int32_t fs_nspf; /* value of NSPF */ /* yet another configuration parameter */ - long fs_optim; /* optimization preference, see below */ + int32_t fs_optim; /* optimization preference, see below */ /* these fields are derived from the hardware */ - long fs_npsect; /* # sectors/track including spares */ - long fs_interleave; /* hardware sector interleave */ - long fs_trackskew; /* sector 0 skew, per track */ - long fs_headswitch; /* head switch time, usec */ - long fs_trkseek; /* track-to-track seek, usec */ + int32_t fs_npsect; /* # sectors/track including spares */ + int32_t fs_interleave; /* hardware sector interleave */ + int32_t fs_trackskew; /* sector 0 skew, per track */ + int32_t fs_headswitch; /* head switch time, usec */ + int32_t fs_trkseek; /* track-to-track seek, usec */ /* sizes determined by number of cylinder groups and their sizes */ - daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ - long fs_cssize; /* size of cyl grp summary area */ - long fs_cgsize; /* cylinder group size */ + ufs_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int32_t fs_cssize; /* size of cyl grp summary area */ + int32_t fs_cgsize; /* cylinder group size */ /* these fields are derived from the hardware */ - long fs_ntrak; /* tracks per cylinder */ - long fs_nsect; /* sectors per track */ - long fs_spc; /* sectors per cylinder */ + int32_t fs_ntrak; /* tracks per cylinder */ + int32_t fs_nsect; /* sectors per track */ + int32_t fs_spc; /* sectors per cylinder */ /* this comes from the disk driver partitioning */ - long fs_ncyl; /* cylinders in file system */ + int32_t fs_ncyl; /* cylinders in file system */ /* these fields can be computed from the others */ - long fs_cpg; /* cylinders per group */ - long fs_ipg; /* inodes per group */ - long fs_fpg; /* blocks per group * fs_frag */ + int32_t fs_cpg; /* cylinders per group */ + int32_t fs_ipg; /* inodes per group */ + int32_t fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ struct csum fs_cstotal; /* cylinder summary information */ /* these fields are cleared at mount time */ - char fs_fmod; /* super block modified flag */ - char fs_clean; /* file system is clean flag */ - char fs_ronly; /* mounted read-only flag */ - char fs_flags; /* currently unused flag */ - char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ + int8_t fs_fmod; /* super block modified flag */ + int8_t fs_clean; /* file system is clean flag */ + int8_t fs_ronly; /* mounted read-only flag */ + int8_t fs_flags; /* currently unused flag */ + u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ /* these fields retain the current block allocation info */ - long fs_cgrotor; /* last cg searched */ + int32_t fs_cgrotor; /* last cg searched */ struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */ - long fs_cpc; /* cyl per cycle in postbl */ - short fs_opostbl[16][8]; /* old rotation block list head */ - long fs_sparecon[50]; /* reserved for future constants */ - long fs_contigsumsize; /* size of cluster summary array */ - long fs_maxsymlinklen; /* max length of an internal symlink */ - long fs_inodefmt; /* format of on-disk inodes */ - u_quad_t fs_maxfilesize; /* maximum representable file size */ - quad_t fs_qbmask; /* ~fs_bmask - for use with quad size */ - quad_t fs_qfmask; /* ~fs_fmask - for use with quad size */ - long fs_state; /* validate fs_clean field */ - long fs_postblformat; /* format of positional layout tables */ - long fs_nrpos; /* number of rotational positions */ - long fs_postbloff; /* (short) rotation block list head */ - long fs_rotbloff; /* (u_char) blocks for each rotation */ - long fs_magic; /* magic number */ - u_char fs_space[1]; /* list of blocks for each rotation */ + int32_t *fs_maxcluster; /* max cluster in each cyl group */ + int32_t fs_cpc; /* cyl per cycle in postbl */ + int16_t fs_opostbl[16][8]; /* old rotation block list head */ + int32_t fs_sparecon[50]; /* reserved for future constants */ + int32_t fs_contigsumsize; /* size of cluster summary array */ + int32_t fs_maxsymlinklen; /* max length of an internal symlink */ + int32_t fs_inodefmt; /* format of on-disk inodes */ + u_int64_t fs_maxfilesize; /* maximum representable file size */ + int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ + int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ + int32_t fs_state; /* validate fs_clean field */ + int32_t fs_postblformat; /* format of positional layout tables */ + int32_t fs_nrpos; /* number of rotational positions */ + int32_t fs_postbloff; /* (u_int16) rotation block list head */ + int32_t fs_rotbloff; /* (u_int8) blocks for each rotation */ + int32_t fs_magic; /* magic number */ + u_int8_t fs_space[1]; /* list of blocks for each rotation */ /* actually longer */ }; + /* * Filesystem identification */ @@ -263,11 +271,12 @@ struct fs { #define fs_postbl(fs, cylno) \ (((fs)->fs_postblformat == FS_42POSTBLFMT) \ ? ((fs)->fs_opostbl[cylno]) \ - : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) + : ((int16_t *)((u_int8_t *)(fs) + \ + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) #define fs_rotbl(fs) \ (((fs)->fs_postblformat == FS_42POSTBLFMT) \ ? ((fs)->fs_space) \ - : ((u_char *)((char *)(fs) + (fs)->fs_rotbloff))) + : ((u_int8_t *)((u_int8_t *)(fs) + (fs)->fs_rotbloff))) /* * The size of a cylinder group is calculated by CGSIZE. The maximum size @@ -276,13 +285,13 @@ struct fs { * cylinder group and the (struct cg) size. */ #define CGSIZE(fs) \ - /* base cg */ (sizeof(struct cg) + sizeof(long) + \ - /* blktot size */ (fs)->fs_cpg * sizeof(long) + \ - /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \ + /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ + /* blktot size */ (fs)->fs_cpg * sizeof(int32_t) + \ + /* blks size */ (fs)->fs_cpg * (fs)->fs_nrpos * sizeof(int16_t) + \ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ /* block map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY) +\ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ - /* cluster sum */ (fs)->fs_contigsumsize * sizeof(long) + \ + /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ /* cluster map */ howmany((fs)->fs_cpg * (fs)->fs_spc / NSPB(fs), NBBY))) /* @@ -297,79 +306,81 @@ struct fs { * Cylinder group block for a file system. */ #define CG_MAGIC 0x090255 -struct cg { - struct cg *cg_link; /* linked list of cyl groups */ - long cg_magic; /* magic number */ - time_t cg_time; /* time last written */ - long cg_cgx; /* we are the cgx'th cylinder group */ - short cg_ncyl; /* number of cyl's this cg */ - short cg_niblk; /* number of inode blocks this cg */ - long cg_ndblk; /* number of data blocks this cg */ +struct cg { + int32_t cg_firstfield; /* historic cyl groups linked list */ + int32_t cg_magic; /* magic number */ + time_t cg_time; /* time last written */ + int32_t cg_cgx; /* we are the cgx'th cylinder group */ + int16_t cg_ncyl; /* number of cyl's this cg */ + int16_t cg_niblk; /* number of inode blocks this cg */ + int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ - long cg_rotor; /* position of last used block */ - long cg_frotor; /* position of last used frag */ - long cg_irotor; /* position of last used inode */ - long cg_frsum[MAXFRAG]; /* counts of available frags */ - long cg_btotoff; /* (long) block totals per cylinder */ - long cg_boff; /* (short) free block positions */ - long cg_iusedoff; /* (char) used inode map */ - long cg_freeoff; /* (u_char) free block map */ - long cg_nextfreeoff; /* (u_char) next available space */ - long cg_clustersumoff; /* (long) counts of avail clusters */ - long cg_clusteroff; /* (char) free cluster map */ - long cg_nclusterblks; /* number of clusters this cg */ - long cg_sparecon[13]; /* reserved for future use */ - u_char cg_space[1]; /* space for cylinder group maps */ + int32_t cg_rotor; /* position of last used block */ + int32_t cg_frotor; /* position of last used frag */ + int32_t cg_irotor; /* position of last used inode */ + int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ + int32_t cg_btotoff; /* (int32) block totals per cylinder */ + int32_t cg_boff; /* (u_int16) free block positions */ + int32_t cg_iusedoff; /* (u_int8) used inode map */ + int32_t cg_freeoff; /* (u_int8) free block map */ + int32_t cg_nextfreeoff; /* (u_int8) next available space */ + int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ + int32_t cg_clusteroff; /* (u_int8) free cluster map */ + int32_t cg_nclusterblks; /* number of clusters this cg */ + int32_t cg_sparecon[13]; /* reserved for future use */ + u_int8_t cg_space[1]; /* space for cylinder group maps */ /* actually longer */ }; + /* * Macros for access to cylinder group array structures */ #define cg_blktot(cgp) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_btot) \ - : ((long *)((char *)(cgp) + (cgp)->cg_btotoff))) + : ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_btotoff))) #define cg_blks(fs, cgp, cylno) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_b[cylno]) \ - : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) + : ((int16_t *)((u_int8_t *)(cgp) + \ + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) #define cg_inosused(cgp) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_iused) \ - : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff))) + : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff))) #define cg_blksfree(cgp) \ (((cgp)->cg_magic != CG_MAGIC) \ ? (((struct ocg *)(cgp))->cg_free) \ - : ((u_char *)((char *)(cgp) + (cgp)->cg_freeoff))) + : ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff))) #define cg_chkmagic(cgp) \ ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) #define cg_clustersfree(cgp) \ - ((u_char *)((char *)(cgp) + (cgp)->cg_clusteroff)) + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) #define cg_clustersum(cgp) \ - ((long *)((char *)(cgp) + (cgp)->cg_clustersumoff)) + ((int32_t *)((u_int8_t *)(cgp) + (cgp)->cg_clustersumoff)) /* * The following structure is defined * for compatibility with old file systems. */ -struct ocg { - struct ocg *cg_link; /* linked list of cyl groups */ - struct ocg *cg_rlink; /* used for incore cyl groups */ - time_t cg_time; /* time last written */ - long cg_cgx; /* we are the cgx'th cylinder group */ - short cg_ncyl; /* number of cyl's this cg */ - short cg_niblk; /* number of inode blocks this cg */ - long cg_ndblk; /* number of data blocks this cg */ +struct ocg { + int32_t cg_firstfield; /* historic linked list of cyl groups */ + int32_t cg_unused_1; /* used for incore cyl groups */ + time_t cg_time; /* time last written */ + int32_t cg_cgx; /* we are the cgx'th cylinder group */ + int16_t cg_ncyl; /* number of cyl's this cg */ + int16_t cg_niblk; /* number of inode blocks this cg */ + int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ - long cg_rotor; /* position of last used block */ - long cg_frotor; /* position of last used frag */ - long cg_irotor; /* position of last used inode */ - long cg_frsum[8]; /* counts of available frags */ - long cg_btot[32]; /* block totals per cylinder */ - short cg_b[32][8]; /* positions of free blocks */ - char cg_iused[256]; /* used inode map */ - long cg_magic; /* magic number */ - u_char cg_free[1]; /* free block map */ + int32_t cg_rotor; /* position of last used block */ + int32_t cg_frotor; /* position of last used frag */ + int32_t cg_irotor; /* position of last used inode */ + int32_t cg_frsum[8]; /* counts of available frags */ + int32_t cg_btot[32]; /* block totals per cylinder */ + int16_t cg_b[32][8]; /* positions of free blocks */ + u_int8_t cg_iused[256]; /* used inode map */ + int32_t cg_magic; /* magic number */ + u_int8_t cg_free[1]; /* free block map */ /* actually longer */ }; @@ -384,7 +395,7 @@ struct ocg { * Cylinder group macros to locate things in cylinder groups. * They calc file system addresses of cylinder group data structures. */ -#define cgbase(fs, c) ((daddr_t)((fs)->fs_fpg * (c))) +#define cgbase(fs, c) ((ufs_daddr_t)((fs)->fs_fpg * (c))) #define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ #define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ #define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ @@ -400,7 +411,7 @@ struct ocg { */ #define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) #define ino_to_fsba(fs, x) \ - ((daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ + ((ufs_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) #define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) @@ -457,7 +468,7 @@ struct ocg { /* * Determine the number of available frags given a - * percentage to hold in reserve + * percentage to hold in reserve. */ #define freespace(fs, percentreserved) \ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ @@ -476,19 +487,20 @@ struct ocg { : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) /* - * Number of disk sectors per block; assumes DEV_BSIZE byte sector size. + * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte + * sector size. */ #define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) #define NSPF(fs) ((fs)->fs_nspf) /* - * INOPB is the number of inodes in a secondary storage block. + * Number of inodes in a secondary storage block/fragment. */ #define INOPB(fs) ((fs)->fs_inopb) #define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) /* - * NINDIR is the number of indirects in a file system block. + * Number of indirects in a file system block. */ #define NINDIR(fs) ((fs)->fs_nindir) |