Commit 84e21e3f authored by Zhang Yi's avatar Zhang Yi Committed by Theodore Ts'o
Browse files

ext4: do not check fast symlink during orphan recovery



Commit '5f920d5d ("ext4: verify fast symlink length")' causes the
generic/475 test to fail during orphan cleanup of zero-length symlinks.

  generic/475  84s ... _check_generic_filesystem: filesystem on /dev/vde is inconsistent

The fsck reports are provided below:

  Deleted inode 9686 has zero dtime.
  Deleted inode 158230 has zero dtime.
  ...
  Inode bitmap differences:  -9686 -158230
  Orphan file (inode 12) block 13 is not clean.
  Failed to initialize orphan file.

In ext4_symlink(), a newly created symlink can be added to the orphan
list due to ENOSPC. Its data has not been initialized, and its size is
zero. Therefore, we need to disregard the length check of the symbolic
link when cleaning up orphan inodes. Instead, we should ensure that the
nlink count is zero.

Fixes: 5f920d5d ("ext4: verify fast symlink length")
Signed-off-by: default avatarZhang Yi <yi.zhang@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260131091156.1733648-1-yi.zhang@huaweicloud.com


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
parent 82c4f23d
Loading
Loading
Loading
Loading
+29 −11
Original line number Diff line number Diff line
@@ -5401,6 +5401,23 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
			inode->i_op = &ext4_encrypted_symlink_inode_operations;
		} else if (ext4_inode_is_fast_symlink(inode)) {
			inode->i_op = &ext4_fast_symlink_inode_operations;

			/*
			 * Orphan cleanup can see inodes with i_size == 0
			 * and i_data uninitialized. Skip size checks in
			 * that case. This is safe because the first thing
			 * ext4_evict_inode() does for fast symlinks is
			 * clearing of i_data and i_size.
			 */
			if ((EXT4_SB(sb)->s_mount_state & EXT4_ORPHAN_FS)) {
				if (inode->i_nlink != 0) {
					ext4_error_inode(inode, function, line, 0,
						"invalid orphan symlink nlink %d",
						inode->i_nlink);
					ret = -EFSCORRUPTED;
					goto bad_inode;
				}
			} else {
				if (inode->i_size == 0 ||
				    inode->i_size >= sizeof(ei->i_data) ||
				    strnlen((char *)ei->i_data, inode->i_size + 1) !=
@@ -5413,6 +5430,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
				}
				inode_set_cached_link(inode, (char *)ei->i_data,
						      inode->i_size);
			}
		} else {
			inode->i_op = &ext4_symlink_inode_operations;
		}