Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext2: fix fs corruption when trying to remove a non-empty directory with IO error

We got issue as follows:
[home]# mount /dev/sdd test
[home]# cd test
[test]# ls
dir1 lost+found
[test]# rmdir dir1
ext2_empty_dir: inject fault
[test]# ls
lost+found
[test]# cd ..
[home]# umount test
[home]# fsck.ext2 -fn /dev/sdd
e2fsck 1.42.9 (28-Dec-2013)
Pass 1: Checking inodes, blocks, and sizes
Inode 4065, i_size is 0, should be 1024. Fix? no

Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Unconnected directory inode 4065 (/???)
Connect to /lost+found? no

'..' in ... (4065) is / (2), should be <The NULL inode> (0).
Fix? no

Pass 4: Checking reference counts
Inode 2 ref count is 3, should be 4. Fix? no

Inode 4065 ref count is 2, should be 3. Fix? no

Pass 5: Checking group summary information

/dev/sdd: ********** WARNING: Filesystem still has errors **********

/dev/sdd: 14/128016 files (0.0% non-contiguous), 18477/512000 blocks

Reason is same with commit 7aab5c84a0f6. We can't assume directory
is empty when read directory entry failed.

Link: https://lore.kernel.org/r/20220615090010.1544152-1-yebin10@huawei.com
Signed-off-by: Ye Bin <yebin10@huawei.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Ye Bin and committed by
Jan Kara
27cfa258 b13baccc

+3 -6
+3 -6
fs/ext2/dir.c
··· 672 672 void *page_addr = NULL; 673 673 struct page *page = NULL; 674 674 unsigned long i, npages = dir_pages(inode); 675 - int dir_has_error = 0; 676 675 677 676 for (i = 0; i < npages; i++) { 678 677 char *kaddr; 679 678 ext2_dirent * de; 680 - page = ext2_get_page(inode, i, dir_has_error, &page_addr); 679 + page = ext2_get_page(inode, i, 0, &page_addr); 681 680 682 - if (IS_ERR(page)) { 683 - dir_has_error = 1; 684 - continue; 685 - } 681 + if (IS_ERR(page)) 682 + goto not_empty; 686 683 687 684 kaddr = page_addr; 688 685 de = (ext2_dirent *)kaddr;