summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs/ffs_snapshot.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs/ffs/ffs_snapshot.c')
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c611
1 files changed, 474 insertions, 137 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index 7965211..7bc4656 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -35,6 +35,7 @@
*/
#include <sys/param.h>
+#include <sys/stdint.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/disklabel.h>
@@ -47,6 +48,7 @@
#include <sys/mount.h>
#include <sys/resource.h>
#include <sys/resourcevar.h>
+#include <sys/disklabel.h>
#include <sys/vnode.h>
#include <ufs/ufs/extattr.h>
@@ -62,20 +64,34 @@
#define DEBUG 1
static int cgaccount(int, struct vnode *, struct buf *, int);
-static int expunge(struct vnode *, struct inode *, struct fs *,
- int (*)(struct vnode *, ufs_daddr_t *, ufs_daddr_t *, struct fs *,
- ufs_daddr_t, int), int);
-static int indiracct(struct vnode *, struct vnode *, int, ufs_daddr_t,
- int, int, int, int, struct fs *, int (*)(struct vnode *,
- ufs_daddr_t *, ufs_daddr_t *, struct fs *, ufs_daddr_t, int), int);
-static int fullacct(struct vnode *, ufs_daddr_t *, ufs_daddr_t *,
- struct fs *, ufs_daddr_t, int);
-static int snapacct(struct vnode *, ufs_daddr_t *, ufs_daddr_t *,
- struct fs *, ufs_daddr_t, int);
-static int mapacct(struct vnode *, ufs_daddr_t *, ufs_daddr_t *,
- struct fs *, ufs_daddr_t, int);
+static int expunge_ufs1(struct vnode *, struct inode *, struct fs *,
+ int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *,
+ ufs_lbn_t, int), int);
+static int indiracct_ufs1(struct vnode *, struct vnode *, int,
+ ufs1_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *,
+ int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *,
+ ufs_lbn_t, int), int);
+static int fullacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+static int snapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+static int mapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+static int expunge_ufs2(struct vnode *, struct inode *, struct fs *,
+ int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *,
+ ufs_lbn_t, int), int);
+static int indiracct_ufs2(struct vnode *, struct vnode *, int,
+ ufs2_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *,
+ int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *,
+ ufs_lbn_t, int), int);
+static int fullacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
static int ffs_copyonwrite(struct vnode *, struct buf *);
-static int readblock(struct buf *, daddr_t);
+static int readblock(struct buf *, ufs2_daddr_t);
/*
* To ensure the consistency of snapshots across crashes, we must
@@ -104,8 +120,8 @@ ffs_snapshot(mp, snapfile)
struct mount *mp;
char *snapfile;
{
- ufs_daddr_t blkno;
- int error, cg, snaploc, numblks;
+ ufs2_daddr_t numblks, blkno;
+ int error, cg, snaploc;
int i, size, len, loc;
int flag = mp->mnt_flag;
struct timespec starttime = {0, 0}, endtime;
@@ -191,6 +207,7 @@ restart:
if (error)
goto out;
ip->i_size = lblktosize(fs, (off_t)numblks);
+ DIP(ip, i_size) = ip->i_size;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
if ((error = readblock(bp, numblks - 1)) != 0)
goto out;
@@ -216,7 +233,8 @@ restart:
/*
* Allocate copies for the superblock and its summary information.
*/
- error = UFS_BALLOC(vp, (off_t)(SBOFF), SBSIZE, KERNCRED, 0, &nbp);
+ error = UFS_BALLOC(vp, lfragtosize(fs, fs->fs_sblockloc),
+ fs->fs_sbsize, KERNCRED, 0, &nbp);
if (error)
goto out;
bawrite(nbp);
@@ -266,6 +284,7 @@ restart:
* Change inode to snapshot type file.
*/
ip->i_flags |= SF_SNAPSHOT;
+ DIP(ip, i_flags) = ip->i_flags;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* Ensure that the snapshot is completely on disk.
@@ -315,19 +334,21 @@ restart:
* Grab a copy of the superblock and its summary information.
* We delay writing it until the suspension is released below.
*/
- error = bread(vp, lblkno(fs, SBOFF), fs->fs_bsize, KERNCRED, &sbp);
+ error = bread(vp, fragstoblks(fs, fs->fs_sblockloc), fs->fs_bsize,
+ KERNCRED, &sbp);
if (error) {
brelse(sbp);
sbp = NULL;
goto out1;
}
- copy_fs = (struct fs *)(sbp->b_data + blkoff(fs, SBOFF));
+ loc = blkoff(fs, lfragtosize(fs, fs->fs_sblockloc));
+ copy_fs = (struct fs *)(sbp->b_data + loc);
bcopy(fs, copy_fs, fs->fs_sbsize);
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
copy_fs->fs_clean = 1;
- if (fs->fs_sbsize < SBSIZE)
- bzero(&sbp->b_data[blkoff(fs, SBOFF) + fs->fs_sbsize],
- SBSIZE - fs->fs_sbsize);
+ if (fs->fs_sbsize < SBLOCKSIZE)
+ bzero(&sbp->b_data[loc + fs->fs_sbsize],
+ SBLOCKSIZE - fs->fs_sbsize);
size = blkroundup(fs, fs->fs_cssize);
if (fs->fs_contigsumsize > 0)
size += fs->fs_ncg * sizeof(int32_t);
@@ -399,15 +420,20 @@ loop:
if (loc < NDADDR) {
len = fragroundup(fs, blkoff(fs, xp->i_size));
if (len < fs->fs_bsize) {
- ffs_blkfree(copy_fs, vp, xp->i_db[loc], len,
- xp->i_number);
- blkno = xp->i_db[loc];
- xp->i_db[loc] = 0;
+ ffs_blkfree(copy_fs, vp, DIP(xp, i_db[loc]),
+ len, xp->i_number);
+ blkno = DIP(xp, i_db[loc]);
+ DIP(xp, i_db[loc]) = 0;
}
}
- error = expunge(vp, xp, copy_fs, fullacct, BLK_NOCOPY);
+ if (xp->i_ump->um_fstype == UFS1)
+ error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1,
+ BLK_NOCOPY);
+ else
+ error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2,
+ BLK_NOCOPY);
if (blkno)
- xp->i_db[loc] = blkno;
+ DIP(xp, i_db[loc]) = blkno;
if (!error)
error = ffs_freefile(copy_fs, vp, xp->i_number,
xp->i_mode);
@@ -458,7 +484,13 @@ out1:
TAILQ_FOREACH(xp, snaphead, i_nextsnap) {
if (xp == ip)
break;
- if ((error = expunge(vp, xp, fs, snapacct, BLK_SNAP)) != 0) {
+ if (xp->i_ump->um_fstype == UFS1)
+ error = expunge_ufs1(vp, xp, fs, snapacct_ufs1,
+ BLK_SNAP);
+ else
+ error = expunge_ufs2(vp, xp, fs, snapacct_ufs2,
+ BLK_SNAP);
+ if (error) {
fs->fs_snapinum[snaploc] = 0;
goto done;
}
@@ -467,7 +499,11 @@ out1:
* Expunge the blocks used by the snapshots from the set of
* blocks marked as used in the snapshot bitmaps.
*/
- if ((error = expunge(vp, ip, copy_fs, mapacct, BLK_SNAP)) != 0) {
+ if (ip->i_ump->um_fstype == UFS1)
+ error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, BLK_SNAP);
+ else
+ error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, BLK_SNAP);
+ if (error) {
fs->fs_snapinum[snaploc] = 0;
goto done;
}
@@ -528,7 +564,8 @@ cgaccount(cg, vp, nbp, passno)
struct inode *ip;
struct cg *cgp;
struct fs *fs;
- int error, numblks, base, len, loc, indiroff;
+ ufs2_daddr_t base, numblks;
+ int error, len, loc, indiroff;
ip = VTOI(vp);
fs = ip->i_fs;
@@ -559,10 +596,10 @@ cgaccount(cg, vp, nbp, passno)
if (base < NDADDR) {
for ( ; loc < NDADDR; loc++) {
if (ffs_isblock(fs, cg_blksfree(cgp), loc))
- ip->i_db[loc] = BLK_NOCOPY;
- else if (passno == 2 && ip->i_db[loc] == BLK_NOCOPY)
- ip->i_db[loc] = 0;
- else if (passno == 1 && ip->i_db[loc] == BLK_NOCOPY)
+ DIP(ip, i_db[loc]) = BLK_NOCOPY;
+ else if (passno == 2 && DIP(ip, i_db[loc])== BLK_NOCOPY)
+ DIP(ip, i_db[loc]) = 0;
+ else if (passno == 1 && DIP(ip, i_db[loc])== BLK_NOCOPY)
panic("ffs_snapshot: lost direct block");
}
}
@@ -587,13 +624,25 @@ cgaccount(cg, vp, nbp, passno)
}
indiroff = 0;
}
+ if (ip->i_ump->um_fstype == UFS1) {
+ if (ffs_isblock(fs, cg_blksfree(cgp), loc))
+ ((ufs1_daddr_t *)(ibp->b_data))[indiroff] =
+ BLK_NOCOPY;
+ else if (passno == 2 && ((ufs1_daddr_t *)(ibp->b_data))
+ [indiroff] == BLK_NOCOPY)
+ ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = 0;
+ else if (passno == 1 && ((ufs1_daddr_t *)(ibp->b_data))
+ [indiroff] == BLK_NOCOPY)
+ panic("ffs_snapshot: lost indirect block");
+ continue;
+ }
if (ffs_isblock(fs, cg_blksfree(cgp), loc))
- ((ufs_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY;
+ ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY;
else if (passno == 2 &&
- ((ufs_daddr_t *)(ibp->b_data))[indiroff] == BLK_NOCOPY)
- ((ufs_daddr_t *)(ibp->b_data))[indiroff] = 0;
+ ((ufs2_daddr_t *)(ibp->b_data)) [indiroff] == BLK_NOCOPY)
+ ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = 0;
else if (passno == 1 &&
- ((ufs_daddr_t *)(ibp->b_data))[indiroff] == BLK_NOCOPY)
+ ((ufs2_daddr_t *)(ibp->b_data)) [indiroff] == BLK_NOCOPY)
panic("ffs_snapshot: lost indirect block");
}
bqrelse(bp);
@@ -608,34 +657,37 @@ cgaccount(cg, vp, nbp, passno)
* blocks that it claims with BLK_SNAP so that fsck will
* be able to account for those blocks properly and so
* that this snapshot knows that it need not copy them
- * if the other snapshot holding them is freed.
+ * if the other snapshot holding them is freed. This code
+ * is reproduced once each for UFS1 and UFS2.
*/
static int
-expunge(snapvp, cancelip, fs, acctfunc, expungetype)
+expunge_ufs1(snapvp, cancelip, fs, acctfunc, expungetype)
struct vnode *snapvp;
struct inode *cancelip;
struct fs *fs;
- int (*acctfunc)(struct vnode *, ufs_daddr_t *, ufs_daddr_t *,
- struct fs *, ufs_daddr_t, int);
+ int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
int expungetype;
{
- int i, len, error, numblks, blksperindir;
- ufs_daddr_t lbn, rlbn, blkno, indiroff;
+ int i, error, indiroff;
+ ufs_lbn_t lbn, rlbn;
+ ufs2_daddr_t len, blkno, numblks, blksperindir;
+ struct ufs1_dinode *dip;
struct thread *td = curthread;
- struct dinode *dip;
struct buf *bp;
numblks = howmany(cancelip->i_size, fs->fs_bsize);
- if ((error = (*acctfunc)(snapvp, &cancelip->i_db[0],
- &cancelip->i_ib[NIADDR], fs, 0, expungetype)))
+ if ((error = (*acctfunc)(snapvp, &cancelip->i_din1->di_db[0],
+ &cancelip->i_din1->di_ib[NIADDR], fs, 0, expungetype)))
return (error);
blksperindir = 1;
lbn = -NDADDR;
len = numblks - NDADDR;
rlbn = NDADDR;
for (i = 0; len > 0 && i < NIADDR; i++) {
- error = indiracct(snapvp, ITOV(cancelip), i, cancelip->i_ib[i],
- lbn, rlbn, len, blksperindir, fs, acctfunc, expungetype);
+ error = indiracct_ufs1(snapvp, ITOV(cancelip), i,
+ cancelip->i_din1->di_ib[i], lbn, rlbn, len,
+ blksperindir, fs, acctfunc, expungetype);
if (error)
return (error);
blksperindir *= NINDIR(fs);
@@ -650,7 +702,7 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype)
lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
blkno = 0;
if (lbn < NDADDR) {
- blkno = cancelip->i_db[lbn];
+ blkno = cancelip->i_din1->di_db[lbn];
} else {
td->td_proc->p_flag |= P_COWINPROGRESS;
error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn),
@@ -659,7 +711,7 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype)
if (error)
return (error);
indiroff = (lbn - NDADDR) % NINDIR(fs);
- blkno = ((ufs_daddr_t *)(bp->b_data))[indiroff];
+ blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff];
bqrelse(bp);
}
error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn),
@@ -672,13 +724,14 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype)
* Set a snapshot inode to be a zero length file, regular files
* to be completely unallocated.
*/
- dip = (struct dinode *)bp->b_data + ino_to_fsbo(fs, cancelip->i_number);
+ dip = (struct ufs1_dinode *)bp->b_data +
+ ino_to_fsbo(fs, cancelip->i_number);
if (expungetype == BLK_NOCOPY)
dip->di_mode = 0;
dip->di_size = 0;
dip->di_blocks = 0;
dip->di_flags &= ~SF_SNAPSHOT;
- bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs_daddr_t));
+ bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs1_daddr_t));
bdwrite(bp);
return (0);
}
@@ -688,24 +741,25 @@ expunge(snapvp, cancelip, fs, acctfunc, expungetype)
* its indirect blocks in snapvp.
*/
static int
-indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs,
- acctfunc, expungetype)
+indiracct_ufs1(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks,
+ blksperindir, fs, acctfunc, expungetype)
struct vnode *snapvp;
struct vnode *cancelvp;
int level;
- ufs_daddr_t blkno;
- int lbn;
- int rlbn;
- int remblks;
- int blksperindir;
+ ufs1_daddr_t blkno;
+ ufs_lbn_t lbn;
+ ufs_lbn_t rlbn;
+ ufs_lbn_t remblks;
+ ufs_lbn_t blksperindir;
struct fs *fs;
- int (*acctfunc)(struct vnode *, ufs_daddr_t *, ufs_daddr_t *,
- struct fs *, ufs_daddr_t, int);
+ int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
int expungetype;
{
- int subblksperindir, error, last, num, i;
+ int error, num, i;
+ ufs_lbn_t subblksperindir;
struct indir indirs[NIADDR + 2];
- ufs_daddr_t *bap;
+ ufs1_daddr_t last, *bap;
struct buf *bp;
if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0)
@@ -729,7 +783,7 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs,
last = howmany(remblks, blksperindir);
if (last > NINDIR(fs))
last = NINDIR(fs);
- MALLOC(bap, ufs_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK);
+ MALLOC(bap, ufs1_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK);
bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize);
bqrelse(bp);
error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, rlbn, expungetype);
@@ -741,7 +795,7 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs,
*/
subblksperindir = blksperindir / NINDIR(fs);
for (lbn++, level--, i = 0; i < last; i++) {
- error = indiracct(snapvp, cancelvp, level, bap[i], lbn,
+ error = indiracct_ufs1(snapvp, cancelvp, level, bap[i], lbn,
rlbn, remblks, subblksperindir, fs, acctfunc, expungetype);
if (error)
goto out;
@@ -758,33 +812,287 @@ out:
* Do both snap accounting and map accounting.
*/
static int
-fullacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
+fullacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype)
+ struct vnode *vp;
+ ufs1_daddr_t *oldblkp, *lastblkp;
+ struct fs *fs;
+ ufs_lbn_t lblkno;
+ int exptype; /* BLK_SNAP or BLK_NOCOPY */
+{
+ int error;
+
+ if ((error = snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype)))
+ return (error);
+ return (mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype));
+}
+
+/*
+ * Identify a set of blocks allocated in a snapshot inode.
+ */
+static int
+snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
struct vnode *vp;
- ufs_daddr_t *oldblkp, *lastblkp;
+ ufs1_daddr_t *oldblkp, *lastblkp;
struct fs *fs;
- ufs_daddr_t lblkno;
+ ufs_lbn_t lblkno;
int expungetype; /* BLK_SNAP or BLK_NOCOPY */
{
+ struct inode *ip = VTOI(vp);
+ ufs1_daddr_t blkno, *blkp;
+ ufs_lbn_t lbn;
+ struct buf *ibp;
+ int error;
+
+ for ( ; oldblkp < lastblkp; oldblkp++) {
+ blkno = *oldblkp;
+ if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP)
+ continue;
+ lbn = fragstoblks(fs, blkno);
+ if (lbn < NDADDR) {
+ blkp = &ip->i_din1->di_db[lbn];
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ } else {
+ error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn),
+ fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
+ if (error)
+ return (error);
+ blkp = &((ufs1_daddr_t *)(ibp->b_data))
+ [(lbn - NDADDR) % NINDIR(fs)];
+ }
+ /*
+ * If we are expunging a snapshot vnode and we
+ * find a block marked BLK_NOCOPY, then it is
+ * one that has been allocated to this snapshot after
+ * we took our current snapshot and can be ignored.
+ */
+ if (expungetype == BLK_SNAP && *blkp == BLK_NOCOPY) {
+ if (lbn >= NDADDR)
+ brelse(ibp);
+ } else {
+ if (*blkp != 0)
+ panic("snapacct: bad block");
+ *blkp = expungetype;
+ if (lbn >= NDADDR)
+ bdwrite(ibp);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Account for a set of blocks allocated in a snapshot inode.
+ */
+static int
+mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
+ struct vnode *vp;
+ ufs1_daddr_t *oldblkp, *lastblkp;
+ struct fs *fs;
+ ufs_lbn_t lblkno;
+ int expungetype;
+{
+ ufs1_daddr_t blkno;
+ ino_t inum;
+
+ inum = VTOI(vp)->i_number;
+ for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) {
+ blkno = *oldblkp;
+ if (blkno == 0 || blkno == BLK_NOCOPY)
+ continue;
+ if (blkno == BLK_SNAP)
+ blkno = blkstofrags(fs, lblkno);
+ ffs_blkfree(fs, vp, blkno, fs->fs_bsize, inum);
+ }
+ return (0);
+}
+
+/*
+ * Before expunging a snapshot inode, note all the
+ * blocks that it claims with BLK_SNAP so that fsck will
+ * be able to account for those blocks properly and so
+ * that this snapshot knows that it need not copy them
+ * if the other snapshot holding them is freed. This code
+ * is reproduced once each for UFS1 and UFS2.
+ */
+static int
+expunge_ufs2(snapvp, cancelip, fs, acctfunc, expungetype)
+ struct vnode *snapvp;
+ struct inode *cancelip;
+ struct fs *fs;
+ int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+ int expungetype;
+{
+ int i, error, indiroff;
+ ufs_lbn_t lbn, rlbn;
+ ufs2_daddr_t len, blkno, numblks, blksperindir;
+ struct ufs2_dinode *dip;
+ struct thread *td = curthread;
+ struct buf *bp;
+
+ numblks = howmany(cancelip->i_size, fs->fs_bsize);
+ if ((error = (*acctfunc)(snapvp, &cancelip->i_din2->di_db[0],
+ &cancelip->i_din2->di_ib[NIADDR], fs, 0, expungetype)))
+ return (error);
+ blksperindir = 1;
+ lbn = -NDADDR;
+ len = numblks - NDADDR;
+ rlbn = NDADDR;
+ for (i = 0; len > 0 && i < NIADDR; i++) {
+ error = indiracct_ufs2(snapvp, ITOV(cancelip), i,
+ cancelip->i_din2->di_ib[i], lbn, rlbn, len,
+ blksperindir, fs, acctfunc, expungetype);
+ if (error)
+ return (error);
+ blksperindir *= NINDIR(fs);
+ lbn -= blksperindir + 1;
+ len -= blksperindir;
+ rlbn += blksperindir;
+ }
+ /*
+ * Prepare to expunge the inode. If its inode block has not
+ * yet been copied, then allocate and fill the copy.
+ */
+ lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number));
+ blkno = 0;
+ if (lbn < NDADDR) {
+ blkno = cancelip->i_din2->di_db[lbn];
+ } else {
+ td->td_proc->p_flag |= P_COWINPROGRESS;
+ error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn),
+ fs->fs_bsize, KERNCRED, B_METAONLY, &bp);
+ td->td_proc->p_flag &= ~P_COWINPROGRESS;
+ if (error)
+ return (error);
+ indiroff = (lbn - NDADDR) % NINDIR(fs);
+ blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff];
+ bqrelse(bp);
+ }
+ error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn),
+ fs->fs_bsize, KERNCRED, 0, &bp);
+ if (error)
+ return (error);
+ if (blkno == 0 && (error = readblock(bp, lbn)))
+ return (error);
+ /*
+ * Set a snapshot inode to be a zero length file, regular files
+ * to be completely unallocated.
+ */
+ dip = (struct ufs2_dinode *)bp->b_data +
+ ino_to_fsbo(fs, cancelip->i_number);
+ if (expungetype == BLK_NOCOPY)
+ dip->di_mode = 0;
+ dip->di_size = 0;
+ dip->di_blocks = 0;
+ dip->di_flags &= ~SF_SNAPSHOT;
+ bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs2_daddr_t));
+ bdwrite(bp);
+ return (0);
+}
+
+/*
+ * Descend an indirect block chain for vnode cancelvp accounting for all
+ * its indirect blocks in snapvp.
+ */
+static int
+indiracct_ufs2(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks,
+ blksperindir, fs, acctfunc, expungetype)
+ struct vnode *snapvp;
+ struct vnode *cancelvp;
+ int level;
+ ufs2_daddr_t blkno;
+ ufs_lbn_t lbn;
+ ufs_lbn_t rlbn;
+ ufs_lbn_t remblks;
+ ufs_lbn_t blksperindir;
+ struct fs *fs;
+ int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
+ struct fs *, ufs_lbn_t, int);
+ int expungetype;
+{
+ int error, num, i;
+ ufs_lbn_t subblksperindir;
+ struct indir indirs[NIADDR + 2];
+ ufs2_daddr_t last, *bap;
+ struct buf *bp;
+
+ if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0)
+ return (error);
+ if (lbn != indirs[num - 1 - level].in_lbn || blkno == 0 || num < 2)
+ panic("indiracct: botched params");
+ /*
+ * We have to expand bread here since it will deadlock looking
+ * up the block number for any blocks that are not in the cache.
+ */
+ bp = getblk(cancelvp, lbn, fs->fs_bsize, 0, 0);
+ bp->b_blkno = fsbtodb(fs, blkno);
+ if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0 &&
+ (error = readblock(bp, fragstoblks(fs, blkno)))) {
+ brelse(bp);
+ return (error);
+ }
+ /*
+ * Account for the block pointers in this indirect block.
+ */
+ last = howmany(remblks, blksperindir);
+ if (last > NINDIR(fs))
+ last = NINDIR(fs);
+ MALLOC(bap, ufs2_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK);
+ bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize);
+ bqrelse(bp);
+ error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, rlbn, expungetype);
+ if (error || level == 0)
+ goto out;
+ /*
+ * Account for the block pointers in each of the indirect blocks
+ * in the levels below us.
+ */
+ subblksperindir = blksperindir / NINDIR(fs);
+ for (lbn++, level--, i = 0; i < last; i++) {
+ error = indiracct_ufs2(snapvp, cancelvp, level, bap[i], lbn,
+ rlbn, remblks, subblksperindir, fs, acctfunc, expungetype);
+ if (error)
+ goto out;
+ rlbn += blksperindir;
+ lbn -= blksperindir;
+ remblks -= blksperindir;
+ }
+out:
+ FREE(bap, M_DEVBUF);
+ return (error);
+}
+
+/*
+ * Do both snap accounting and map accounting.
+ */
+static int
+fullacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype)
+ struct vnode *vp;
+ ufs2_daddr_t *oldblkp, *lastblkp;
+ struct fs *fs;
+ ufs_lbn_t lblkno;
+ int exptype; /* BLK_SNAP or BLK_NOCOPY */
+{
int error;
- if ((error = snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)))
+ if ((error = snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype)))
return (error);
- return (mapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype));
+ return (mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype));
}
/*
* Identify a set of blocks allocated in a snapshot inode.
*/
static int
-snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
+snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
struct vnode *vp;
- ufs_daddr_t *oldblkp, *lastblkp;
+ ufs2_daddr_t *oldblkp, *lastblkp;
struct fs *fs;
- ufs_daddr_t lblkno;
+ ufs_lbn_t lblkno;
int expungetype; /* BLK_SNAP or BLK_NOCOPY */
{
struct inode *ip = VTOI(vp);
- ufs_daddr_t lbn, blkno, *blkp;
+ ufs2_daddr_t blkno, *blkp;
+ ufs_lbn_t lbn;
struct buf *ibp;
int error;
@@ -794,14 +1102,14 @@ snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
continue;
lbn = fragstoblks(fs, blkno);
if (lbn < NDADDR) {
- blkp = &ip->i_db[lbn];
+ blkp = &ip->i_din2->di_db[lbn];
ip->i_flag |= IN_CHANGE | IN_UPDATE;
} else {
error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn),
fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
if (error)
return (error);
- blkp = &((ufs_daddr_t *)(ibp->b_data))
+ blkp = &((ufs2_daddr_t *)(ibp->b_data))
[(lbn - NDADDR) % NINDIR(fs)];
}
/*
@@ -828,14 +1136,14 @@ snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
* Account for a set of blocks allocated in a snapshot inode.
*/
static int
-mapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
+mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
struct vnode *vp;
- ufs_daddr_t *oldblkp, *lastblkp;
+ ufs2_daddr_t *oldblkp, *lastblkp;
struct fs *fs;
- ufs_daddr_t lblkno;
+ ufs_lbn_t lblkno;
int expungetype;
{
- ufs_daddr_t blkno;
+ ufs2_daddr_t blkno;
ino_t inum;
inum = VTOI(vp)->i_number;
@@ -901,8 +1209,8 @@ ffs_snapremove(vp)
struct vnode *devvp;
struct buf *ibp;
struct fs *fs;
- ufs_daddr_t blkno, dblk;
- int error, numblks, loc, last;
+ ufs2_daddr_t numblks, blkno, dblk;
+ int error, loc, last;
ip = VTOI(vp);
fs = ip->i_fs;
@@ -927,14 +1235,14 @@ ffs_snapremove(vp)
* snapshots that want them (see ffs_snapblkfree below).
*/
for (blkno = 1; blkno < NDADDR; blkno++) {
- dblk = ip->i_db[blkno];
+ dblk = DIP(ip, i_db[blkno]);
if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
- ip->i_db[blkno] = 0;
+ DIP(ip, i_db[blkno]) = 0;
else if ((dblk == blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize,
ip->i_number))) {
- ip->i_blocks -= btodb(fs->fs_bsize);
- ip->i_db[blkno] = 0;
+ DIP(ip, i_blocks) -= btodb(fs->fs_bsize);
+ DIP(ip, i_db[blkno]) = 0;
}
}
numblks = howmany(ip->i_size, fs->fs_bsize);
@@ -943,17 +1251,32 @@ ffs_snapremove(vp)
fs->fs_bsize, KERNCRED, B_METAONLY, &ibp);
if (error)
continue;
- if ((last = fs->fs_size - blkno) > NINDIR(fs))
+ if (fs->fs_size - blkno > NINDIR(fs))
last = NINDIR(fs);
+ else
+ last = fs->fs_size - blkno;
for (loc = 0; loc < last; loc++) {
- dblk = ((ufs_daddr_t *)(ibp->b_data))[loc];
+ if (ip->i_ump->um_fstype == UFS1) {
+ dblk = ((ufs1_daddr_t *)(ibp->b_data))[loc];
+ if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
+ ((ufs1_daddr_t *)(ibp->b_data))[loc]= 0;
+ else if ((dblk == blkstofrags(fs, blkno) &&
+ ffs_snapblkfree(fs, ip->i_devvp, dblk,
+ fs->fs_bsize, ip->i_number))) {
+ ip->i_din1->di_blocks -=
+ btodb(fs->fs_bsize);
+ ((ufs1_daddr_t *)(ibp->b_data))[loc]= 0;
+ }
+ continue;
+ }
+ dblk = ((ufs2_daddr_t *)(ibp->b_data))[loc];
if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
- ((ufs_daddr_t *)(ibp->b_data))[loc] = 0;
+ ((ufs2_daddr_t *)(ibp->b_data))[loc] = 0;
else if ((dblk == blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk,
fs->fs_bsize, ip->i_number))) {
- ip->i_blocks -= btodb(fs->fs_bsize);
- ((ufs_daddr_t *)(ibp->b_data))[loc] = 0;
+ ip->i_din2->di_blocks -= btodb(fs->fs_bsize);
+ ((ufs2_daddr_t *)(ibp->b_data))[loc] = 0;
}
}
bawrite(ibp);
@@ -962,6 +1285,7 @@ ffs_snapremove(vp)
* Clear snapshot flag and drop reference.
*/
ip->i_flags &= ~SF_SNAPSHOT;
+ DIP(ip, i_flags) = ip->i_flags;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
}
@@ -987,7 +1311,7 @@ int
ffs_snapblkfree(fs, devvp, bno, size, inum)
struct fs *fs;
struct vnode *devvp;
- ufs_daddr_t bno;
+ ufs2_daddr_t bno;
long size;
ino_t inum;
{
@@ -995,7 +1319,8 @@ ffs_snapblkfree(fs, devvp, bno, size, inum)
struct thread *td = curthread;
struct inode *ip;
struct vnode *vp;
- ufs_daddr_t lbn, blkno;
+ ufs_lbn_t lbn;
+ ufs2_daddr_t blkno;
int indiroff = 0, error = 0, claimedblk = 0;
struct snaphead *snaphead;
@@ -1007,7 +1332,7 @@ ffs_snapblkfree(fs, devvp, bno, size, inum)
* Lookup block being written.
*/
if (lbn < NDADDR) {
- blkno = ip->i_db[lbn];
+ blkno = DIP(ip, i_db[lbn]);
} else {
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
td->td_proc->p_flag |= P_COWINPROGRESS;
@@ -1018,46 +1343,52 @@ ffs_snapblkfree(fs, devvp, bno, size, inum)
if (error)
break;
indiroff = (lbn - NDADDR) % NINDIR(fs);
- blkno = ((ufs_daddr_t *)(ibp->b_data))[indiroff];
+ if (ip->i_ump->um_fstype == UFS1)
+ blkno=((ufs1_daddr_t *)(ibp->b_data))[indiroff];
+ else
+ blkno=((ufs2_daddr_t *)(ibp->b_data))[indiroff];
}
/*
* Check to see if block needs to be copied.
*/
- switch (blkno) {
- /*
- * If the snapshot has already copied the block (default),
- * or does not care about the block, it is not needed.
- */
- default:
- case BLK_NOCOPY:
- if (lbn >= NDADDR)
- bqrelse(ibp);
- continue;
- /*
- * No previous snapshot claimed the block, so it will be
- * freed and become a BLK_NOCOPY (don't care) for us.
- */
- case BLK_SNAP:
+ if (blkno == 0) {
+ /*
+ * A block that we map is being freed. If it has not
+ * been claimed yet, we will claim or copy it (below).
+ */
+ claimedblk = 1;
+ } else if (blkno == BLK_SNAP) {
+ /*
+ * No previous snapshot claimed the block,
+ * so it will be * freed and become a BLK_NOCOPY
+ * (don't care) for us.
+ */
if (claimedblk)
panic("snapblkfree: inconsistent block type");
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (lbn < NDADDR) {
- ip->i_db[lbn] = BLK_NOCOPY;
+ DIP(ip, i_db[lbn]) = BLK_NOCOPY;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ } else if (ip->i_ump->um_fstype == UFS1) {
+ ((ufs1_daddr_t *)(ibp->b_data))[indiroff] =
+ BLK_NOCOPY;
+ bdwrite(ibp);
} else {
- ((ufs_daddr_t *)(ibp->b_data))[indiroff] =
+ ((ufs2_daddr_t *)(ibp->b_data))[indiroff] =
BLK_NOCOPY;
bdwrite(ibp);
}
VOP_UNLOCK(vp, 0, td);
continue;
- /*
- * A block that we map is being freed. If it has not been
- * claimed yet, we will claim or copy it (below).
- */
- case 0:
- claimedblk = 1;
- break;
+ } else /* BLK_NOCOPY or default */ {
+ /*
+ * If the snapshot has already copied the block
+ * (default), or does not care about the block,
+ * it is not needed.
+ */
+ if (lbn >= NDADDR)
+ bqrelse(ibp);
+ continue;
}
/*
* If this is a full size block, we will just grab it
@@ -1069,18 +1400,21 @@ ffs_snapblkfree(fs, devvp, bno, size, inum)
if (size == fs->fs_bsize) {
#ifdef DEBUG
if (snapdebug)
- printf("%s %d lbn %d from inum %d\n",
- "Grabonremove: snapino", ip->i_number, lbn,
- inum);
+ printf("%s %d lbn %lld from inum %d\n",
+ "Grabonremove: snapino", ip->i_number,
+ (intmax_t)lbn, inum);
#endif
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (lbn < NDADDR) {
- ip->i_db[lbn] = bno;
+ DIP(ip, i_db[lbn]) = bno;
+ } else if (ip->i_ump->um_fstype == UFS1) {
+ ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = bno;
+ bdwrite(ibp);
} else {
- ((ufs_daddr_t *)(ibp->b_data))[indiroff] = bno;
+ ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = bno;
bdwrite(ibp);
}
- ip->i_blocks += btodb(size);
+ DIP(ip, i_blocks) += btodb(size);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
VOP_UNLOCK(vp, 0, td);
return (1);
@@ -1103,10 +1437,10 @@ ffs_snapblkfree(fs, devvp, bno, size, inum)
}
#ifdef DEBUG
if (snapdebug)
- printf(
-"Copyonremove: snapino %lu lbn %ld for inum %lu size %ld to blkno %lld\n",
- (unsigned long)ip->i_number, (long)lbn,
- (unsigned long)inum, size, (long long)cbp->b_blkno);
+ printf("%s%d lbn %lld %s %d size %ld to blkno %lld\n",
+ "Copyonremove: snapino ", ip->i_number,
+ (intmax_t)lbn, "for inum", inum, size,
+ (intmax_t)cbp->b_blkno);
#endif
/*
* If we have already read the old block contents, then
@@ -1245,7 +1579,7 @@ ffs_copyonwrite(devvp, bp)
struct fs *fs;
struct inode *ip;
struct vnode *vp;
- ufs_daddr_t lbn, blkno;
+ ufs2_daddr_t lbn, blkno;
int indiroff, error = 0;
fs = TAILQ_FIRST(&devvp->v_rdev->si_snapshots)->i_fs;
@@ -1273,7 +1607,7 @@ ffs_copyonwrite(devvp, bp)
retry:
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (lbn < NDADDR) {
- blkno = ip->i_db[lbn];
+ blkno = DIP(ip, i_db[lbn]);
} else {
td->td_proc->p_flag |= P_COWINPROGRESS;
error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn),
@@ -1287,7 +1621,10 @@ retry:
goto retry;
}
indiroff = (lbn - NDADDR) % NINDIR(fs);
- blkno = ((ufs_daddr_t *)(ibp->b_data))[indiroff];
+ if (ip->i_ump->um_fstype == UFS1)
+ blkno=((ufs1_daddr_t *)(ibp->b_data))[indiroff];
+ else
+ blkno=((ufs2_daddr_t *)(ibp->b_data))[indiroff];
bqrelse(ibp);
}
#ifdef DIAGNOSTIC
@@ -1316,14 +1653,14 @@ retry:
}
#ifdef DEBUG
if (snapdebug) {
- printf("Copyonwrite: snapino %d lbn %d for ",
- ip->i_number, lbn);
+ printf("Copyonwrite: snapino %d lbn %lld for ",
+ ip->i_number, (intmax_t)lbn);
if (bp->b_vp == devvp)
printf("fs metadata");
else
printf("inum %d", VTOI(bp->b_vp)->i_number);
printf(" lblkno %lld to blkno %lld\n",
- (long long)bp->b_lblkno, (long long)cbp->b_blkno);
+ (intmax_t)bp->b_lblkno, (intmax_t)cbp->b_blkno);
}
#endif
/*
@@ -1379,7 +1716,7 @@ retry:
static int
readblock(bp, lbn)
struct buf *bp;
- daddr_t lbn;
+ ufs2_daddr_t lbn;
{
struct uio auio;
struct iovec aiov;
OpenPOWER on IntegriCloud