aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_extern.h2
-rw-r--r--sys/ufs/ffs/ffs_inode.c1
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c2
-rw-r--r--sys/ufs/ffs/ffs_softdep.c11
-rw-r--r--sys/ufs/ffs/ffs_subr.c47
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c2
6 files changed, 62 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index 16f517d5f12e..f7d95404c046 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -108,6 +108,8 @@ void ffs_sync_snap(struct mount *, int);
int ffs_syncvnode(struct vnode *vp, int waitfor, int flags);
int ffs_truncate(struct vnode *, off_t, int, struct ucred *);
int ffs_update(struct vnode *, int);
+void ffs_update_dinode_ckhash(struct fs *, struct ufs2_dinode *);
+int ffs_verify_dinode_ckhash(struct fs *, struct ufs2_dinode *);
int ffs_valloc(struct vnode *, int, struct ucred *, struct vnode **);
int ffs_vfree(struct vnode *, ino_t, int);
vfs_vget_t ffs_vget;
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index d146d14980c3..bbacaaa59e5f 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -154,6 +154,7 @@ loop:
*/
random_harvest_queue(&(ip->i_din1), sizeof(ip->i_din1), RANDOM_FS_ATIME);
} else {
+ ffs_update_dinode_ckhash(fs, ip->i_din2);
*((struct ufs2_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
/*
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index e230d4b0c6c8..092720a9cbeb 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -1340,6 +1340,8 @@ expunge_ufs2(snapvp, cancelip, fs, acctfunc, expungetype, clearmode)
bzero(&dip->di_db[0], (UFS_NDADDR + UFS_NIADDR) * sizeof(ufs2_daddr_t));
if (clearmode || cancelip->i_effnlink == 0)
dip->di_mode = 0;
+ else
+ ffs_update_dinode_ckhash(fs, dip);
bdwrite(bp);
/*
* Now go through and expunge all the blocks in the file
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index aad19c6014cd..eb093d4bf419 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -6702,6 +6702,7 @@ softdep_journal_freeblocks(ip, cred, length, flags)
*((struct ufs1_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
} else {
+ ffs_update_dinode_ckhash(fs, ip->i_din2);
*((struct ufs2_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
}
@@ -6957,6 +6958,7 @@ softdep_setup_freeblocks(ip, length, flags)
dp2 = ((struct ufs2_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number));
ip->i_din2->di_freelink = dp2->di_freelink;
+ ffs_update_dinode_ckhash(fs, ip->i_din2);
*dp2 = *ip->i_din2;
}
/*
@@ -9752,6 +9754,7 @@ clear_unlinked_inodedep(inodedep)
dip = (struct ufs2_dinode *)bp->b_data +
ino_to_fsbo(fs, pino);
dip->di_freelink = nino;
+ ffs_update_dinode_ckhash(fs, dip);
}
/*
* If the bwrite fails we have no recourse to recover. The
@@ -10392,6 +10395,7 @@ initiate_write_inodeblock_ufs2(inodedep, bp)
inon = TAILQ_NEXT(inodedep, id_unlinked);
dp->di_freelink = inon ? inon->id_ino : 0;
+ ffs_update_dinode_ckhash(fs, dp);
}
/*
* If the bitmap is not yet written, then the allocated
@@ -10553,6 +10557,7 @@ initiate_write_inodeblock_ufs2(inodedep, bp)
#endif /* INVARIANTS */
dp->di_ib[i] = 0;
}
+ ffs_update_dinode_ckhash(fs, dp);
return;
}
/*
@@ -10581,6 +10586,7 @@ initiate_write_inodeblock_ufs2(inodedep, bp)
*/
for (; adp; adp = TAILQ_NEXT(adp, ad_next))
dp->di_ib[adp->ad_offset - UFS_NDADDR] = 0;
+ ffs_update_dinode_ckhash(fs, dp);
}
/*
@@ -11619,8 +11625,11 @@ handle_written_inodeblock(inodedep, bp, flags)
* marked dirty so that its will eventually get written back in
* its correct form.
*/
- if (hadchanges)
+ if (hadchanges) {
+ if (fstype == UFS2)
+ ffs_update_dinode_ckhash(inodedep->id_fs, dp2);
bdirty(bp);
+ }
bufwait:
/*
* If the write did not succeed, we have done all the roll-forward
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
index 64354bbd5383..2891c8d8fe96 100644
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -119,6 +119,7 @@ ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
{
struct ufs1_dinode *dip1;
struct ufs2_dinode *dip2;
+ int error;
if (I_IS_UFS1(ip)) {
dip1 = ip->i_din1;
@@ -142,11 +143,55 @@ ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
ip->i_gen = dip2->di_gen;
ip->i_uid = dip2->di_uid;
ip->i_gid = dip2->di_gid;
- return (0);
+ if ((error = ffs_verify_dinode_ckhash(fs, dip2)) != 0)
+ printf("Inode %jd: check-hash failed\n", (intmax_t)ino);
+ return (error);
}
#endif /* _KERNEL */
/*
+ * Verify an inode check-hash.
+ */
+int
+ffs_verify_dinode_ckhash(struct fs *fs, struct ufs2_dinode *dip)
+{
+ uint32_t save_ckhash;
+
+ /*
+ * Return success if unallocated or we are not doing inode check-hash.
+ */
+ if (dip->di_mode == 0 || (fs->fs_metackhash & CK_INODE) == 0)
+ return (0);
+ /*
+ * Exclude di_ckhash from the crc32 calculation, e.g., always use
+ * a check-hash value of zero when calculating the check-hash.
+ */
+ save_ckhash = dip->di_ckhash;
+ dip->di_ckhash = 0;
+ if (save_ckhash != calculate_crc32c(~0L, (void *)dip, sizeof(*dip)))
+ return (EINVAL);
+ dip->di_ckhash = save_ckhash;
+ return (0);
+}
+
+/*
+ * Update an inode check-hash.
+ */
+void
+ffs_update_dinode_ckhash(struct fs *fs, struct ufs2_dinode *dip)
+{
+
+ if (dip->di_mode == 0 || (fs->fs_metackhash & CK_INODE) == 0)
+ return;
+ /*
+ * Exclude old di_ckhash from the crc32 calculation, e.g., always use
+ * a check-hash value of zero when calculating the new check-hash.
+ */
+ dip->di_ckhash = 0;
+ dip->di_ckhash = calculate_crc32c(~0L, (void *)dip, sizeof(*dip));
+}
+
+/*
* These are the low-level functions that actually read and write
* the superblock and its associated data.
*/
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 7cb81cfa450a..15b208c5c06a 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -817,7 +817,7 @@ ffs_mountfs(devvp, mp, td)
if ((error = ffs_sbget(devvp, &fs, loc, M_UFSMNT, ffs_use_bread)) != 0)
goto out;
/* none of these types of check-hashes are maintained by this kernel */
- fs->fs_metackhash &= ~(CK_INODE | CK_INDIR | CK_DIR);
+ fs->fs_metackhash &= ~(CK_INDIR | CK_DIR);
/* no support for any undefined flags */
fs->fs_flags &= FS_SUPPORTED;
fs->fs_flags &= ~FS_UNCLEAN;