Fix directory blocks checksum updating logic.

The checksum updating functions were not called in case of dir index inode splitting
and in case of dir entry removing, when the entry was first in the block.
Fix and move the dir entry adding logic when i_count == 0 to new function.

MFC after:      3 months
This commit is contained in:
Fedor Uporov 2018-08-08 12:07:45 +00:00
parent d0f408fab9
commit 17c7b27f55
2 changed files with 72 additions and 31 deletions

View File

@ -800,7 +800,7 @@ ext2_htree_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry,
cursize = roundup(ip->i_size, blksize);
dirsize = cursize + blksize;
blknum = dirsize / blksize - 1;
ext2_dx_csum_set(ip, (struct ext2fs_direct_2 *)newidxblock);
error = ext2_htree_append_block(dvp, newidxblock,
cnp, blksize);
if (error)

View File

@ -858,6 +858,68 @@ ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
return error_msg == NULL ? 0 : 1;
}
/*
* Insert an entry into the fresh directory block.
* Initialize entry tail if the metadata_csum feature is turned on.
*/
static int
ext2_add_first_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry,
struct componentname *cnp)
{
struct inode *dp;
struct iovec aiov;
struct uio auio;
char* buf = NULL;
int dirblksize, error;
dp = VTOI(dvp);
dirblksize = dp->i_e2fs->e2fs_bsize;
if (dp->i_offset & (dirblksize - 1))
panic("ext2_add_first_entry: bad directory offset");
if (EXT2_HAS_RO_COMPAT_FEATURE(dp->i_e2fs,
EXT2F_ROCOMPAT_METADATA_CKSUM)) {
entry->e2d_reclen = dirblksize - sizeof(struct ext2fs_direct_tail);
buf = malloc(dirblksize, M_TEMP, M_WAITOK);
if (!buf) {
error = ENOMEM;
goto out;
}
memcpy(buf, entry, EXT2_DIR_REC_LEN(entry->e2d_namlen));
ext2_init_dirent_tail(EXT2_DIRENT_TAIL(buf, dirblksize));
ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)buf);
auio.uio_offset = dp->i_offset;
auio.uio_resid = dirblksize;
aiov.iov_len = auio.uio_resid;
aiov.iov_base = (caddr_t)buf;
} else {
entry->e2d_reclen = dirblksize;
auio.uio_offset = dp->i_offset;
auio.uio_resid = EXT2_DIR_REC_LEN(entry->e2d_namlen);
aiov.iov_len = auio.uio_resid;
aiov.iov_base = (caddr_t)entry;
}
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_td = (struct thread *)0;
error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
if (error)
goto out;
dp->i_size = roundup2(dp->i_size, dirblksize);
dp->i_flag |= IN_CHANGE;
out:
free(buf, M_TEMP);
return (error);
}
/*
* Write a directory entry after a call to namei, using the parameters
* that it left in nameidata. The argument ip is the inode which the new
@ -871,7 +933,6 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
{
struct inode *dp;
struct ext2fs_direct_2 newdir;
struct buf *bp;
int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
int error;
@ -911,35 +972,14 @@ ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
}
}
if (dp->i_count == 0) {
/*
* If dp->i_count is 0, then namei could find no
* space in the directory. Here, dp->i_offset will
* be on a directory block boundary and we will write the
* new entry into a fresh block.
*/
if (dp->i_offset & (DIRBLKSIZ - 1))
panic("ext2_direnter: newblk");
newdir.e2d_reclen = DIRBLKSIZ;
bp = getblk(ip->i_devvp, lblkno(dp->i_e2fs, dp->i_offset),
DIRBLKSIZ, 0, 0, 0);
if (!bp)
return (EIO);
memcpy(bp->b_data, &newdir, sizeof(struct ext2fs_direct_2));
ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data);
error = bwrite(bp);
if (error)
return (error);
dp->i_size = roundup2(dp->i_size, DIRBLKSIZ);
dp->i_flag |= IN_CHANGE;
return (0);
}
/*
* If dp->i_count is 0, then namei could find no
* space in the directory. Here, dp->i_offset will
* be on a directory block boundary and we will write the
* new entry into a fresh block.
*/
if (dp->i_count == 0)
return ext2_add_first_entry(dvp, &newdir, cnp);
error = ext2_add_entry(dvp, &newdir);
if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
@ -1071,6 +1111,7 @@ ext2_dirremove(struct vnode *dvp, struct componentname *cnp)
&bp)) != 0)
return (error);
ep->e2d_ino = 0;
ext2_dirent_csum_set(dp, (struct ext2fs_direct_2 *)bp->b_data);
error = bwrite(bp);
dp->i_flag |= IN_CHANGE | IN_UPDATE;
return (error);