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 | |
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')
-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 | ||||
-rw-r--r-- | sys/ufs/ufs/inode.h | 11 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extern.h | 27 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 263 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_quota.c | 8 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_readwrite.c | 10 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 340 |
14 files changed, 778 insertions, 380 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 diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index f2fd0f2..4bd1cf5 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)inode.h 8.9 (Berkeley) 5/14/95 - * $Id: inode.h,v 1.19 1997/12/05 13:43:47 jkh Exp $ + * $Id: inode.h,v 1.20 1998/01/30 11:34:02 phk Exp $ */ #ifndef _UFS_UFS_INODE_H_ @@ -46,6 +46,11 @@ #include <ufs/ufs/dinode.h> /* + * The size of a logical block number. + */ +typedef long ufs_lbn_t; + +/* * This must agree with the definition in <ufs/ufs/dir.h>. */ #define doff_t int32_t @@ -67,6 +72,7 @@ struct inode { u_int32_t i_flag; /* flags, see below */ dev_t i_dev; /* Device associated with the inode. */ ino_t i_number; /* The identity of the inode. */ + int i_effnlink; /* i_nlink when I/O completes */ union { /* Associated filesystem. */ struct fs *fs; /* FFS */ @@ -160,6 +166,9 @@ struct indir { } \ } +/* Determine if soft dependencies are being done */ +#define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & MNT_SOFTDEP) + /* This overlays the fid structure (see mount.h). */ struct ufid { u_int16_t ufid_len; /* Length of structure. */ diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h index 5d7ec5f..55d068c 100644 --- a/sys/ufs/ufs/ufs_extern.h +++ b/sys/ufs/ufs/ufs_extern.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95 - * $Id: ufs_extern.h,v 1.21 1997/10/16 11:59:09 phk Exp $ + * $Id: ufs_extern.h,v 1.22 1997/10/27 12:50:57 bde Exp $ */ #ifndef _UFS_UFS_EXTERN_H_ @@ -68,12 +68,12 @@ int ufs_checkpath __P((struct inode *, struct inode *, struct ucred *)); void ufs_dirbad __P((struct inode *, doff_t, char *)); int ufs_dirbadentry __P((struct vnode *, struct direct *, int)); int ufs_dirempty __P((struct inode *, ino_t, struct ucred *)); -int ufs_direnter __P((struct inode *, struct vnode *,struct componentname *)); -int ufs_direnter2 __P((struct vnode *, struct direct *, struct ucred *, - struct proc *)); -int ufs_dirremove __P((struct vnode *, struct componentname*)); -int ufs_dirrewrite - __P((struct inode *, struct inode *, struct componentname *)); +void ufs_makedirentry __P((struct inode *, struct componentname *, + struct direct *)); +int ufs_direnter __P((struct vnode *, struct vnode *, struct direct *, + struct componentname *, struct buf *)); +int ufs_dirremove __P((struct vnode *, struct inode *, int, int)); +int ufs_dirrewrite __P((struct inode *, struct inode *, ino_t, int, int)); int ufs_getlbns __P((struct vnode *, ufs_daddr_t, struct indir *, int *)); struct vnode * ufs_ihashget __P((dev_t, ino_t)); @@ -90,4 +90,17 @@ int ufs_root __P((struct mount *, struct vnode **)); int ufs_start __P((struct mount *, int, struct proc *)); int ufs_vinit __P((struct mount *, vop_t **, vop_t **, struct vnode **)); +/* + * Soft update function prototypes. + */ +void softdep_setup_directory_add __P((struct buf *, struct inode *, off_t, + long, struct buf *)); +void softdep_change_directoryentry_offset __P((struct inode *, caddr_t, + caddr_t, caddr_t, int)); +void softdep_setup_remove __P((struct buf *,struct inode *, struct inode *, + int)); +void softdep_setup_directory_change __P((struct buf *, struct inode *, + struct inode *, long, int)); +void softdep_increase_linkcnt __P((struct inode *)); + #endif /* !_UFS_UFS_EXTERN_H_ */ diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 1088807..2e7d9d9 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -36,16 +36,22 @@ * SUCH DAMAGE. * * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 - * $Id: ufs_lookup.c,v 1.20 1998/02/04 22:33:36 eivind Exp $ + * $Id: ufs_lookup.c,v 1.21 1998/02/06 12:14:18 eivind Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> #include <sys/namei.h> #include <sys/buf.h> +#include <sys/proc.h> +#include <sys/stat.h> #include <sys/mount.h> #include <sys/vnode.h> +#include <vm/vm.h> +#include <vm/vm_extern.h> + #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> @@ -143,7 +149,12 @@ ufs_lookup(ap) bp = NULL; slotoffset = -1; +/* + * XXX there was a soft-update diff about this I couldn't merge. + * I think this was the equiv. + */ *vpp = NULL; + vdp = ap->a_dvp; dp = VTOI(vdp); lockparent = flags & LOCKPARENT; @@ -331,7 +342,7 @@ notfound: (nameiop == DELETE && (ap->a_cnp->cn_flags & DOWHITEOUT) && (ap->a_cnp->cn_flags & ISWHITEOUT))) && - (flags & ISLASTCN) && dp->i_nlink != 0) { + (flags & ISLASTCN) && dp->i_effnlink != 0) { /* * Access for write is interpreted as allowing * creation of files in the directory. @@ -603,64 +614,66 @@ bad: } /* - * Write a directory entry after a call to namei, using the parameters - * that it left in nameidata. The argument ip is the inode which the new - * directory entry will refer to. Dvp is a pointer to the directory to - * be written, which was left locked by namei. Remaining parameters - * (dp->i_offset, dp->i_count) indicate how the space for the new - * entry is to be obtained. + * Construct a new directory entry after a call to namei, using the + * parameters that it left in the componentname argument cnp. The + * argument ip is the inode to which the new directory entry will refer. */ -int -ufs_direnter(ip, dvp, cnp) +void +ufs_makedirentry(ip, cnp, newdirp) struct inode *ip; - struct vnode *dvp; - register struct componentname *cnp; + struct componentname *cnp; + struct direct *newdirp; { - register struct inode *dp; - struct direct newdir; #ifdef DIAGNOSTIC if ((cnp->cn_flags & SAVENAME) == 0) - panic("ufs_direnter: missing name"); + panic("ufs_makedirentry: missing name"); #endif - dp = VTOI(dvp); - newdir.d_ino = ip->i_number; - newdir.d_namlen = cnp->cn_namelen; - bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); - if (!OFSFMT(dvp)) - newdir.d_type = IFTODT(ip->i_mode); + newdirp->d_ino = ip->i_number; + newdirp->d_namlen = cnp->cn_namelen; + bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1); + if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) + newdirp->d_type = IFTODT(ip->i_mode); else { - newdir.d_type = 0; + newdirp->d_type = 0; # if (BYTE_ORDER == LITTLE_ENDIAN) - { u_char tmp = newdir.d_namlen; - newdir.d_namlen = newdir.d_type; - newdir.d_type = tmp; } + { u_char tmp = newdirp->d_namlen; + newdirp->d_namlen = newdirp->d_type; + newdirp->d_type = tmp; } # endif } - return (ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc)); } /* - * Common entry point for directory entry removal used by ufs_direnter - * and ufs_whiteout + * Write a directory entry after a call to namei, using the parameters + * that it left in nameidata. The argument dirp is the new directory + * entry contents. Dvp is a pointer to the directory to be written, + * which was left locked by namei. Remaining parameters (dp->i_offset, + * dp->i_count) indicate how the space for the new entry is to be obtained. + * Non-null bp indicates that a directory is being created (for the + * soft dependency code). */ int -ufs_direnter2(dvp, dirp, cr, p) +ufs_direnter(dvp, tvp, dirp, cnp, newdirbp) struct vnode *dvp; + struct vnode *tvp; struct direct *dirp; + struct componentname *cnp; + struct buf *newdirbp; +{ struct ucred *cr; struct proc *p; -{ int newentrysize; struct inode *dp; struct buf *bp; - struct iovec aiov; - struct uio auio; u_int dsize; struct direct *ep, *nep; - int error, loc, spacefree; + int error, ret, blkoff, loc, spacefree, flags; char *dirbuf; + p = curproc; /* XXX */ + cr = p->p_ucred; + dp = VTOI(dvp); newentrysize = DIRSIZ(OFSFMT(dvp), dirp); @@ -672,36 +685,55 @@ ufs_direnter2(dvp, dirp, cr, p) * new entry into a fresh block. */ if (dp->i_offset & (DIRBLKSIZ - 1)) - panic("ufs_direnter2: newblk"); - auio.uio_offset = dp->i_offset; + panic("ufs_direnter: newblk"); + flags = B_CLRBUF; + if (!DOINGSOFTDEP(dvp)) + flags |= B_SYNC; + if ((error = VOP_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ, + cr, flags, &bp)) != 0) { + if (DOINGSOFTDEP(dvp) && newdirbp != NULL) + bdwrite(newdirbp); + return (error); + } + dp->i_size = dp->i_offset + DIRBLKSIZ; + dp->i_flag |= IN_CHANGE | IN_UPDATE; + vnode_pager_setsize(dvp, (u_long)dp->i_size); dirp->d_reclen = DIRBLKSIZ; - auio.uio_resid = newentrysize; - aiov.iov_len = newentrysize; - aiov.iov_base = (caddr_t)dirp; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_WRITE; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = (struct proc *)0; - error = VOP_WRITE(dvp, &auio, IO_SYNC, cr); - if (DIRBLKSIZ > - VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) - /* XXX should grow with balloc() */ - panic("ufs_direnter2: frag size"); - else if (!error) { - dp->i_size = roundup2(dp->i_size, DIRBLKSIZ); - dp->i_flag |= IN_CHANGE; + blkoff = dp->i_offset & + (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); + bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); + if (DOINGSOFTDEP(dvp)) { + /* + * Ensure that the entire newly allocated block is a + * valid directory so that future growth within the + * block does not have to ensure that the block is + * written before the inode. + */ + blkoff += DIRBLKSIZ; + while (blkoff < bp->b_bcount) { + ((struct direct *) + (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; + blkoff += DIRBLKSIZ; + } + softdep_setup_directory_add(bp, dp, dp->i_offset, + dirp->d_ino, newdirbp); + bdwrite(bp); + } else { + error = VOP_BWRITE(bp); } + ret = UFS_UPDATE(dvp, &time, &time, !DOINGSOFTDEP(dvp)); + if (error == 0) + return (ret); return (error); } /* - * If dp->i_count is non-zero, then namei found space - * for the new entry in the range dp->i_offset to - * dp->i_offset + dp->i_count in the directory. - * To use this space, we may have to compact the entries located - * there, by copying them together towards the beginning of the - * block, leaving the free space in one usable chunk at the end. + * If dp->i_count is non-zero, then namei found space for the new + * entry in the range dp->i_offset to dp->i_offset + dp->i_count + * in the directory. To use this space, we may have to compact + * the entries located there, by copying them together towards the + * beginning of the block, leaving the free space in one usable + * chunk at the end. */ /* @@ -717,14 +749,16 @@ ufs_direnter2(dvp, dirp, cr, p) * Get the block containing the space for the new directory entry. */ error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp); - if (error) + if (error) { + if (DOINGSOFTDEP(dvp) && newdirbp != NULL) + bdwrite(newdirbp); return (error); + } /* * Find space for the new entry. In the simple case, the entry at * offset base will have the space. If it does not, then namei * arranged that compacting the region dp->i_offset to - * dp->i_offset + dp->i_count would yield the - * space. + * dp->i_offset + dp->i_count would yield the space. */ ep = (struct direct *)dirbuf; dsize = DIRSIZ(OFSFMT(dvp), ep); @@ -742,7 +776,11 @@ ufs_direnter2(dvp, dirp, cr, p) dsize = DIRSIZ(OFSFMT(dvp), nep); spacefree += nep->d_reclen - dsize; loc += nep->d_reclen; - bcopy((caddr_t)nep, (caddr_t)ep, dsize); + if (DOINGSOFTDEP(dvp)) + softdep_change_directoryentry_offset(dp, dirbuf, + (caddr_t)nep, (caddr_t)ep, dsize); + else + bcopy((caddr_t)nep, (caddr_t)ep, dsize); } /* * Update the pointer fields in the previous entry (if any), @@ -752,26 +790,44 @@ ufs_direnter2(dvp, dirp, cr, p) (ep->d_ino == WINO && bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { if (spacefree + dsize < newentrysize) - panic("ufs_direnter2: compact1"); + panic("ufs_direnter: compact1"); dirp->d_reclen = spacefree + dsize; } else { if (spacefree < newentrysize) - panic("ufs_direnter2: compact2"); + panic("ufs_direnter: compact2"); dirp->d_reclen = spacefree; ep->d_reclen = dsize; ep = (struct direct *)((char *)ep + dsize); } bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); - if (dvp->v_mount->mnt_flag & MNT_ASYNC) { + if (DOINGSOFTDEP(dvp)) { + softdep_setup_directory_add(bp, dp, + dp->i_offset + (caddr_t)ep - dirbuf, dirp->d_ino, newdirbp); bdwrite(bp); - error = 0; } else { - error = bowrite(bp); + if (dvp->v_mount->mnt_flag & MNT_ASYNC) { + bdwrite(bp); + error = 0; + } else { + error = bowrite(bp); + } } dp->i_flag |= IN_CHANGE | IN_UPDATE; - if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) - error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p); + /* + * If all went well, and the directory can be shortened, proceed + * with the truncation. Note that we have to unlock the inode for + * the entry that we just entered, as the truncation may need to + * lock other inodes which can lead to deadlock if we also hold a + * lock on the newly entered node. + */ + if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_size) { + if (tvp != NULL) + VOP_UNLOCK(tvp, 0, p); + (void) UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p); + if (tvp != NULL) + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p); + } return (error); } @@ -788,18 +844,20 @@ ufs_direnter2(dvp, dirp, cr, p) * to the size of the previous entry. */ int -ufs_dirremove(dvp, cnp) +ufs_dirremove(dvp, ip, flags, isrmdir) struct vnode *dvp; - struct componentname *cnp; + struct inode *ip; + int flags; + int isrmdir; { - register struct inode *dp; + struct inode *dp; struct direct *ep; struct buf *bp; int error; dp = VTOI(dvp); - if (cnp->cn_flags & DOWHITEOUT) { + if (flags & DOWHITEOUT) { /* * Whiteout entry: set d_ino to WINO. */ @@ -808,24 +866,44 @@ ufs_dirremove(dvp, cnp) return (error); ep->d_ino = WINO; ep->d_type = DT_WHT; - error = VOP_BWRITE(bp); - dp->i_flag |= IN_CHANGE | IN_UPDATE; - return (error); + goto out; } + if ((error = UFS_BLKATOFF(dvp, + (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) + return (error); if (dp->i_count == 0) { /* * First entry in block: set d_ino to zero. */ +#if 0 error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp); if (error) return (error); +#endif ep->d_ino = 0; - error = bowrite(bp); - dp->i_flag |= IN_CHANGE | IN_UPDATE; - return (error); + } else { + /* + * Collapse new free space into previous entry. + */ + ep->d_reclen += dp->i_reclen; + } +out: + if (ip) { + ip->i_effnlink--; + ip->i_flag |= IN_CHANGE; + } + if (DOINGSOFTDEP(dvp)) { + if (ip) + softdep_setup_remove(bp, dp, ip, isrmdir); + bdwrite(bp); + } else { + if (ip) + ip->i_nlink--; + error = bowrite(bp); /* maybe this should be as below? */ } +#if 0 /* * Collapse new free space into previous entry. */ @@ -840,6 +918,7 @@ ufs_dirremove(dvp, cnp) } else { error = bowrite(bp); } +#endif dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } @@ -850,9 +929,11 @@ ufs_dirremove(dvp, cnp) * set up by a call to namei. */ int -ufs_dirrewrite(dp, ip, cnp) - struct inode *dp, *ip; - struct componentname *cnp; +ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) + struct inode *dp, *oip; + ino_t newinum; + int newtype; + int isrmdir; { struct buf *bp; struct direct *ep; @@ -862,14 +943,22 @@ ufs_dirrewrite(dp, ip, cnp) error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); if (error) return (error); - ep->d_ino = ip->i_number; + ep->d_ino = newinum; if (!OFSFMT(vdp)) - ep->d_type = IFTODT(ip->i_mode); - if (vdp->v_mount->mnt_flag & MNT_ASYNC) { + ep->d_type = newtype; + oip->i_effnlink--; + oip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(vdp)) { + softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); bdwrite(bp); - error = 0; } else { - error = bowrite(bp); + oip->i_nlink--; + if (vdp->v_mount->mnt_flag & MNT_ASYNC) { + bdwrite(bp); + error = 0; + } else { + error = bowrite(bp); + } } dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); @@ -929,7 +1018,7 @@ ufs_dirempty(ip, parentino, cred) * 1 implies ".", 2 implies ".." if second * char is also "." */ - if (namlen == 1) + if (namlen == 1 && dp->d_ino == ip->i_number) continue; if (dp->d_name[1] == '.' && dp->d_ino == parentino) continue; diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c index da4641d..2eae865 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 - * $Id: ufs_quota.c,v 1.18 1998/02/06 12:14:18 eivind Exp $ + * $Id: ufs_quota.c,v 1.19 1998/02/09 06:11:12 eivind Exp $ */ #include <sys/param.h> @@ -425,7 +425,7 @@ quotaon(p, mp, type, fname) again: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { nextvp = vp->v_mntvnodes.le_next; - if (vp->v_writecount == 0) + if (vp->v_type == VNON || vp->v_writecount == 0) continue; if (vget(vp, LK_EXCLUSIVE, p)) goto again; @@ -470,6 +470,8 @@ quotaoff(p, mp, type) again: for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nextvp) { nextvp = vp->v_mntvnodes.le_next; + if (vp->v_type == VNON) + continue; if (vget(vp, LK_EXCLUSIVE, p)) goto again; ip = VTOI(vp); @@ -657,6 +659,8 @@ again: if (vp->v_mount != mp) goto again; nextvp = vp->v_mntvnodes.le_next; + if (vp->v_type == VNON) + continue; simple_lock(&vp->v_interlock); simple_unlock(&mntvnode_slock); error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); diff --git a/sys/ufs/ufs/ufs_readwrite.c b/sys/ufs/ufs/ufs_readwrite.c index 6abb130..e0a3488 100644 --- a/sys/ufs/ufs/ufs_readwrite.c +++ b/sys/ufs/ufs/ufs_readwrite.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95 - * $Id: ufs_readwrite.c,v 1.43 1998/02/26 06:39:50 msmith Exp $ + * $Id: ufs_readwrite.c,v 1.44 1998/03/07 21:36:42 dyson Exp $ */ #define BLKSIZE(a, b, c) blksize(a, b, c) @@ -338,10 +338,10 @@ WRITE(ap) flags |= B_CLRBUF; else flags &= ~B_CLRBUF; - - error = ffs_balloc(ip, - lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); - if (error) +/* XXX is uio->uio_offset the right thing here? */ + error = VOP_BALLOC(vp, uio->uio_offset, xfersize, + ap->a_cred, flags, &bp); + if (error != 0) break; if (uio->uio_offset + xfersize > ip->i_size) { diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 28eae14..82a7cc3 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 - * $Id: ufs_vnops.c,v 1.77 1998/02/06 12:14:19 eivind Exp $ + * $Id: ufs_vnops.c,v 1.78 1998/02/09 06:11:14 eivind Exp $ */ #include "opt_quota.h" @@ -59,6 +59,8 @@ #include <sys/poll.h> #include <vm/vm_zone.h> +#include <vm/vm.h> +#include <vm/vm_extern.h> #include <miscfs/specfs/specdev.h> #include <miscfs/fifofs/fifo.h> @@ -121,6 +123,18 @@ union _qcvt { } /* + * A virgin directory (no blushing please). + */ +static struct dirtemplate mastertemplate = { + 0, 12, DT_DIR, 1, ".", + 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." +}; +static struct odirtemplate omastertemplate = { + 0, 12, 1, ".", + 0, DIRBLKSIZ - 12, 2, ".." +}; + +/* * Create a regular file */ int @@ -273,6 +287,8 @@ ufs_access(ap) return (error); #endif break; + default: + break; } } @@ -340,7 +356,7 @@ ufs_getattr(ap) vap->va_fsid = ip->i_dev; vap->va_fileid = ip->i_number; vap->va_mode = ip->i_mode & ~IFMT; - vap->va_nlink = ip->i_nlink; + vap->va_nlink = ip->i_effnlink; vap->va_uid = ip->i_uid; vap->va_gid = ip->i_gid; vap->va_rdev = (dev_t)ip->i_rdev; @@ -444,6 +460,8 @@ ufs_setattr(ap) if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; + default: + break; } if (error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, p)) return (error); @@ -465,7 +483,7 @@ ufs_setattr(ap) atimeval.tv_usec = vap->va_atime.tv_nsec / 1000; mtimeval.tv_sec = vap->va_mtime.tv_sec; mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000; - error = UFS_UPDATE(vp, &atimeval, &mtimeval, 1); + error = UFS_UPDATE(vp, &atimeval, &mtimeval, 0); if (error) return (error); } @@ -652,11 +670,7 @@ ufs_remove(ap) error = EPERM; goto out; } - error = ufs_dirremove(dvp, ap->a_cnp); - if (error == 0) { - ip->i_nlink--; - ip->i_flag |= IN_CHANGE; - } + error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0); VN_POLLEVENT(vp, POLLNLINK); VN_POLLEVENT(dvp, POLLWRITE); out: @@ -685,6 +699,7 @@ ufs_link(ap) struct proc *p = cnp->cn_proc; struct inode *ip; struct timeval tv; + struct direct newdir; int error; #ifdef DIAGNOSTIC @@ -711,15 +726,20 @@ ufs_link(ap) error = EPERM; goto out1; } + ip->i_effnlink++; ip->i_nlink++; ip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(vp)) + softdep_increase_linkcnt(ip); gettime(&tv); - error = UFS_UPDATE(vp, &tv, &tv, 1); + error = UFS_UPDATE(vp, &tv, &tv, !DOINGSOFTDEP(vp)); if (!error) { - error = ufs_direnter(ip, tdvp, cnp); + ufs_makedirentry(ip, cnp, &newdir); + error = ufs_direnter(tdvp, vp, &newdir, cnp, NULL); } if (error) { + ip->i_effnlink--; ip->i_nlink--; ip->i_flag |= IN_CHANGE; } @@ -770,7 +790,7 @@ ufs_whiteout(ap) newdir.d_namlen = cnp->cn_namelen; bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); newdir.d_type = DT_WHT; - error = ufs_direnter2(dvp, &newdir, cnp->cn_cred, cnp->cn_proc); + error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL); break; case DELETE: @@ -781,8 +801,10 @@ ufs_whiteout(ap) #endif cnp->cn_flags &= ~DOWHITEOUT; - error = ufs_dirremove(dvp, cnp); + error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0); break; + default: + panic("ufs_whiteout: unknown op"); } if (cnp->cn_flags & HASBUF) { zfree(namei_zone, cnp->cn_pnbuf); @@ -834,11 +856,10 @@ ufs_rename(ap) struct componentname *fcnp = ap->a_fcnp; struct proc *p = fcnp->cn_proc; struct inode *ip, *xp, *dp; - struct dirtemplate dirbuf; + struct direct newdir; struct timeval tv; int doingdirectory = 0, oldparent = 0, newparent = 0; int error = 0; - u_char namlen; #ifdef DIAGNOSTIC if ((tcnp->cn_flags & HASBUF) == 0 || @@ -965,10 +986,13 @@ abortit: * completing our work, the link count * may be wrong, but correctable. */ + ip->i_effnlink++; ip->i_nlink++; ip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(fvp)) + softdep_increase_linkcnt(ip); gettime(&tv); - if (error = UFS_UPDATE(fvp, &tv, &tv, 1)) { + if (error = UFS_UPDATE(fvp, &tv, &tv, !DOINGSOFTDEP(fvp))) { VOP_UNLOCK(fvp, 0, p); goto bad; } @@ -1027,15 +1051,20 @@ abortit: error = EMLINK; goto bad; } + dp->i_effnlink++; dp->i_nlink++; dp->i_flag |= IN_CHANGE; - error = UFS_UPDATE(tdvp, &tv, &tv, 1); + if (DOINGSOFTDEP(tdvp)) + softdep_increase_linkcnt(dp); + error = UFS_UPDATE(tdvp, &tv, &tv, !DOINGSOFTDEP(tdvp)); if (error) goto bad; } - error = ufs_direnter(ip, tdvp, tcnp); + ufs_makedirentry(ip, tcnp, &newdir); + error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL); if (error) { if (doingdirectory && newparent) { + dp->i_effnlink--; dp->i_nlink--; dp->i_flag |= IN_CHANGE; (void)UFS_UPDATE(tdvp, &tv, &tv, 1); @@ -1070,9 +1099,8 @@ abortit: * (both directories, or both not directories). */ if ((xp->i_mode&IFMT) == IFDIR) { - if (! ufs_dirempty - (xp, dp->i_number, tcnp->cn_cred) || - xp->i_nlink > 2) { + if ((xp->i_effnlink > 2) || + !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) { error = ENOTEMPTY; goto bad; } @@ -1085,40 +1113,37 @@ abortit: error = EISDIR; goto bad; } - error = ufs_dirrewrite(dp, ip, tcnp); + error = ufs_dirrewrite(dp, xp, ip->i_number, + IFTODT(ip->i_mode), doingdirectory); if (error) goto bad; - /* - * If the target directory is in the same - * directory as the source directory, - * decrement the link count on the parent - * of the target directory. - */ - if (doingdirectory && !newparent) { - dp->i_nlink--; + if (doingdirectory) { + dp->i_effnlink--; dp->i_flag |= IN_CHANGE; + xp->i_effnlink--; + xp->i_flag |= IN_CHANGE; } VN_POLLEVENT(tdvp, POLLWRITE); - vput(tdvp); - /* - * Adjust the link count of the target to - * reflect the dirrewrite above. If this is - * a directory it is empty and there are - * no links to it, so we can squash the inode and - * any space associated with it. We disallowed - * renaming over top of a directory with links to - * it above, as the remaining link would point to - * a directory without "." or ".." entries. - */ - xp->i_nlink--; - if (doingdirectory) { - if (--xp->i_nlink != 0) - panic("ufs_rename: linked directory"); - error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, - tcnp->cn_cred, tcnp->cn_proc); + if (doingdirectory && !DOINGSOFTDEP(tvp)) { + /* + * Truncate inode. The only stuff left in the directory + * is "." and "..". The "." reference is inconsequential + * since we are quashing it. We have removed the "." + * reference and the reference in the parent directory, + * but there may be other hard links. The soft + * dependency code will arrange to do these operations + * after the parent directory entry has been deleted on + * disk, so when running with that code we avoid doing + * them now. + */ + dp->i_nlink--; + xp->i_nlink--; + if ((error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, + tcnp->cn_cred, tcnp->cn_proc)) != 0) + goto bad; } - xp->i_flag |= IN_CHANGE; - VN_POLLEVENT(tvp, POLLNLINK); + vput(tdvp); + VN_POLLEVENT(tvp, POLLNLINK); /* XXX this right? */ vput(tvp); xp = NULL; } @@ -1151,10 +1176,9 @@ abortit: * changed while the new name has been entered. If the source is * a file then the entry may have been unlinked or renamed. In * either case there is no further work to be done. If the source - * is a directory then it cannot have been rmdir'ed; its link - * count of three would cause a rmdir to fail with ENOTEMPTY. - * The IN_RENAME flag ensures that it cannot be moved by another - * rename. + * is a directory then it cannot have been rmdir'ed; the IN_RENAME + * flag ensures that it cannot be moved by another rename or removed + * by a rmdir. */ if (xp != ip) { if (doingdirectory) @@ -1167,44 +1191,11 @@ abortit: * and ".." set to point to the new parent. */ if (doingdirectory && newparent) { - dp->i_nlink--; - dp->i_flag |= IN_CHANGE; - error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf, - sizeof (struct dirtemplate), (off_t)0, - UIO_SYSSPACE, IO_NODELOCKED, - tcnp->cn_cred, (int *)0, (struct proc *)0); - if (error == 0) { -# if (BYTE_ORDER == LITTLE_ENDIAN) - if (fvp->v_mount->mnt_maxsymlinklen <= 0) - namlen = dirbuf.dotdot_type; - else - namlen = dirbuf.dotdot_namlen; -# else - namlen = dirbuf.dotdot_namlen; -# endif - if (namlen != 2 || - dirbuf.dotdot_name[0] != '.' || - dirbuf.dotdot_name[1] != '.') { - ufs_dirbad(xp, (doff_t)12, - "rename: mangled dir"); - } else { - dirbuf.dotdot_ino = newparent; - (void) vn_rdwr(UIO_WRITE, fvp, - (caddr_t)&dirbuf, - sizeof (struct dirtemplate), - (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED|IO_SYNC, - tcnp->cn_cred, (int *)0, - (struct proc *)0); - cache_purge(fdvp); - } - } - } - error = ufs_dirremove(fdvp, fcnp); - if (!error) { - xp->i_nlink--; - xp->i_flag |= IN_CHANGE; + xp->i_offset = mastertemplate.dot_reclen; + ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0); + cache_purge(fdvp); } + error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0); xp->i_flag &= ~IN_RENAME; } if (dp) @@ -1222,6 +1213,7 @@ out: if (doingdirectory) ip->i_flag &= ~IN_RENAME; if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) { + ip->i_effnlink--; ip->i_nlink--; ip->i_flag |= IN_CHANGE; ip->i_flag &= ~IN_RENAME; @@ -1232,18 +1224,6 @@ out: } /* - * A virgin directory (no blushing please). - */ -static struct dirtemplate mastertemplate = { - 0, 12, DT_DIR, 1, { '.', 0 }, - 0, DIRBLKSIZ - 12, DT_DIR, 2, { '.', '.', 0 } -}; -static struct odirtemplate omastertemplate = { - 0, 12, 1, { '.', 0 }, - 0, DIRBLKSIZ - 12, 2, { '.', '.', 0 } -}; - -/* * Mkdir system call */ int @@ -1260,7 +1240,9 @@ ufs_mkdir(ap) register struct componentname *cnp = ap->a_cnp; register struct inode *ip, *dp; struct vnode *tvp; + struct buf *bp; struct dirtemplate dirtemplate, *dtp; + struct direct newdir; struct timeval tv; int error, dmode; @@ -1348,25 +1330,31 @@ ufs_mkdir(ap) ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = dmode; tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ + ip->i_effnlink = 2; ip->i_nlink = 2; + if (DOINGSOFTDEP(tvp)) + softdep_increase_linkcnt(ip); if (cnp->cn_flags & ISWHITEOUT) ip->i_flags |= UF_OPAQUE; - gettime(&tv); - error = UFS_UPDATE(tvp, &tv, &tv, 1); /* - * Bump link count in parent directory - * to reflect work done below. Should - * be done before reference is created - * so reparation is possible if we crash. + * Bump link count in parent directory to reflect work done below. + * Should be done before reference is created so cleanup is + * possible if we crash. */ + dp->i_effnlink++; dp->i_nlink++; dp->i_flag |= IN_CHANGE; - error = UFS_UPDATE(dvp, &tv, &tv, 1); + if (DOINGSOFTDEP(dvp)) + softdep_increase_linkcnt(dp); + gettime(&tv); + error = UFS_UPDATE(tvp, &tv, &tv, !DOINGSOFTDEP(dvp)); if (error) goto bad; - /* Initialize directory with "." and ".." from static template. */ + /* + * Initialize directory with "." and ".." from static template. + */ if (dvp->v_mount->mnt_maxsymlinklen > 0 ) dtp = &mastertemplate; @@ -1375,39 +1363,50 @@ ufs_mkdir(ap) dirtemplate = *dtp; dirtemplate.dot_ino = ip->i_number; dirtemplate.dotdot_ino = dp->i_number; - error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate, - sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE, - IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0); - if (error) { - dp->i_nlink--; - dp->i_flag |= IN_CHANGE; + if ((error = VOP_BALLOC(tvp, (off_t)0, DIRBLKSIZ, cnp->cn_cred, + B_CLRBUF, &bp)) != 0) + goto bad; + ip->i_size = DIRBLKSIZ; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + vnode_pager_setsize(tvp, (u_long)ip->i_size); + bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate); + if ((error = UFS_UPDATE(tvp, &tv, &tv, !DOINGSOFTDEP(tvp))) != 0) { + (void)VOP_BWRITE(bp); goto bad; } - if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) - panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */ - else { - ip->i_size = DIRBLKSIZ; - ip->i_flag |= IN_CHANGE; - } - - /* Directory set up, now install it's entry in the parent directory. */ - error = ufs_direnter(ip, dvp, cnp); - if (error) { - dp->i_nlink--; - dp->i_flag |= IN_CHANGE; - } - VN_POLLEVENT(dvp, POLLWRITE); -bad: + VN_POLLEVENT(dvp, POLLWRITE); /* XXX right place? */ /* - * No need to do an explicit VOP_TRUNCATE here, vrele will do this - * for us because we set the link count to 0. + * Directory set up, now install it's entry in the parent directory. + * + * If we are not doing soft dependencies, then we must write out the + * buffer containing the new directory body before entering the new + * name in the parent. If we are doing soft dependencies, then the + * buffer containing the new directory body will be passed to and + * released in the soft dependency code after the code has attached + * an appropriate ordering dependency to the buffer which ensures that + * the buffer is written before the new name is written in the parent. */ - if (error) { + if (!DOINGSOFTDEP(dvp) && ((error = VOP_BWRITE(bp)) != 0)) + goto bad; + ufs_makedirentry(ip, cnp, &newdir); + error = ufs_direnter(dvp, tvp, &newdir, cnp, bp); + +bad: + if (error == 0) { + *ap->a_vpp = tvp; + } else { + dp->i_effnlink--; + dp->i_nlink--; + dp->i_flag |= IN_CHANGE; + /* + * No need to do an explicit VOP_TRUNCATE here, vrele will + * do this for us because we set the link count to 0. + */ + ip->i_effnlink = 0; ip->i_nlink = 0; ip->i_flag |= IN_CHANGE; vput(tvp); - } else - *ap->a_vpp = tvp; + } out: zfree(namei_zone, cnp->cn_pnbuf); vput(dvp); @@ -1435,14 +1434,17 @@ ufs_rmdir(ap) dp = VTOI(dvp); /* - * Verify the directory is empty (and valid). - * (Rmdir ".." won't be valid since - * ".." will contain a reference to - * the current directory and thus be - * non-empty.) + * Do not remove a directory that is in the process of being renamed. + * Verify the directory is empty (and valid). Rmdir ".." will not be + * valid since ".." will contain a reference to the current directory + * and thus be non-empty. */ error = 0; - if (ip->i_nlink != 2 || + if (ip->i_flag & IN_RENAME) { + error = EINVAL; + goto out; + } + if (ip->i_effnlink != 2 || !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) { error = ENOTEMPTY; goto out; @@ -1457,34 +1459,36 @@ ufs_rmdir(ap) * inode. If we crash in between, the directory * will be reattached to lost+found, */ - error = ufs_dirremove(dvp, cnp); + error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1); if (error) goto out; VN_POLLEVENT(dvp, POLLWRITE|POLLNLINK); - dp->i_nlink--; - dp->i_flag |= IN_CHANGE; cache_purge(dvp); - vput(dvp); - dvp = NULL; /* - * Truncate inode. The only stuff left - * in the directory is "." and "..". The - * "." reference is inconsequential since - * we're quashing it. The ".." reference - * has already been adjusted above. We've - * removed the "." reference and the reference - * in the parent directory, but there may be - * other hard links so decrement by 2 and - * worry about them later. + * Truncate inode. The only stuff left in the directory is "." and + * "..". The "." reference is inconsequential since we are quashing + * it. We have removed the "." reference and the reference in the + * parent directory, but there may be other hard links. So, + * ufs_dirremove will set the UF_IMMUTABLE flag to ensure that no + * new entries are made. The soft dependency code will arrange to + * do these operations after the parent directory entry has been + * deleted on disk, so when running with that code we avoid doing + * them now. */ - ip->i_nlink -= 2; - error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, - cnp->cn_proc); - cache_purge(ITOV(ip)); - VN_POLLEVENT(vp, POLLNLINK); + dp->i_effnlink--; + dp->i_flag |= IN_CHANGE; + ip->i_effnlink--; + ip->i_flag |= IN_CHANGE; + if (!DOINGSOFTDEP(vp)) { + dp->i_nlink--; + ip->i_nlink--; + error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, + cnp->cn_proc); + } + cache_purge(vp); out: - if (dvp) - vput(dvp); + vput(dvp); + VN_POLLEVENT(vp, POLLNLINK); vput(vp); return (error); } @@ -1974,7 +1978,7 @@ ufs_vinit(mntp, specops, fifoops, vpp) } if (ip->i_number == ROOTINO) - vp->v_flag |= VROOT; + vp->v_flag |= VROOT; /* * Initialize modrev times */ @@ -1995,6 +1999,7 @@ ufs_makeinode(mode, dvp, vpp, cnp) struct componentname *cnp; { register struct inode *ip, *pdir; + struct direct newdir; struct timeval tv; struct vnode *tvp; int error; @@ -2078,7 +2083,10 @@ ufs_makeinode(mode, dvp, vpp, cnp) ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ + ip->i_effnlink = 1; ip->i_nlink = 1; + if (DOINGSOFTDEP(tvp)) + softdep_increase_linkcnt(ip); if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && suser(cnp->cn_cred, NULL)) ip->i_mode &= ~ISGID; @@ -2090,10 +2098,11 @@ ufs_makeinode(mode, dvp, vpp, cnp) * Make sure inode goes to disk before directory entry. */ gettime(&tv); - error = UFS_UPDATE(tvp, &tv, &tv, 1); + error = UFS_UPDATE(tvp, &tv, &tv, !DOINGSOFTDEP(tvp)); if (error) goto bad; - error = ufs_direnter(ip, dvp, cnp); + ufs_makedirentry(ip, cnp, &newdir); + error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL); if (error) goto bad; @@ -2110,6 +2119,7 @@ bad: */ zfree(namei_zone, cnp->cn_pnbuf); vput(dvp); + ip->i_effnlink = 0; ip->i_nlink = 0; ip->i_flag |= IN_CHANGE; vput(tvp); |