From 61db3f4296e7cbf26765b9523064a58053f033d1 Mon Sep 17 00:00:00 2001 From: mckusick Date: Wed, 7 Mar 2001 07:09:55 +0000 Subject: Fixes to track snapshot copy-on-write checking in the specinfo structure rather than assuming that the device vnode would reside in the FFS filesystem (which is obviously a broken assumption with the device filesystem). --- sys/fs/specfs/spec_vnops.c | 4 +- sys/gnu/ext2fs/inode.h | 2 +- sys/gnu/fs/ext2fs/inode.h | 2 +- sys/kern/kern_conf.c | 1 + sys/kern/vnode_if.src | 8 ---- sys/miscfs/specfs/spec_vnops.c | 4 +- sys/sys/conf.h | 4 ++ sys/sys/linedisc.h | 4 ++ sys/ufs/ffs/ffs_extern.h | 1 - sys/ufs/ffs/ffs_snapshot.c | 97 +++++++++++++++++++++--------------------- sys/ufs/ffs/ffs_subr.c | 2 + sys/ufs/ffs/ffs_vfsops.c | 8 ++-- sys/ufs/ffs/ffs_vnops.c | 1 - sys/ufs/ffs/fs.h | 3 +- sys/ufs/mfs/mfs_vnops.c | 1 - sys/ufs/ufs/inode.h | 2 +- 16 files changed, 72 insertions(+), 72 deletions(-) diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index 35a0a49..2940f40 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/specfs/spec_vnops.c @@ -455,8 +455,8 @@ spec_strategy(ap) bp->b_flags &= ~B_VALIDSUSPWRT; if (LIST_FIRST(&bp->b_dep) != NULL) buf_start(bp); - if ((vp->v_flag & VCOPYONWRITE) && - (error = VOP_COPYONWRITE(vp, bp)) != 0 && + if ((vp->v_flag & VCOPYONWRITE) && vp->v_rdev->si_copyonwrite && + (error = (*vp->v_rdev->si_copyonwrite)(vp, bp)) != 0 && error != EOPNOTSUPP) { bp->b_io.bio_error = error; bp->b_io.bio_flags |= BIO_ERROR; diff --git a/sys/gnu/ext2fs/inode.h b/sys/gnu/ext2fs/inode.h index 79e79b1..3e7c67d 100644 --- a/sys/gnu/ext2fs/inode.h +++ b/sys/gnu/ext2fs/inode.h @@ -67,6 +67,7 @@ typedef long ufs_lbn_t; */ struct inode { LIST_ENTRY(inode) i_hash;/* Hash chain. */ + TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list */ struct vnode *i_vnode;/* Vnode associated with this inode. */ struct vnode *i_devvp;/* Vnode for block I/O. */ u_int32_t i_flag; /* flags, see below */ @@ -83,7 +84,6 @@ struct inode { struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ u_quad_t i_modrev; /* Revision level for NFS lease. */ struct lockf *i_lockf;/* Head of byte-level lock list. */ - struct inode *i_copyonwrite; /* copy-on-write list */ /* * Side effects; used during directory lookup. */ diff --git a/sys/gnu/fs/ext2fs/inode.h b/sys/gnu/fs/ext2fs/inode.h index 79e79b1..3e7c67d 100644 --- a/sys/gnu/fs/ext2fs/inode.h +++ b/sys/gnu/fs/ext2fs/inode.h @@ -67,6 +67,7 @@ typedef long ufs_lbn_t; */ struct inode { LIST_ENTRY(inode) i_hash;/* Hash chain. */ + TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list */ struct vnode *i_vnode;/* Vnode associated with this inode. */ struct vnode *i_devvp;/* Vnode for block I/O. */ u_int32_t i_flag; /* flags, see below */ @@ -83,7 +84,6 @@ struct inode { struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ u_quad_t i_modrev; /* Revision level for NFS lease. */ struct lockf *i_lockf;/* Head of byte-level lock list. */ - struct inode *i_copyonwrite; /* copy-on-write list */ /* * Side effects; used during directory lookup. */ diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index e6a173b..86185f7 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -179,6 +179,7 @@ allocdev(void) si->si_flags |= SI_STASHED; } LIST_INIT(&si->si_names); + TAILQ_INIT(&si->si_snapshots); return (si); } diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index c8f91f1..87fe31c 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -400,14 +400,6 @@ vop_getwritemount { }; # -#% copyonwrite vp L L L -# -vop_copyonwrite { - IN struct vnode *vp; - IN struct buf *bp; -}; - -# #% print vp = = = # vop_print { diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index 35a0a49..2940f40 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -455,8 +455,8 @@ spec_strategy(ap) bp->b_flags &= ~B_VALIDSUSPWRT; if (LIST_FIRST(&bp->b_dep) != NULL) buf_start(bp); - if ((vp->v_flag & VCOPYONWRITE) && - (error = VOP_COPYONWRITE(vp, bp)) != 0 && + if ((vp->v_flag & VCOPYONWRITE) && vp->v_rdev->si_copyonwrite && + (error = (*vp->v_rdev->si_copyonwrite)(vp, bp)) != 0 && error != EOPNOTSUPP) { bp->b_io.bio_error = error; bp->b_io.bio_flags |= BIO_ERROR; diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 81b94bc..7f1e85e 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -50,6 +50,8 @@ struct tty; struct disk; struct vnode; +struct buf; +TAILQ_HEAD(snaphead, inode); struct specinfo { u_int si_flags; @@ -64,6 +66,8 @@ struct specinfo { LIST_ENTRY(specinfo) si_hash; SLIST_HEAD(, vnode) si_hlist; LIST_HEAD(, specinfo) si_names; + struct snaphead si_snapshots; + int (*si_copyonwrite)(struct vnode *, struct buf *); u_int si_inode; char si_name[SPECNAMELEN + 1]; void *si_drv1, *si_drv2; diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h index 81b94bc..7f1e85e 100644 --- a/sys/sys/linedisc.h +++ b/sys/sys/linedisc.h @@ -50,6 +50,8 @@ struct tty; struct disk; struct vnode; +struct buf; +TAILQ_HEAD(snaphead, inode); struct specinfo { u_int si_flags; @@ -64,6 +66,8 @@ struct specinfo { LIST_ENTRY(specinfo) si_hash; SLIST_HEAD(, vnode) si_hlist; LIST_HEAD(, specinfo) si_names; + struct snaphead si_snapshots; + int (*si_copyonwrite)(struct vnode *, struct buf *); u_int si_inode; char si_name[SPECNAMELEN + 1]; void *si_drv1, *si_drv2; diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 7801412..a755980 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -77,7 +77,6 @@ void ffs_blkfree __P((struct inode *, ufs_daddr_t, long)); ufs_daddr_t ffs_blkpref __P((struct inode *, ufs_daddr_t, int, ufs_daddr_t *)); int ffs_bmap __P((struct vop_bmap_args *)); void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t)); -int ffs_copyonwrite __P((struct vop_copyonwrite_args *ap)); int ffs_fhtovp __P((struct mount *, struct fid *, struct vnode **)); int ffs_flushfiles __P((struct mount *, int, struct proc *)); void ffs_fragacct __P((struct fs *, int, int32_t [], int)); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 029ab35..c8a808f 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -62,6 +63,7 @@ static int indiracct __P((struct vnode *, struct vnode *, int, ufs_daddr_t, int, int, int, int)); static int snapacct __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *)); +static int ffs_copyonwrite __P((struct vnode *, struct buf *)); static int readblock __P((struct buf *, daddr_t)); #ifdef DEBUG @@ -85,14 +87,15 @@ ffs_snapshot(mp, snapfile) int blksperindir, flag = mp->mnt_flag; void *space; struct fs *copy_fs, *fs = VFSTOUFS(mp)->um_fs; + struct snaphead *snaphead; struct proc *p = CURPROC; - struct inode *devip, *ip, *xp; + struct inode *ip, *xp; struct buf *bp, *nbp, *ibp; - struct vnode *vp, *devvp; struct nameidata nd; struct mount *wrtmp; struct dinode *dip; struct vattr vat; + struct vnode *vp; struct cg *cgp; /* @@ -153,8 +156,6 @@ restart: } vp = nd.ni_vp; ip = VTOI(vp); - devvp = ip->i_devvp; - devip = VTOI(devvp); /* * Allocate and copy the last block contents so as to be able * to set size to that of the filesystem. @@ -379,7 +380,8 @@ restart: * Copy allocation information from other snapshots and then * expunge them from the view of the current snapshot. */ - for (xp = devip->i_copyonwrite; xp; xp = xp->i_copyonwrite) { + snaphead = &ip->i_devvp->v_rdev->si_snapshots; + TAILQ_FOREACH(xp, snaphead, i_nextsnap) { /* * Before expunging a snapshot inode, note all the * blocks that it claims with BLK_SNAP so that fsck will @@ -451,16 +453,11 @@ restart: * it must be placed at the end of the list. */ fs->fs_snapinum[snaploc] = ip->i_number; - if (ip->i_copyonwrite != 0) + if (ip->i_nextsnap.tqe_prev != 0) panic("ffs_snapshot: %d already on list", ip->i_number); - if (devip->i_copyonwrite == 0) { - devvp->v_flag |= VCOPYONWRITE; - devip->i_copyonwrite = ip; - } else { - for (xp = devip->i_copyonwrite; xp->i_copyonwrite != 0; ) - xp = xp->i_copyonwrite; - xp->i_copyonwrite = ip; - } + TAILQ_INSERT_TAIL(snaphead, ip, i_nextsnap); + ip->i_devvp->v_rdev->si_copyonwrite = ffs_copyonwrite; + ip->i_devvp->v_flag |= VCOPYONWRITE; vp->v_flag |= VSYSTEM; /* * Resume operation on filesystem. @@ -608,8 +605,8 @@ ffs_snapgone(ip) /* * Find snapshot in incore list. */ - for (xp = VTOI(ip->i_devvp); xp; xp = xp->i_copyonwrite) - if (xp->i_copyonwrite == ip) + TAILQ_FOREACH(xp, &ip->i_devvp->v_rdev->si_snapshots, i_nextsnap) + if (xp == ip) break; if (xp == 0) printf("ffs_snapgone: lost snapshot vnode %d\n", @@ -625,7 +622,7 @@ void ffs_snapremove(vp) struct vnode *vp; { - struct inode *ip, *xp; + struct inode *ip; struct vnode *devvp; struct buf *ibp; struct fs *fs; @@ -653,18 +650,17 @@ ffs_snapremove(vp) * Clear copy-on-write flag if last snapshot. */ devvp = ip->i_devvp; - for (xp = VTOI(devvp); xp; xp = xp->i_copyonwrite) { - if (xp->i_copyonwrite != ip) - continue; - xp->i_copyonwrite = ip->i_copyonwrite; - ip->i_copyonwrite = 0; - break; - } - if (xp == 0) + if (ip->i_nextsnap.tqe_prev == 0) { printf("ffs_snapremove: lost snapshot vnode %d\n", ip->i_number); - if (VTOI(devvp)->i_copyonwrite == 0) - devvp->v_flag &= ~VCOPYONWRITE; + } else { + TAILQ_REMOVE(&devvp->v_rdev->si_snapshots, ip, i_nextsnap); + ip->i_nextsnap.tqe_prev = 0; + if (TAILQ_FIRST(&devvp->v_rdev->si_snapshots) == 0) { + devvp->v_rdev->si_copyonwrite = 0; + devvp->v_flag &= ~VCOPYONWRITE; + } + } /* * Clear all BLK_NOCOPY fields. Pass any block claims to other * snapshots that want them (see ffs_snapblkfree below). @@ -730,10 +726,11 @@ ffs_snapblkfree(freeip, bno, size) struct vnode *vp; ufs_daddr_t lbn, blkno; int indiroff = 0, error = 0, claimedblk = 0; + struct snaphead *snaphead; lbn = fragstoblks(fs, bno); - for (ip = VTOI(freeip->i_devvp)->i_copyonwrite; ip; - ip = ip->i_copyonwrite) { + snaphead = &freeip->i_devvp->v_rdev->si_snapshots; + TAILQ_FOREACH(ip, snaphead, i_nextsnap) { vp = ITOV(ip); /* * Lookup block being written. @@ -875,11 +872,12 @@ ffs_snapshot_mount(mp) struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs = ump->um_fs; struct proc *p = CURPROC; - struct inode *ip, **listtailp; + struct snaphead *snaphead; struct vnode *vp; + struct inode *ip; int error, snaploc, loc; - listtailp = &VTOI(ump->um_devvp)->i_copyonwrite; + snaphead = &ump->um_devvp->v_rdev->si_snapshots; for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) { if (fs->fs_snapinum[snaploc] == 0) return; @@ -901,14 +899,15 @@ ffs_snapshot_mount(mp) snaploc--; continue; } - if (ip->i_copyonwrite != 0) + if (ip->i_nextsnap.tqe_prev != 0) panic("ffs_snapshot_mount: %d already on list", ip->i_number); - *listtailp = ip; - listtailp = &ip->i_copyonwrite; + else + TAILQ_INSERT_TAIL(snaphead, ip, i_nextsnap); vp->v_flag |= VSYSTEM; - VOP_UNLOCK(vp, 0, p); + ump->um_devvp->v_rdev->si_copyonwrite = ffs_copyonwrite; ump->um_devvp->v_flag |= VCOPYONWRITE; + VOP_UNLOCK(vp, 0, p); } } @@ -920,15 +919,16 @@ ffs_snapshot_unmount(mp) struct mount *mp; { struct ufsmount *ump = VFSTOUFS(mp); - struct inode *devip = VTOI(ump->um_devvp); + struct snaphead *snaphead = &ump->um_devvp->v_rdev->si_snapshots; struct inode *xp; - while ((xp = devip->i_copyonwrite) != 0) { - devip->i_copyonwrite = xp->i_copyonwrite; - xp->i_copyonwrite = 0; + while ((xp = TAILQ_FIRST(snaphead)) != 0) { + TAILQ_REMOVE(snaphead, xp, i_nextsnap); + xp->i_nextsnap.tqe_prev = 0; if (xp->i_effnlink > 0) vrele(ITOV(xp)); } + ump->um_devvp->v_rdev->si_copyonwrite = 0; ump->um_devvp->v_flag &= ~VCOPYONWRITE; } @@ -936,25 +936,24 @@ ffs_snapshot_unmount(mp) * Check for need to copy block that is about to be written, * copying the block if necessary. */ -int -ffs_copyonwrite(ap) - struct vop_copyonwrite_args /* { - struct vnode *a_vp; - struct buf *a_bp; - } */ *ap; +static int +ffs_copyonwrite(devvp, bp) + struct vnode *devvp; + struct buf *bp; { - struct buf *ibp, *cbp, *savedcbp = 0, *bp = ap->a_bp; - struct fs *fs = VTOI(bp->b_vp)->i_fs; + struct buf *ibp, *cbp, *savedcbp = 0; struct proc *p = CURPROC; + struct fs *fs; struct inode *ip; struct vnode *vp; ufs_daddr_t lbn, blkno; int indiroff, error = 0; + fs = TAILQ_FIRST(&devvp->v_rdev->si_snapshots)->i_fs; lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno)); if (p->p_flag & P_COWINPROGRESS) panic("ffs_copyonwrite: recursive call"); - for (ip = VTOI(ap->a_vp)->i_copyonwrite; ip; ip = ip->i_copyonwrite) { + TAILQ_FOREACH(ip, &devvp->v_rdev->si_snapshots, i_nextsnap) { vp = ITOV(ip); /* * We ensure that everything of our own that needs to be @@ -1020,7 +1019,7 @@ retry: if (snapdebug) { printf("Copyonwrite: snapino %d lbn %d for ", ip->i_number, lbn); - if (bp->b_vp == ap->a_vp) + if (bp->b_vp == devvp) printf("fs metadata"); else printf("inum %d", VTOI(bp->b_vp)->i_number); diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index 5155a42..c3471de 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -191,6 +191,7 @@ ffs_isblock(fs, cp, h) default: panic("ffs_isblock"); } + return (0); } /* @@ -215,6 +216,7 @@ ffs_isfreeblock(fs, cp, h) default: panic("ffs_isfreeblock"); } + return (0); } /* diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 4558780..78aaae5 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -987,15 +987,15 @@ loop: goto loop; } } - if (waitfor == MNT_NOWAIT) { +#ifdef QUOTA + qsync(mp); +#endif + if (waitfor != MNT_LAZY) { 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. */ diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index a01217d..4910f6a 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -95,7 +95,6 @@ vop_t **ffs_specop_p; static struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, { &vop_fsync_desc, (vop_t *) ffs_fsync }, - { &vop_copyonwrite_desc, (vop_t *) ffs_copyonwrite }, #ifdef FFS_EXTATTR { &vop_getextattr_desc, (vop_t *) ufs_vop_getextattr }, { &vop_setextattr_desc, (vop_t *) ufs_vop_setextattr }, diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 515c065..53d497c 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -513,7 +513,8 @@ struct ocg { ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) #define dblksize(fs, dip, lbn) \ - (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \ + (((lbn) >= NDADDR || \ + (dip)->di_size >= (u_int64_t)smalllblktosize(fs, (lbn) + 1)) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) #define sblksize(fs, size, lbn) \ diff --git a/sys/ufs/mfs/mfs_vnops.c b/sys/ufs/mfs/mfs_vnops.c index 872d947..9912dfb 100644 --- a/sys/ufs/mfs/mfs_vnops.c +++ b/sys/ufs/mfs/mfs_vnops.c @@ -82,7 +82,6 @@ static struct vnodeopv_entry_desc mfs_vnodeop_entries[] = { { &vop_print_desc, (vop_t *) mfs_print }, { &vop_reclaim_desc, (vop_t *) mfs_reclaim }, { &vop_strategy_desc, (vop_t *) mfs_strategy }, - { &vop_copyonwrite_desc, (vop_t *) vop_eopnotsupp }, { &vop_unlock_desc, (vop_t *) vop_defaultop }, { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount }, { NULL, NULL } diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index 79e79b1..3e7c67d 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -67,6 +67,7 @@ typedef long ufs_lbn_t; */ struct inode { LIST_ENTRY(inode) i_hash;/* Hash chain. */ + TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list */ struct vnode *i_vnode;/* Vnode associated with this inode. */ struct vnode *i_devvp;/* Vnode for block I/O. */ u_int32_t i_flag; /* flags, see below */ @@ -83,7 +84,6 @@ struct inode { struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ u_quad_t i_modrev; /* Revision level for NFS lease. */ struct lockf *i_lockf;/* Head of byte-level lock list. */ - struct inode *i_copyonwrite; /* copy-on-write list */ /* * Side effects; used during directory lookup. */ -- cgit v1.1