diff options
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 2 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_inode.c | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 2 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 11 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_subr.c | 47 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 2 |
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; |