Explicitly initialize rather than reading newly allocated UFS inodes.
The function ffs_vgetf() is used to find or load UFS inodes into a vnode. It first looks up the inode and if found in the cache its vnode is returned. If it is not already in the cache, a new vnode is allocated and its associated inode read in from the disk. The read is done even for inodes that are being initially created. The contents for the inode on the disk are assumed to be empty. If the on-disk contents had been corrupted either due to a hardware glitch or an agent deliberately trying to exploit the system, the UFS code could panic from the unexpected partially-allocated inode. Rather then having fsck_ffs(8) verify that all unallocated inodes are properly empty, it is easier and quicker to add a flag to ffs_vgetf() to indicate that the request is for a newly allocated inode. When set, the disk read is skipped and the inode is set to its expected empty (zero'ed out) initial state. As a side benefit, an unneeded disk I/O is avoided. Reported by: Peter Holm Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
30f6269155
commit
6b9d4fbb7f
@ -1159,7 +1159,7 @@ ffs_valloc(struct vnode *pvp,
|
||||
* return the error.
|
||||
*/
|
||||
if ((error = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp,
|
||||
FFSV_FORCEINSMQ | FFSV_REPLACE)) != 0) {
|
||||
FFSV_FORCEINSMQ | FFSV_REPLACE | FFSV_NEWINODE)) != 0) {
|
||||
ffs_vfree(pvp, ino, mode);
|
||||
return (error);
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ int ffs_breadz(struct ufsmount *, struct vnode *, daddr_t, daddr_t, int,
|
||||
doomed */
|
||||
#define FFSV_FORCEINODEDEP 0x0008 /* Force allocation of inodedep, ignore
|
||||
MNT_SOFTDEP */
|
||||
#define FFSV_NEWINODE 0x0010 /* Newly allocated inode */
|
||||
|
||||
/*
|
||||
* Flags to ffs_reload
|
||||
|
@ -1928,40 +1928,48 @@ ffs_vgetf(struct mount *mp,
|
||||
MPASS((ffs_flags & FFSV_REPLACE) == 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read in the disk contents for the inode, copy into the inode. */
|
||||
dbn = fsbtodb(fs, ino_to_fsba(fs, ino));
|
||||
error = ffs_breadz(ump, ump->um_devvp, dbn, dbn, (int)fs->fs_bsize,
|
||||
NULL, NULL, 0, NOCRED, 0, NULL, &bp);
|
||||
if (error != 0) {
|
||||
/*
|
||||
* The inode does not contain anything useful, so it would
|
||||
* be misleading to leave it on its hash chain. With mode
|
||||
* still zero, it will be unlinked and returned to the free
|
||||
* list by vput().
|
||||
*/
|
||||
vgone(vp);
|
||||
vput(vp);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
if (I_IS_UFS1(ip))
|
||||
ip->i_din1 = uma_zalloc(uma_ufs1, M_WAITOK);
|
||||
else
|
||||
ip->i_din2 = uma_zalloc(uma_ufs2, M_WAITOK);
|
||||
if ((error = ffs_load_inode(bp, ip, fs, ino)) != 0) {
|
||||
|
||||
if ((ffs_flags & FFSV_NEWINODE) != 0) {
|
||||
/* New inode, just zero out its contents. */
|
||||
if (I_IS_UFS1(ip))
|
||||
memset(ip->i_din1, 0, sizeof(struct ufs1_dinode));
|
||||
else
|
||||
memset(ip->i_din2, 0, sizeof(struct ufs2_dinode));
|
||||
} else {
|
||||
/* Read the disk contents for the inode, copy into the inode. */
|
||||
dbn = fsbtodb(fs, ino_to_fsba(fs, ino));
|
||||
error = ffs_breadz(ump, ump->um_devvp, dbn, dbn,
|
||||
(int)fs->fs_bsize, NULL, NULL, 0, NOCRED, 0, NULL, &bp);
|
||||
if (error != 0) {
|
||||
/*
|
||||
* The inode does not contain anything useful, so it
|
||||
* would be misleading to leave it on its hash chain.
|
||||
* With mode still zero, it will be unlinked and
|
||||
* returned to the free list by vput().
|
||||
*/
|
||||
vgone(vp);
|
||||
vput(vp);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
if ((error = ffs_load_inode(bp, ip, fs, ino)) != 0) {
|
||||
bqrelse(bp);
|
||||
vgone(vp);
|
||||
vput(vp);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
bqrelse(bp);
|
||||
vgone(vp);
|
||||
vput(vp);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
if (DOINGSOFTDEP(vp) && (!fs->fs_ronly ||
|
||||
(ffs_flags & FFSV_FORCEINODEDEP) != 0))
|
||||
softdep_load_inodeblock(ip);
|
||||
else
|
||||
ip->i_effnlink = ip->i_nlink;
|
||||
bqrelse(bp);
|
||||
|
||||
/*
|
||||
* Initialize the vnode from the inode, check for aliases.
|
||||
|
Loading…
Reference in New Issue
Block a user