diff --git a/sys/fs/ext2fs/ext2_extern.h b/fs/ext2fs/ext2_extern.h --- a/sys/fs/ext2fs/ext2_extern.h +++ b/fs/ext2fs/ext2_extern.h @@ -66,7 +66,7 @@ int ext4_bmapext(struct vnode *, int32_t, int64_t *, int *, int *); int ext2_bmap_seekdata(struct vnode *, off_t *); void ext2_clusteracct(struct m_ext2fs *, char *, int, e4fs_daddr_t, int); -void ext2_dirbad(struct inode *ip, doff_t offset, char *how); +void ext2_dirbad(struct inode *ip, doff_t offset, char *how, bool do_panic); int ext2_ei2i(struct ext2fs_dinode *, struct inode *); int ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *); int ext2_i2ei(struct inode *, struct ext2fs_dinode *); diff --git a/sys/fs/ext2fs/ext2_lookup.c b/fs/ext2fs/ext2_lookup.c --- a/sys/fs/ext2fs/ext2_lookup.c +++ b/fs/ext2fs/ext2_lookup.c @@ -538,9 +538,9 @@ */ if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen) > dp->i_size) { - ext2_dirbad(dp, i_offset, "i_size too small"); - dp->i_size = entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen); - dp->i_flag |= IN_CHANGE | IN_UPDATE; + ext2_dirbad(dp, i_offset, "i_size too small", false); + brelse(bp); + return (EIO); } brelse(bp); @@ -726,7 +726,7 @@ if (ext2_check_direntry(vdp, ep, offset)) { int i; - ext2_dirbad(ip, *offp, "mangled entry"); + ext2_dirbad(ip, *offp, "mangled entry", false); i = bsize - (offset & (bsize - 1)); *offp += i; offset += i; @@ -797,18 +797,18 @@ } void -ext2_dirbad(struct inode *ip, doff_t offset, char *how) +ext2_dirbad(struct inode *ip, doff_t offset, char *how, bool do_panic) { struct mount *mp; mp = ITOV(ip)->v_mount; - if ((mp->mnt_flag & MNT_RDONLY) == 0) + if (do_panic && (mp->mnt_flag & MNT_RDONLY) == 0) panic("ext2_dirbad: %s: bad dir ino %ju at offset %ld: %s\n", mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, (long)offset, how); - else - SDT_PROBE4(ext2fs, , trace, ext2_dirbad_error, - mp->mnt_stat.f_mntonname, ip->i_number, offset, how); + + SDT_PROBE4(ext2fs, , trace, ext2_dirbad_error, + mp->mnt_stat.f_mntonname, ip->i_number, offset, how); } /* diff --git a/sys/fs/ext2fs/ext2_vnops.c b/fs/ext2fs/ext2_vnops.c --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/fs/ext2fs/ext2_vnops.c @@ -1088,8 +1088,14 @@ if (namlen != 2 || dirbuf->dotdot_name[0] != '.' || dirbuf->dotdot_name[1] != '.') { + /* + * The filesystem is in corrupted state, + * need to run fsck to fix mangled dir + * and remove unneeded directory entry + * from new parent. + */ ext2_dirbad(xp, (doff_t)12, - "rename: mangled dir"); + "rename: mangled dir", true); } else { dirbuf->dotdot_ino = htole32(newparent); /*