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).
This commit is contained in:
Kirk McKusick 2001-03-07 07:09:55 +00:00
parent 393d77ffad
commit 589c7af992
16 changed files with 72 additions and 72 deletions

View File

@ -455,8 +455,8 @@ spec_strategy(ap)
bp->b_flags &= ~B_VALIDSUSPWRT; bp->b_flags &= ~B_VALIDSUSPWRT;
if (LIST_FIRST(&bp->b_dep) != NULL) if (LIST_FIRST(&bp->b_dep) != NULL)
buf_start(bp); buf_start(bp);
if ((vp->v_flag & VCOPYONWRITE) && if ((vp->v_flag & VCOPYONWRITE) && vp->v_rdev->si_copyonwrite &&
(error = VOP_COPYONWRITE(vp, bp)) != 0 && (error = (*vp->v_rdev->si_copyonwrite)(vp, bp)) != 0 &&
error != EOPNOTSUPP) { error != EOPNOTSUPP) {
bp->b_io.bio_error = error; bp->b_io.bio_error = error;
bp->b_io.bio_flags |= BIO_ERROR; bp->b_io.bio_flags |= BIO_ERROR;

View File

@ -67,6 +67,7 @@ typedef long ufs_lbn_t;
*/ */
struct inode { struct inode {
LIST_ENTRY(inode) i_hash;/* Hash chain. */ 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_vnode;/* Vnode associated with this inode. */
struct vnode *i_devvp;/* Vnode for block I/O. */ struct vnode *i_devvp;/* Vnode for block I/O. */
u_int32_t i_flag; /* flags, see below */ u_int32_t i_flag; /* flags, see below */
@ -83,7 +84,6 @@ struct inode {
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */ u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */ struct lockf *i_lockf;/* Head of byte-level lock list. */
struct inode *i_copyonwrite; /* copy-on-write list */
/* /*
* Side effects; used during directory lookup. * Side effects; used during directory lookup.
*/ */

View File

@ -67,6 +67,7 @@ typedef long ufs_lbn_t;
*/ */
struct inode { struct inode {
LIST_ENTRY(inode) i_hash;/* Hash chain. */ 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_vnode;/* Vnode associated with this inode. */
struct vnode *i_devvp;/* Vnode for block I/O. */ struct vnode *i_devvp;/* Vnode for block I/O. */
u_int32_t i_flag; /* flags, see below */ u_int32_t i_flag; /* flags, see below */
@ -83,7 +84,6 @@ struct inode {
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */ u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */ struct lockf *i_lockf;/* Head of byte-level lock list. */
struct inode *i_copyonwrite; /* copy-on-write list */
/* /*
* Side effects; used during directory lookup. * Side effects; used during directory lookup.
*/ */

View File

@ -179,6 +179,7 @@ allocdev(void)
si->si_flags |= SI_STASHED; si->si_flags |= SI_STASHED;
} }
LIST_INIT(&si->si_names); LIST_INIT(&si->si_names);
TAILQ_INIT(&si->si_snapshots);
return (si); return (si);
} }

View File

@ -399,14 +399,6 @@ vop_getwritemount {
OUT struct mount **mpp; OUT struct mount **mpp;
}; };
#
#% copyonwrite vp L L L
#
vop_copyonwrite {
IN struct vnode *vp;
IN struct buf *bp;
};
# #
#% print vp = = = #% print vp = = =
# #

View File

@ -455,8 +455,8 @@ spec_strategy(ap)
bp->b_flags &= ~B_VALIDSUSPWRT; bp->b_flags &= ~B_VALIDSUSPWRT;
if (LIST_FIRST(&bp->b_dep) != NULL) if (LIST_FIRST(&bp->b_dep) != NULL)
buf_start(bp); buf_start(bp);
if ((vp->v_flag & VCOPYONWRITE) && if ((vp->v_flag & VCOPYONWRITE) && vp->v_rdev->si_copyonwrite &&
(error = VOP_COPYONWRITE(vp, bp)) != 0 && (error = (*vp->v_rdev->si_copyonwrite)(vp, bp)) != 0 &&
error != EOPNOTSUPP) { error != EOPNOTSUPP) {
bp->b_io.bio_error = error; bp->b_io.bio_error = error;
bp->b_io.bio_flags |= BIO_ERROR; bp->b_io.bio_flags |= BIO_ERROR;

View File

@ -50,6 +50,8 @@
struct tty; struct tty;
struct disk; struct disk;
struct vnode; struct vnode;
struct buf;
TAILQ_HEAD(snaphead, inode);
struct specinfo { struct specinfo {
u_int si_flags; u_int si_flags;
@ -64,6 +66,8 @@ struct specinfo {
LIST_ENTRY(specinfo) si_hash; LIST_ENTRY(specinfo) si_hash;
SLIST_HEAD(, vnode) si_hlist; SLIST_HEAD(, vnode) si_hlist;
LIST_HEAD(, specinfo) si_names; LIST_HEAD(, specinfo) si_names;
struct snaphead si_snapshots;
int (*si_copyonwrite)(struct vnode *, struct buf *);
u_int si_inode; u_int si_inode;
char si_name[SPECNAMELEN + 1]; char si_name[SPECNAMELEN + 1];
void *si_drv1, *si_drv2; void *si_drv1, *si_drv2;

View File

@ -50,6 +50,8 @@
struct tty; struct tty;
struct disk; struct disk;
struct vnode; struct vnode;
struct buf;
TAILQ_HEAD(snaphead, inode);
struct specinfo { struct specinfo {
u_int si_flags; u_int si_flags;
@ -64,6 +66,8 @@ struct specinfo {
LIST_ENTRY(specinfo) si_hash; LIST_ENTRY(specinfo) si_hash;
SLIST_HEAD(, vnode) si_hlist; SLIST_HEAD(, vnode) si_hlist;
LIST_HEAD(, specinfo) si_names; LIST_HEAD(, specinfo) si_names;
struct snaphead si_snapshots;
int (*si_copyonwrite)(struct vnode *, struct buf *);
u_int si_inode; u_int si_inode;
char si_name[SPECNAMELEN + 1]; char si_name[SPECNAMELEN + 1];
void *si_drv1, *si_drv2; void *si_drv1, *si_drv2;

View File

@ -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 *)); ufs_daddr_t ffs_blkpref __P((struct inode *, ufs_daddr_t, int, ufs_daddr_t *));
int ffs_bmap __P((struct vop_bmap_args *)); int ffs_bmap __P((struct vop_bmap_args *));
void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t)); 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_fhtovp __P((struct mount *, struct fid *, struct vnode **));
int ffs_flushfiles __P((struct mount *, int, struct proc *)); int ffs_flushfiles __P((struct mount *, int, struct proc *));
void ffs_fragacct __P((struct fs *, int, int32_t [], int)); void ffs_fragacct __P((struct fs *, int, int32_t [], int));

View File

@ -36,6 +36,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/conf.h>
#include <sys/bio.h> #include <sys/bio.h>
#include <sys/buf.h> #include <sys/buf.h>
#include <sys/proc.h> #include <sys/proc.h>
@ -62,6 +63,7 @@
static int indiracct __P((struct vnode *, struct vnode *, int, ufs_daddr_t, static int indiracct __P((struct vnode *, struct vnode *, int, ufs_daddr_t,
int, int, int, int)); int, int, int, int));
static int snapacct __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *)); 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)); static int readblock __P((struct buf *, daddr_t));
#ifdef DEBUG #ifdef DEBUG
@ -85,14 +87,15 @@ ffs_snapshot(mp, snapfile)
int blksperindir, flag = mp->mnt_flag; int blksperindir, flag = mp->mnt_flag;
void *space; void *space;
struct fs *copy_fs, *fs = VFSTOUFS(mp)->um_fs; struct fs *copy_fs, *fs = VFSTOUFS(mp)->um_fs;
struct snaphead *snaphead;
struct proc *p = CURPROC; struct proc *p = CURPROC;
struct inode *devip, *ip, *xp; struct inode *ip, *xp;
struct buf *bp, *nbp, *ibp; struct buf *bp, *nbp, *ibp;
struct vnode *vp, *devvp;
struct nameidata nd; struct nameidata nd;
struct mount *wrtmp; struct mount *wrtmp;
struct dinode *dip; struct dinode *dip;
struct vattr vat; struct vattr vat;
struct vnode *vp;
struct cg *cgp; struct cg *cgp;
/* /*
@ -153,8 +156,6 @@ restart:
} }
vp = nd.ni_vp; vp = nd.ni_vp;
ip = VTOI(vp); ip = VTOI(vp);
devvp = ip->i_devvp;
devip = VTOI(devvp);
/* /*
* Allocate and copy the last block contents so as to be able * Allocate and copy the last block contents so as to be able
* to set size to that of the filesystem. * to set size to that of the filesystem.
@ -379,7 +380,8 @@ restart:
* Copy allocation information from other snapshots and then * Copy allocation information from other snapshots and then
* expunge them from the view of the current snapshot. * 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 * Before expunging a snapshot inode, note all the
* blocks that it claims with BLK_SNAP so that fsck will * 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. * it must be placed at the end of the list.
*/ */
fs->fs_snapinum[snaploc] = ip->i_number; 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); panic("ffs_snapshot: %d already on list", ip->i_number);
if (devip->i_copyonwrite == 0) { TAILQ_INSERT_TAIL(snaphead, ip, i_nextsnap);
devvp->v_flag |= VCOPYONWRITE; ip->i_devvp->v_rdev->si_copyonwrite = ffs_copyonwrite;
devip->i_copyonwrite = ip; ip->i_devvp->v_flag |= VCOPYONWRITE;
} else {
for (xp = devip->i_copyonwrite; xp->i_copyonwrite != 0; )
xp = xp->i_copyonwrite;
xp->i_copyonwrite = ip;
}
vp->v_flag |= VSYSTEM; vp->v_flag |= VSYSTEM;
/* /*
* Resume operation on filesystem. * Resume operation on filesystem.
@ -608,8 +605,8 @@ ffs_snapgone(ip)
/* /*
* Find snapshot in incore list. * Find snapshot in incore list.
*/ */
for (xp = VTOI(ip->i_devvp); xp; xp = xp->i_copyonwrite) TAILQ_FOREACH(xp, &ip->i_devvp->v_rdev->si_snapshots, i_nextsnap)
if (xp->i_copyonwrite == ip) if (xp == ip)
break; break;
if (xp == 0) if (xp == 0)
printf("ffs_snapgone: lost snapshot vnode %d\n", printf("ffs_snapgone: lost snapshot vnode %d\n",
@ -625,7 +622,7 @@ void
ffs_snapremove(vp) ffs_snapremove(vp)
struct vnode *vp; struct vnode *vp;
{ {
struct inode *ip, *xp; struct inode *ip;
struct vnode *devvp; struct vnode *devvp;
struct buf *ibp; struct buf *ibp;
struct fs *fs; struct fs *fs;
@ -653,18 +650,17 @@ ffs_snapremove(vp)
* Clear copy-on-write flag if last snapshot. * Clear copy-on-write flag if last snapshot.
*/ */
devvp = ip->i_devvp; devvp = ip->i_devvp;
for (xp = VTOI(devvp); xp; xp = xp->i_copyonwrite) { if (ip->i_nextsnap.tqe_prev == 0) {
if (xp->i_copyonwrite != ip)
continue;
xp->i_copyonwrite = ip->i_copyonwrite;
ip->i_copyonwrite = 0;
break;
}
if (xp == 0)
printf("ffs_snapremove: lost snapshot vnode %d\n", printf("ffs_snapremove: lost snapshot vnode %d\n",
ip->i_number); ip->i_number);
if (VTOI(devvp)->i_copyonwrite == 0) } else {
devvp->v_flag &= ~VCOPYONWRITE; 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 * Clear all BLK_NOCOPY fields. Pass any block claims to other
* snapshots that want them (see ffs_snapblkfree below). * snapshots that want them (see ffs_snapblkfree below).
@ -730,10 +726,11 @@ ffs_snapblkfree(freeip, bno, size)
struct vnode *vp; struct vnode *vp;
ufs_daddr_t lbn, blkno; ufs_daddr_t lbn, blkno;
int indiroff = 0, error = 0, claimedblk = 0; int indiroff = 0, error = 0, claimedblk = 0;
struct snaphead *snaphead;
lbn = fragstoblks(fs, bno); lbn = fragstoblks(fs, bno);
for (ip = VTOI(freeip->i_devvp)->i_copyonwrite; ip; snaphead = &freeip->i_devvp->v_rdev->si_snapshots;
ip = ip->i_copyonwrite) { TAILQ_FOREACH(ip, snaphead, i_nextsnap) {
vp = ITOV(ip); vp = ITOV(ip);
/* /*
* Lookup block being written. * Lookup block being written.
@ -875,11 +872,12 @@ ffs_snapshot_mount(mp)
struct ufsmount *ump = VFSTOUFS(mp); struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs = ump->um_fs; struct fs *fs = ump->um_fs;
struct proc *p = CURPROC; struct proc *p = CURPROC;
struct inode *ip, **listtailp; struct snaphead *snaphead;
struct vnode *vp; struct vnode *vp;
struct inode *ip;
int error, snaploc, loc; 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++) { for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) {
if (fs->fs_snapinum[snaploc] == 0) if (fs->fs_snapinum[snaploc] == 0)
return; return;
@ -901,14 +899,15 @@ ffs_snapshot_mount(mp)
snaploc--; snaploc--;
continue; continue;
} }
if (ip->i_copyonwrite != 0) if (ip->i_nextsnap.tqe_prev != 0)
panic("ffs_snapshot_mount: %d already on list", panic("ffs_snapshot_mount: %d already on list",
ip->i_number); ip->i_number);
*listtailp = ip; else
listtailp = &ip->i_copyonwrite; TAILQ_INSERT_TAIL(snaphead, ip, i_nextsnap);
vp->v_flag |= VSYSTEM; vp->v_flag |= VSYSTEM;
VOP_UNLOCK(vp, 0, p); ump->um_devvp->v_rdev->si_copyonwrite = ffs_copyonwrite;
ump->um_devvp->v_flag |= VCOPYONWRITE; ump->um_devvp->v_flag |= VCOPYONWRITE;
VOP_UNLOCK(vp, 0, p);
} }
} }
@ -920,15 +919,16 @@ ffs_snapshot_unmount(mp)
struct mount *mp; struct mount *mp;
{ {
struct ufsmount *ump = VFSTOUFS(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; struct inode *xp;
while ((xp = devip->i_copyonwrite) != 0) { while ((xp = TAILQ_FIRST(snaphead)) != 0) {
devip->i_copyonwrite = xp->i_copyonwrite; TAILQ_REMOVE(snaphead, xp, i_nextsnap);
xp->i_copyonwrite = 0; xp->i_nextsnap.tqe_prev = 0;
if (xp->i_effnlink > 0) if (xp->i_effnlink > 0)
vrele(ITOV(xp)); vrele(ITOV(xp));
} }
ump->um_devvp->v_rdev->si_copyonwrite = 0;
ump->um_devvp->v_flag &= ~VCOPYONWRITE; 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, * Check for need to copy block that is about to be written,
* copying the block if necessary. * copying the block if necessary.
*/ */
int static int
ffs_copyonwrite(ap) ffs_copyonwrite(devvp, bp)
struct vop_copyonwrite_args /* { struct vnode *devvp;
struct vnode *a_vp; struct buf *bp;
struct buf *a_bp;
} */ *ap;
{ {
struct buf *ibp, *cbp, *savedcbp = 0, *bp = ap->a_bp; struct buf *ibp, *cbp, *savedcbp = 0;
struct fs *fs = VTOI(bp->b_vp)->i_fs;
struct proc *p = CURPROC; struct proc *p = CURPROC;
struct fs *fs;
struct inode *ip; struct inode *ip;
struct vnode *vp; struct vnode *vp;
ufs_daddr_t lbn, blkno; ufs_daddr_t lbn, blkno;
int indiroff, error = 0; int indiroff, error = 0;
fs = TAILQ_FIRST(&devvp->v_rdev->si_snapshots)->i_fs;
lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno)); lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno));
if (p->p_flag & P_COWINPROGRESS) if (p->p_flag & P_COWINPROGRESS)
panic("ffs_copyonwrite: recursive call"); 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); vp = ITOV(ip);
/* /*
* We ensure that everything of our own that needs to be * We ensure that everything of our own that needs to be
@ -1020,7 +1019,7 @@ retry:
if (snapdebug) { if (snapdebug) {
printf("Copyonwrite: snapino %d lbn %d for ", printf("Copyonwrite: snapino %d lbn %d for ",
ip->i_number, lbn); ip->i_number, lbn);
if (bp->b_vp == ap->a_vp) if (bp->b_vp == devvp)
printf("fs metadata"); printf("fs metadata");
else else
printf("inum %d", VTOI(bp->b_vp)->i_number); printf("inum %d", VTOI(bp->b_vp)->i_number);

View File

@ -191,6 +191,7 @@ ffs_isblock(fs, cp, h)
default: default:
panic("ffs_isblock"); panic("ffs_isblock");
} }
return (0);
} }
/* /*
@ -215,6 +216,7 @@ ffs_isfreeblock(fs, cp, h)
default: default:
panic("ffs_isfreeblock"); panic("ffs_isfreeblock");
} }
return (0);
} }
/* /*

View File

@ -987,15 +987,15 @@ loop:
goto 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); vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0) if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
allerror = error; allerror = error;
VOP_UNLOCK(ump->um_devvp, 0, p); VOP_UNLOCK(ump->um_devvp, 0, p);
} }
#ifdef QUOTA
qsync(mp);
#endif
/* /*
* Write back modified superblock. * Write back modified superblock.
*/ */

View File

@ -95,7 +95,6 @@ vop_t **ffs_specop_p;
static struct vnodeopv_entry_desc ffs_specop_entries[] = { static struct vnodeopv_entry_desc ffs_specop_entries[] = {
{ &vop_default_desc, (vop_t *) ufs_vnoperatespec }, { &vop_default_desc, (vop_t *) ufs_vnoperatespec },
{ &vop_fsync_desc, (vop_t *) ffs_fsync }, { &vop_fsync_desc, (vop_t *) ffs_fsync },
{ &vop_copyonwrite_desc, (vop_t *) ffs_copyonwrite },
#ifdef FFS_EXTATTR #ifdef FFS_EXTATTR
{ &vop_getextattr_desc, (vop_t *) ufs_vop_getextattr }, { &vop_getextattr_desc, (vop_t *) ufs_vop_getextattr },
{ &vop_setextattr_desc, (vop_t *) ufs_vop_setextattr }, { &vop_setextattr_desc, (vop_t *) ufs_vop_setextattr },

View File

@ -513,7 +513,8 @@ struct ocg {
? (fs)->fs_bsize \ ? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (ip)->i_size)))) : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
#define dblksize(fs, dip, lbn) \ #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 \ ? (fs)->fs_bsize \
: (fragroundup(fs, blkoff(fs, (dip)->di_size)))) : (fragroundup(fs, blkoff(fs, (dip)->di_size))))
#define sblksize(fs, size, lbn) \ #define sblksize(fs, size, lbn) \

View File

@ -82,7 +82,6 @@ static struct vnodeopv_entry_desc mfs_vnodeop_entries[] = {
{ &vop_print_desc, (vop_t *) mfs_print }, { &vop_print_desc, (vop_t *) mfs_print },
{ &vop_reclaim_desc, (vop_t *) mfs_reclaim }, { &vop_reclaim_desc, (vop_t *) mfs_reclaim },
{ &vop_strategy_desc, (vop_t *) mfs_strategy }, { &vop_strategy_desc, (vop_t *) mfs_strategy },
{ &vop_copyonwrite_desc, (vop_t *) vop_eopnotsupp },
{ &vop_unlock_desc, (vop_t *) vop_defaultop }, { &vop_unlock_desc, (vop_t *) vop_defaultop },
{ &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount }, { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ NULL, NULL } { NULL, NULL }

View File

@ -67,6 +67,7 @@ typedef long ufs_lbn_t;
*/ */
struct inode { struct inode {
LIST_ENTRY(inode) i_hash;/* Hash chain. */ 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_vnode;/* Vnode associated with this inode. */
struct vnode *i_devvp;/* Vnode for block I/O. */ struct vnode *i_devvp;/* Vnode for block I/O. */
u_int32_t i_flag; /* flags, see below */ u_int32_t i_flag; /* flags, see below */
@ -83,7 +84,6 @@ struct inode {
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
u_quad_t i_modrev; /* Revision level for NFS lease. */ u_quad_t i_modrev; /* Revision level for NFS lease. */
struct lockf *i_lockf;/* Head of byte-level lock list. */ struct lockf *i_lockf;/* Head of byte-level lock list. */
struct inode *i_copyonwrite; /* copy-on-write list */
/* /*
* Side effects; used during directory lookup. * Side effects; used during directory lookup.
*/ */