diff options
author | julian <julian@FreeBSD.org> | 1998-03-08 09:59:44 +0000 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1998-03-08 09:59:44 +0000 |
commit | 10c5ccc30ae8155c4d8bd25aeffd9ed0e476c387 (patch) | |
tree | d2ed60b6b9462fe6eebf4796c39dfcf3cec39874 /sys/ufs/ffs | |
parent | 1d108bde84c6b5fa5d119363c4f401cc3dcc8110 (diff) | |
download | FreeBSD-src-10c5ccc30ae8155c4d8bd25aeffd9ed0e476c387.zip FreeBSD-src-10c5ccc30ae8155c4d8bd25aeffd9ed0e476c387.tar.gz |
Reviewed by: dyson@freebsd.org (john Dyson), dg@root.com (david greenman)
Submitted by: Kirk McKusick (mcKusick@mckusick.com)
Obtained from: WHistle development tree
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 93 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_balloc.c | 92 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 34 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_inode.c | 56 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_subr.c | 26 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 85 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 97 | ||||
-rw-r--r-- | sys/ufs/ffs/fs.h | 16 |
8 files changed, 386 insertions, 113 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index f2e6a74..8eab25a 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95 - * $Id: ffs_alloc.c,v 1.46 1998/02/04 22:33:27 eivind Exp $ + * $Id: ffs_alloc.c,v 1.47 1998/02/06 12:14:13 eivind Exp $ */ #include "opt_quota.h" @@ -57,7 +57,8 @@ typedef ufs_daddr_t allocfcn_t __P((struct inode *ip, int cg, ufs_daddr_t bpref, int size)); 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 ufs_daddr_t + ffs_alloccgblk __P((struct inode *, struct buf *, ufs_daddr_t)); #ifdef DIAGNOSTIC static int ffs_checkblk __P((struct inode *, ufs_daddr_t, long)); #endif @@ -292,7 +293,8 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) ffs_alloccg); if (bno > 0) { bp->b_blkno = fsbtodb(fs, bno); - ffs_blkfree(ip, bprev, (long)osize); + if (!DOINGSOFTDEP(ITOV(ip))) + ffs_blkfree(ip, bprev, (long)osize); if (nsize < request) ffs_blkfree(ip, bno + numfrags(fs, nsize), (long)(request - nsize)); @@ -455,8 +457,10 @@ ffs_reallocblks(ap) #endif blkno = newblk; for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { - if (i == ssize) + if (i == ssize) { bap = ebap; + soff = -i; + } #ifdef DIAGNOSTIC if (!ffs_checkblk(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) @@ -468,6 +472,16 @@ ffs_reallocblks(ap) if (prtrealloc) printf(" %d,", *bap); #endif + if (DOINGSOFTDEP(vp)) { + if (sbap == &ip->i_db[0] && i < ssize) + softdep_setup_allocdirect(ip, start_lbn + i, + blkno, *bap, fs->fs_bsize, fs->fs_bsize, + buflist->bs_children[i]); + else + softdep_setup_allocindir_page(ip, start_lbn + i, + i < ssize ? sbp : ebp, soff + i, blkno, + *bap, buflist->bs_children[i]); + } *bap++ = blkno; } /* @@ -509,8 +523,10 @@ ffs_reallocblks(ap) 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); + if (!DOINGSOFTDEP(vp)) + 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, @@ -847,6 +863,8 @@ ffs_fragextend(ip, cg, bprev, osize, nsize) fs->fs_cs(fs, cg).cs_nffree--; } fs->fs_fmod = 1; + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_blkmapdep(bp, fs, bprev); bdwrite(bp); return (bprev); } @@ -868,7 +886,8 @@ ffs_alloccg(ip, cg, bpref, size) register struct cg *cgp; struct buf *bp; register int i; - int error, bno, frags, allocsiz; + ufs_daddr_t bno, blkno; + int allocsiz, error, frags; fs = ip->i_fs; if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) @@ -887,7 +906,7 @@ ffs_alloccg(ip, cg, bpref, size) } cgp->cg_time = time.tv_sec; if (size == fs->fs_bsize) { - bno = ffs_alloccgblk(fs, cgp, bpref); + bno = ffs_alloccgblk(ip, bp, bpref); bdwrite(bp); return (bno); } @@ -909,7 +928,7 @@ ffs_alloccg(ip, cg, bpref, size) brelse(bp); return (0); } - bno = ffs_alloccgblk(fs, cgp, bpref); + bno = ffs_alloccgblk(ip, bp, bpref); bpref = dtogd(fs, bno); for (i = frags; i < fs->fs_frag; i++) setbit(cg_blksfree(cgp), bpref + i); @@ -936,8 +955,11 @@ ffs_alloccg(ip, cg, bpref, size) cgp->cg_frsum[allocsiz]--; if (frags != allocsiz) cgp->cg_frsum[allocsiz - frags]++; + blkno = cg * fs->fs_fpg + bno; + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_blkmapdep(bp, fs, blkno); bdwrite(bp); - return (cg * fs->fs_fpg + bno); + return ((u_long)blkno); } /* @@ -952,16 +974,20 @@ ffs_alloccg(ip, cg, bpref, size) * blocks may be fragmented by the routine that allocates them. */ static ufs_daddr_t -ffs_alloccgblk(fs, cgp, bpref) - register struct fs *fs; - register struct cg *cgp; +ffs_alloccgblk(ip, bp, bpref) + struct inode *ip; + struct buf *bp; ufs_daddr_t bpref; { + struct fs *fs; + struct cg *cgp; ufs_daddr_t bno, blkno; int cylno, pos, delta; short *cylbp; register int i; + fs = ip->i_fs; + cgp = (struct cg *)bp->b_data; if (bpref == 0 || dtog(fs, bpref) != cgp->cg_cgx) { bpref = cgp->cg_rotor; goto norot; @@ -1052,7 +1078,10 @@ gotit: cg_blks(fs, cgp, cylno)[cbtorpos(fs, bno)]--; cg_blktot(cgp)[cylno]--; fs->fs_fmod = 1; - return (cgp->cg_cgx * fs->fs_fpg + bno); + blkno = cgp->cg_cgx * fs->fs_fpg + bno; + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_blkmapdep(bp, fs, blkno); + return (blkno); } #ifdef notyet @@ -1155,7 +1184,7 @@ ffs_clusteralloc(ip, cg, bpref, len) panic("ffs_clusteralloc: allocated out of group"); len = blkstofrags(fs, len); for (i = 0; i < len; i += fs->fs_frag) - if ((got = ffs_alloccgblk(fs, cgp, bno + i)) != bno + i) + if ((got = ffs_alloccgblk(ip, bp, bno + i)) != bno + i) panic("ffs_clusteralloc: lost block"); bdwrite(bp); return (bno); @@ -1234,6 +1263,8 @@ ffs_nodealloccg(ip, cg, ipref, mode) panic("ffs_nodealloccg: block not in map"); /* NOTREACHED */ gotit: + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_inomapdep(bp, ip, cg * fs->fs_ipg + ipref); setbit(cg_inosused(cgp), ipref); cgp->cg_cs.cs_nifree--; fs->fs_cstotal.cs_nifree--; @@ -1268,9 +1299,10 @@ ffs_blkfree(ip, bno, size) int i, error, cg, blk, frags, bbase; fs = ip->i_fs; - if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { - printf("dev = 0x%lx, bsize = %ld, size = %ld, fs = %s\n", - (u_long)ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 || + fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { + printf("dev=0x%lx, bno = %d, bsize = %d, size = %ld, fs = %s\n", + (u_long)ip->i_dev, bno, fs->fs_bsize, size, fs->fs_fsmnt); panic("ffs_blkfree: bad size"); } cg = dtog(fs, bno); @@ -1294,7 +1326,7 @@ ffs_blkfree(ip, bno, size) bno = dtogd(fs, bno); if (size == fs->fs_bsize) { blkno = fragstoblks(fs, bno); - if (ffs_isblock(fs, cg_blksfree(cgp), blkno)) { + if (!ffs_isfreeblock(fs, cg_blksfree(cgp), blkno)) { printf("dev = 0x%lx, block = %ld, fs = %s\n", (u_long) ip->i_dev, bno, fs->fs_fsmnt); panic("ffs_blkfree: freeing free block"); @@ -1404,11 +1436,26 @@ ffs_checkblk(ip, bno, size) /* * Free an inode. - * - * The specified inode is placed back in the free map. */ int -ffs_vfree(pvp, ino, mode) +ffs_vfree( pvp, ino, mode) + struct vnode *pvp; + ino_t ino; + int mode; +{ + if (DOINGSOFTDEP(pvp)) { + softdep_freefile(pvp, ino, mode); + return (0); + } + return (ffs_freefile(pvp, ino, mode)); +} + +/* + * Do the actual free operation. + * The specified inode is placed back in the free map. + */ + int + ffs_freefile( pvp, ino, mode) struct vnode *pvp; ino_t ino; int mode; @@ -1429,7 +1476,7 @@ ffs_vfree(pvp, ino, mode) (int)fs->fs_cgsize, NOCRED, &bp); if (error) { brelse(bp); - return (0); + return (error); } cgp = (struct cg *)bp->b_data; if (!cg_chkmagic(cgp)) { diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index 60d2037..cf253b7 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -31,13 +31,14 @@ * SUCH DAMAGE. * * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 - * $Id: ffs_balloc.c,v 1.18 1998/02/04 22:33:31 eivind Exp $ + * $Id: ffs_balloc.c,v 1.19 1998/02/06 12:14:14 eivind Exp $ */ #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> #include <sys/lock.h> +#include <sys/mount.h> #include <sys/vnode.h> #include <ufs/ufs/quota.h> @@ -53,16 +54,23 @@ * the inode and the logical block number in a file. */ int -ffs_balloc(ip, lbn, size, cred, bpp, flags) +ffs_balloc(ap) + struct vop_balloc_args /* { + struct inode *a_ip; + ufs_daddr_t a_lbn; + int a_size; + struct ucred *a_cred; + int a_flags; + struct buf *a_bpp; + } */ *ap; +{ register struct inode *ip; register ufs_daddr_t lbn; int size; struct ucred *cred; - struct buf **bpp; int flags; -{ - register struct fs *fs; - register ufs_daddr_t nb; + struct fs *fs; + ufs_daddr_t nb; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[NIADDR + 2]; @@ -70,10 +78,18 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) int deallocated, osize, nsize, num, i, error; ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; - *bpp = NULL; + vp = ap->a_vp; + ip = VTOI(vp); + fs = ip->i_fs; + lbn = lblkno(fs, ap->a_startoffset); + size = blkoff(fs, ap->a_startoffset) + ap->a_size; + if (size > fs->fs_bsize) + panic("ffs_balloc: blk too big"); + *ap->a_bpp = NULL; if (lbn < 0) return (EFBIG); - fs = ip->i_fs; + cred = ap->a_cred; + flags = ap->a_flags; /* * If the next write will extend the file into a new block, @@ -89,6 +105,10 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) osize, (int)fs->fs_bsize, cred, &bp); if (error) return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, nb, + dbtofsb(fs, bp->b_blkno), ip->i_db[nb], + fs->fs_bsize, osize, bp); ip->i_size = smalllblktosize(fs, nb + 1); ip->i_db[nb] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; @@ -110,7 +130,7 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) return (error); } bp->b_blkno = fsbtodb(fs, nb); - *bpp = bp; + *ap->a_bpp = bp; return (0); } if (nb != 0) { @@ -132,6 +152,10 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) &ip->i_db[0]), osize, nsize, cred, &bp); if (error) return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, + dbtofsb(fs, bp->b_blkno), nb, + nsize, osize, bp); } } else { if (ip->i_size < smalllblktosize(fs, lbn + 1)) @@ -147,10 +171,13 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, newb, 0, + nsize, 0, bp); } ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; - *bpp = bp; + *ap->a_bpp = bp; return (0); } /* @@ -180,12 +207,18 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); bp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(bp); - /* - * Write synchronously so that indirect blocks - * never point at garbage. - */ - if (error = bwrite(bp)) - goto fail; + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, + newb, 0, fs->fs_bsize, 0, bp); + bdwrite(bp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if (error = bwrite(bp)) + goto fail; + } allocib = &ip->i_ib[indirs[0].in_off]; *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; @@ -221,13 +254,19 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); - /* - * Write synchronously so that indirect blocks - * never point at garbage. - */ - if (error = bwrite(nbp)) { - brelse(bp); - goto fail; + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocindir_meta(nbp, ip, bp, + indirs[i - 1].in_off, nb); + bdwrite(nbp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if (error = bwrite(nbp)) { + brelse(bp); + goto fail; + } } bap[indirs[i - 1].in_off] = nb; /* @@ -259,6 +298,9 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) nbp->b_blkno = fsbtodb(fs, nb); if (flags & B_CLRBUF) vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocindir_page(ip, lbn, bp, + indirs[i].in_off, nb, 0, nbp); bap[indirs[i].in_off] = nb; /* * If required, write synchronously, otherwise use @@ -271,7 +313,7 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } - *bpp = nbp; + *ap->a_bpp = nbp; return (0); } brelse(bp); @@ -285,7 +327,7 @@ ffs_balloc(ip, lbn, size, cred, bpp, flags) nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); } - *bpp = nbp; + *ap->a_bpp = nbp; return (0); fail: /* diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index dad97d3..90cb38c 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 - * $Id: ffs_extern.h,v 1.21 1997/11/22 08:35:45 bde Exp $ + * $Id: ffs_extern.h,v 1.22 1998/02/03 21:52:00 bde Exp $ */ #ifndef _UFS_FFS_EXTERN_H @@ -68,8 +68,7 @@ struct vop_reallocblks_args; int ffs_alloc __P((struct inode *, ufs_daddr_t, ufs_daddr_t, int, struct ucred *, ufs_daddr_t *)); -int ffs_balloc __P((struct inode *, - ufs_daddr_t, int, struct ucred *, struct buf **, int)); +int ffs_balloc __P((struct vop_balloc_args *)); int ffs_blkatoff __P((struct vnode *, off_t, char **, struct buf **)); 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 *)); @@ -79,7 +78,9 @@ int ffs_fhtovp __P((struct mount *, struct fid *, struct sockaddr *, struct vnode **, int *, struct ucred **)); int ffs_flushfiles __P((struct mount *, int, struct proc *)); void ffs_fragacct __P((struct fs *, int, int32_t [], int)); +int ffs_freefile __P(( struct vnode *, ino_t, int )); int ffs_isblock __P((struct fs *, u_char *, ufs_daddr_t)); +int ffs_isfreeblock __P((struct fs *, unsigned char *, ufs_daddr_t)); int ffs_mountfs __P((struct vnode *, struct mount *, struct proc *, struct malloc_type *)); int ffs_mountroot __P((void)); @@ -102,4 +103,31 @@ extern vop_t **ffs_vnodeop_p; extern vop_t **ffs_specop_p; extern vop_t **ffs_fifoop_p; +/* + * Soft update function prototypes. + */ +void softdep_initialize __P((void)); +int softdep_process_worklist __P((struct mount *)); +int softdep_mount __P((struct vnode *, struct mount *, struct fs *, + struct ucred *)); +int softdep_flushfiles __P((struct mount *, int, struct proc *)); +void softdep_update_inodeblock __P((struct inode *, struct buf *, int)); +void softdep_load_inodeblock __P((struct inode *)); +int softdep_fsync __P((struct vnode *)); +void softdep_freefile __P((struct vnode *, ino_t, int)); +void softdep_setup_freeblocks __P((struct inode *, off_t)); +void softdep_deallocate_dependencies __P((struct buf *)); +void softdep_setup_inomapdep __P((struct buf *, struct inode *, ino_t)); +void softdep_setup_blkmapdep __P((struct buf *, struct fs *, ufs_daddr_t)); +void softdep_setup_allocdirect __P((struct inode *, ufs_lbn_t, ufs_daddr_t, + ufs_daddr_t, long, long, struct buf *)); +void softdep_setup_allocindir_meta __P((struct buf *, struct inode *, + struct buf *, int, ufs_daddr_t)); +void softdep_setup_allocindir_page __P((struct inode *, ufs_lbn_t, + struct buf *, int, ufs_daddr_t, ufs_daddr_t, struct buf *)); +void softdep_disk_io_initiation __P((struct buf *)); +void softdep_disk_write_complete __P((struct buf *)); +int softdep_sync_metadata __P((struct vop_fsync_args *)); + #endif /* !_UFS_FFS_EXTERN_H */ + diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index cf1c043..d1364a1 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95 - * $Id: ffs_inode.c,v 1.34 1998/02/06 12:14:14 eivind Exp $ + * $Id: ffs_inode.c,v 1.35 1998/03/07 21:36:33 dyson Exp $ */ #include "opt_quota.h" @@ -87,8 +87,9 @@ ffs_update(vp, access, modify, waitfor) ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); return (0); } - if ((ip->i_flag & - (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) + if (((ip->i_flag & + (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && + (waitfor != MNT_WAIT)) return (0); /* * Use a copy of the current time to get consistent timestamps @@ -129,11 +130,15 @@ ffs_update(vp, access, modify, waitfor) brelse(bp); return (error); } + if (DOINGSOFTDEP(vp)) + softdep_update_inodeblock(ip, bp, waitfor); + else if (ip->i_effnlink != ip->i_nlink) + panic("ffs_update: bad link cnt"); *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = ip->i_din; - if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) + if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) { return (bwrite(bp)); - else { + } else { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); @@ -171,6 +176,8 @@ ffs_truncate(vp, length, flags, cred, p) off_t osize; oip = VTOI(ovp); + if (oip->i_size == length) + return (0); fs = oip->i_fs; if (length < 0) return (EINVAL); @@ -197,6 +204,31 @@ ffs_truncate(vp, length, flags, cred, p) if (error) return (error); #endif + ovp->v_lasta = ovp->v_clen = ovp->v_cstart = ovp->v_lastw = 0; + if (DOINGSOFTDEP(ovp)) { + if (length > 0) { + /* + * If a file is only partially truncated, then + * we have to clean up the data structures + * describing the allocation past the truncation + * point. Finding and deallocating those structures + * is a lot of work. Since partial truncation occurs + * rarely, we solve the problem by syncing the file + * so that it will have no data structures left. + */ + if ((error = VOP_FSYNC(ovp, cred, MNT_WAIT, + p)) != 0) + return (error); + } else { +#ifdef QUOTA + (void) chkdq(oip, -oip->i_blocks, NOCRED, 0); +#endif + softdep_setup_freeblocks(oip, length); + (void) vinvalbuf(ovp, 0, cred, p, 0, 0); + oip->i_flag |= IN_CHANGE | IN_UPDATE; + return (ffs_update(ovp, &tv, &tv, 0)); + } + } osize = oip->i_size; /* * Lengthen the size of the file. We must ensure that the @@ -205,13 +237,15 @@ ffs_truncate(vp, length, flags, cred, p) */ if (osize < length) { vnode_pager_setsize(ovp, length); +#if 0 offset = blkoff(fs, length - 1); lbn = lblkno(fs, length - 1); +#endif aflags = B_CLRBUF; if (flags & IO_SYNC) aflags |= B_SYNC; - error = ffs_balloc(oip, lbn, offset + 1, cred, - &bp, aflags); + error = VOP_BALLOC(ovp, length - 1, 1, + cred, aflags, &bp); if (error) return (error); oip->i_size = length; @@ -241,9 +275,13 @@ ffs_truncate(vp, length, flags, cred, p) aflags = B_CLRBUF; if (flags & IO_SYNC) aflags |= B_SYNC; - error = ffs_balloc(oip, lbn, offset, cred, &bp, aflags); - if (error) + error = VOP_BALLOC(ovp, length - 1, 1, cred, aflags, &bp); + if (error) { +#if 0 /* kirk's version had this */ + vnode_pager_setsize(ovp, (u_long)osize); +#endif return (error); + } oip->i_size = length; size = blksize(fs, oip, lbn); bzero((char *)bp->b_data + offset, (u_int)(size - offset)); diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 601a4cf..7d7de14 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 - * $Id: ffs_subr.c,v 1.18 1998/02/06 12:14:14 eivind Exp $ + * $Id: ffs_subr.c,v 1.19 1998/02/13 00:20:36 bde Exp $ */ #include <sys/param.h> @@ -191,6 +191,30 @@ ffs_isblock(fs, cp, h) } /* + * check if a block is free + */ +int +ffs_isfreeblock(fs, cp, h) + struct fs *fs; + unsigned char *cp; + ufs_daddr_t h; +{ + + switch ((int)fs->fs_frag) { + case 8: + return (cp[h] == 0); + case 4: + return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); + case 2: + return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); + case 1: + return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); + default: + panic("ffs_isfreeblock"); + } +} + +/* * take a block out of the map */ void diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index edfe0e6..71a451d 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 - * $Id: ffs_vfsops.c,v 1.74 1998/03/07 14:59:44 bde Exp $ + * $Id: ffs_vfsops.c,v 1.75 1998/03/07 21:36:36 dyson Exp $ */ #include "opt_quota.h" @@ -203,7 +203,11 @@ ffs_mount( mp, path, data, ndp, p) flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; - err = ffs_flushfiles(mp, flags, p); + if (mp->mnt_flag & MNT_SOFTDEP) { + err = softdep_flushfiles(mp, flags, p); + } else { + err = ffs_flushfiles(mp, flags, p); + } } if (!err && (mp->mnt_flag & MNT_RELOAD)) err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); @@ -410,7 +414,10 @@ ffs_reload(mp, cred, p) * Step 1: invalidate all cached meta-data. */ devvp = VFSTOUFS(mp)->um_devvp; - if (vinvalbuf(devvp, 0, cred, p, 0, 0)) + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); + error = vinvalbuf(devvp, 0, cred, p, 0, 0); + VOP_UNLOCK(devvp, 0, p); + if (error) panic("ffs_reload: dirty1"); dev = devvp->v_rdev; @@ -516,6 +523,7 @@ loop: } ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)); + ip->i_effnlink = ip->i_nlink; brelse(bp); vput(vp); simple_lock(&mntvnode_slock); @@ -537,10 +545,12 @@ ffs_mountfs(devvp, mp, p, malloctype) register struct ufsmount *ump; struct buf *bp; register struct fs *fs; + struct cg *cgp; dev_t dev; struct partinfo dpart; + struct csum cstotal; caddr_t base, space; - int error, i, blks, size, ronly; + int error, i, cyl, blks, size, ronly; int32_t *lp; struct ucred *cred; u_int64_t maxfilesize; /* XXX */ @@ -562,7 +572,10 @@ ffs_mountfs(devvp, mp, p, malloctype) if (ncount > 1 && devvp != rootvp) return (EBUSY); - if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); + error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0); + VOP_UNLOCK(devvp, 0, p); + if (error) return (error); /* @@ -674,7 +687,7 @@ ffs_mountfs(devvp, mp, p, malloctype) ump->um_seqinc = fs->fs_frag; for (i = 0; i < MAXQUOTAS; i++) ump->um_quotas[i] = NULLVP; - devvp->v_specflags |= SI_MOUNTEDON; + devvp->v_specmountpoint = mp; ffs_oldfscompat(fs); /* @@ -700,11 +713,17 @@ ffs_mountfs(devvp, mp, p, malloctype) if (fs->fs_maxfilesize > maxfilesize) /* XXX */ fs->fs_maxfilesize = maxfilesize; /* XXX */ if (ronly == 0) { + if ((fs->fs_flags & FS_DOSOFTDEP) && + (error = softdep_mount(devvp, mp, fs, cred)) != 0) { + free(base, M_UFSMNT); + goto out; + } fs->fs_clean = 0; (void) ffs_sbupdate(ump, MNT_WAIT); } return (0); out: + devvp->v_specmountpoint = NULL; if (bp) brelse(bp); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); @@ -765,9 +784,13 @@ ffs_unmount(mp, mntflags, p) if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } - error = ffs_flushfiles(mp, flags, p); - if (error) - return (error); + if (mp->mnt_flag & MNT_SOFTDEP) { + if ((error = softdep_flushfiles(mp, flags, p)) != 0) + return (error); + } else { + if ((error = ffs_flushfiles(mp, flags, p)) != 0) + return (error); + } ump = VFSTOUFS(mp); fs = ump->um_fs; if (fs->fs_ronly == 0) { @@ -778,7 +801,7 @@ ffs_unmount(mp, mntflags, p) return (error); } } - ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; + ump->um_devvp->v_specmountpoint = NULL; vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0); error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, @@ -824,7 +847,17 @@ ffs_flushfiles(mp, flags, p) */ } #endif - error = vflush(mp, NULLVP, flags); + /* + * Flush all the files. + */ + if ((error = vflush(mp, NULL, flags)) != 0) + return (error); + /* + * Flush filesystem metadata. + */ + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p); + VOP_UNLOCK(ump->um_devvp, 0, p); return (error); } @@ -903,9 +936,9 @@ loop: simple_lock(&vp->v_interlock); nvp = vp->v_mntvnodes.le_next; ip = VTOI(vp); - if (((ip->i_flag & + if ((vp->v_type == VNON) || ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) && - vp->v_dirtyblkhd.lh_first == NULL) { + ((vp->v_dirtyblkhd.lh_first == NULL) || (waitfor == MNT_LAZY))) { simple_unlock(&vp->v_interlock); continue; } @@ -937,21 +970,22 @@ loop: /* * Force stale file system control information to be flushed. */ - error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p); - if (error) - allerror = error; + if (waitfor != MNT_LAZY) { + if (ump->um_mountp->mnt_flag & MNT_SOFTDEP) + waitfor = MNT_NOWAIT; + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); + if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0) + allerror = error; + VOP_UNLOCK(ump->um_devvp, 0, p); + } #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; - } + if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0) + allerror = error; return (allerror); } @@ -1060,6 +1094,10 @@ restart: return (error); } ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); + if (DOINGSOFTDEP(vp)) + softdep_load_inodeblock(ip); + else + ip->i_effnlink = ip->i_nlink; bqrelse(bp); /* @@ -1157,6 +1195,7 @@ ffs_init(vfsp) struct vfsconf *vfsp; { + softdep_initialize(); return (ufs_init(vfsp)); } @@ -1200,6 +1239,8 @@ ffs_sbupdate(mp, waitfor) if (allerror) return (allerror); bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; 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 */ diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 0210d61..44db8f4 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 - * $Id: ffs_vnops.c,v 1.42 1998/02/06 12:14:16 eivind Exp $ + * $Id: ffs_vnops.c,v 1.43 1998/02/26 06:39:38 msmith Exp $ */ #include <sys/param.h> @@ -74,6 +74,7 @@ static struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_getpages_desc, (vop_t *) ffs_getpages }, { &vop_putpages_desc, (vop_t *) ffs_putpages }, { &vop_read_desc, (vop_t *) ffs_read }, + { &vop_balloc_desc, (vop_t *) ffs_balloc }, { &vop_reallocblks_desc, (vop_t *) ffs_reallocblks }, { &vop_write_desc, (vop_t *) ffs_write }, { NULL, NULL } @@ -120,12 +121,11 @@ ffs_fsync(ap) struct proc *a_p; } */ *ap; { - register struct vnode *vp = ap->a_vp; - register struct buf *bp; + struct vnode *vp = ap->a_vp; + struct buf *bp; struct timeval tv; struct buf *nbp; - int pass; - int s; + int s, error, passes, skipmeta; daddr_t lbn; @@ -137,31 +137,45 @@ ffs_fsync(ap) lbn = lblkno(ip->i_fs, (ip->i_size + ip->i_fs->fs_bsize - 1)); } - pass = 0; /* * Flush all dirty buffers associated with a vnode. */ + passes = NIADDR; + skipmeta = 0; + if (ap->a_waitfor == MNT_WAIT) + skipmeta = 1; loop: s = splbio(); +loop2: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { nbp = bp->b_vnbufs.le_next; - if ((bp->b_flags & B_BUSY) || (pass == 0 && (bp->b_lblkno < 0))) + /* + * First time through on a synchronous call, + * or if it's already scheduled, skip to the next + * buffer + */ + if ((bp->b_flags & B_BUSY) || + ((skipmeta == 1) && (bp->b_lblkno < 0))) continue; if ((bp->b_flags & B_DELWRI) == 0) panic("ffs_fsync: not dirty"); - - if (((bp->b_vp != vp) || (ap->a_waitfor != MNT_NOWAIT)) || - ((vp->v_type != VREG) && (vp->v_type != VBLK))) { - + /* + * If data is outstanding to another vnode, or we were + * asked to wait for everything, or it's not a file or BDEV, + * start the IO on this buffer immediatly. + */ + if (((bp->b_vp != vp) || (ap->a_waitfor == MNT_WAIT)) || + ((vp->v_type != VREG) && (vp->v_type != VBLK))) { bremfree(bp); bp->b_flags |= B_BUSY; splx(s); /* - * Wait for I/O associated with indirect blocks to complete, - * since there is no way to quickly wait for them below. + * Wait for I/O associated with indirect blocks to + * complete, since there is no way to quickly wait + * for them below. */ - if ((bp->b_vp == vp) && (ap->a_waitfor == MNT_NOWAIT)) { + if ((bp->b_vp == vp) || (ap->a_waitfor != MNT_WAIT)) { if (bp->b_flags & B_CLUSTEROK) { bdwrite(bp); (void) vfs_bio_awrite(bp); @@ -171,26 +185,30 @@ loop: } else { (void) bwrite(bp); } - } else if ((vp->v_type == VREG) && (bp->b_lblkno >= lbn)) { - + /* + * If the buffer is for data that has been truncated + * off the file, then throw it away. + */ bremfree(bp); bp->b_flags |= B_BUSY | B_INVAL | B_NOCACHE; brelse(bp); splx(s); - } else { vfs_bio_awrite(bp); splx(s); } goto loop; } - splx(s); - - if (pass == 0) { - pass = 1; - goto loop; + /* + * If we were asked to do this synchronously, then go back for + * another pass, this time doing the metadata. + */ + if (skipmeta) { + skipmeta = 0; + goto loop2; /* stay within the splbio() */ } + splx(s); if (ap->a_waitfor == MNT_WAIT) { s = splbio(); @@ -198,15 +216,38 @@ loop: vp->v_flag |= VBWAIT; (void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "ffsfsn", 0); } + /* + * Ensure that any filesystem metatdata associated + * with the vnode has been written. + */ splx(s); -#ifdef DIAGNOSTIC + if ((error = softdep_sync_metadata(ap)) != 0) + return (error); + s = splbio(); if (vp->v_dirtyblkhd.lh_first) { - vprint("ffs_fsync: dirty", vp); - goto loop; - } + /* + * Block devices associated with filesystems may + * have new I/O requests posted for them even if + * the vnode is locked, so no amount of trying will + * get them clean. Thus we give block devices a + * good effort, then just give up. For all other file + * types, go around and try again until it is clean. + */ + if (passes > 0) { + passes -= 1; + goto loop2; + } +#ifdef DIAGNOSTIC + if (vp->v_type != VBLK) + vprint("ffs_fsync: dirty", vp); #endif + } } - gettime(&tv); - return (UFS_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT)); + error = UFS_UPDATE(ap->a_vp, &tv, &tv, (ap->a_waitfor == MNT_WAIT)); + if (error) + return (error); + if (DOINGSOFTDEP(vp) && ap->a_waitfor == MNT_WAIT) + error = softdep_fsync(vp); + return (error); } diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 98a9b06..9f99731 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)fs.h 8.13 (Berkeley) 3/21/95 - * $Id: fs.h,v 1.11 1997/03/23 20:08:22 guido Exp $ + * $Id: fs.h,v 1.12 1997/03/24 03:19:37 bde Exp $ */ #ifndef _UFS_FFS_FS_H_ @@ -222,7 +222,7 @@ struct fs { 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 */ + int8_t fs_flags; /* see FS_ flags below */ u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ /* these fields retain the current block allocation info */ int32_t fs_cgrotor; /* last cg searched */ @@ -254,6 +254,7 @@ struct fs { #define FS_OKAY 0x7c269d38 /* superblock checksum */ #define FS_42INODEFMT -1 /* 4.2BSD inode format */ #define FS_44INODEFMT 2 /* 4.4BSD inode format */ + /* * Preference for optimization. */ @@ -261,6 +262,12 @@ struct fs { #define FS_OPTSPACE 1 /* minimize disk fragmentation */ /* + * Filesystem flags. + */ +#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ +#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ + +/* * Rotational layout table format types */ #define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ @@ -485,6 +492,11 @@ struct ocg { (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) +#define sblksize(fs, size, lbn) \ + (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (size))))) + /* * Number of disk sectors per block/fragment; assumes DEV_BSIZE byte |