Re: [bug report] tune2fs: filesystem inconsistency occurs by concurrent write

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2023/7/5 3:33, Theodore Ts'o wrote:

I have written the ioctl for EXT4_IOC_SET_ERROR_BEHAVIOR according to your
instructions and verified that it can indeed modify the data on the disk.

However, I realized some problems. If we use the ioctl method to modify the
data, it would require multiple ioctls in user space to modify the superblock.
If one ioctl successfully modifies the superblock data, but another ioctl
fails, the atomicity of the superblock cannot be guaranteed. This is just
within one user space process, not to mention the scenario of multiple user
space processes calling ioctls concurrently. Additionally, multiple ioctls
modifying the superblock may be placed in multiple transactions, which further
compromises atomicity.

Writing the entire superblock buffer_head to disk can ensure atomicity.
However, these data need to be converted to ext4_sb_info. Otherwise, during
unmount, the data in memory will overwrite the data on the disk.
(Modifying the values in ext4_sb_info can potentially introduce unexpected
issues, just like the problem thata arises when setting the UUID without
checking ext4_has_feature_csum_seed.)

So the better approach is to have multiple new ioctl's for each
superblock field (or set of fields) that you might want modify.  We
have some of these already --- for example, EXT4_IOC_SETFSUUID and
FS_IOC_SETFSLABEL.  For tune2fs, all of additional ioctls for making
configuration changes while the file system is mounted are:

    * EXT4_IOC_SET_FEATURES
	- for tune2fs -O...
    * EXT4_IOC_CLEAR_FEATURES
	- for tune2fs -O^...
    * EXT4_IOC_SET_ERROR_BEHAVIOR
	- for tune2fs -e
    * EXT4_IOC_SET_DEFAULT_MOUNT_FLAGS
         - for tune2fs -o
    * EXT4_IOC_SET_DEFAULT_MOUNT_OPTS
         - for tune2fs -E mount_opts=XXX
    * EXT4_IOC_SET_FSCK_POLICY
	- for tune2fs -[cCiT]
    * EXT4_IOC_SET_RESERVED_ALLOC
	- for tune2fs -[ugm]

diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 331859511f80..d598e1975786 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -51,6 +51,11 @@ static void ext4_sb_setuuid(struct ext4_super_block *es, const void *arg)
 	memcpy(es->s_uuid, (__u8 *)arg, UUID_SIZE);
 }

+static void ext4_sb_set_error_behavior(struct ext4_super_block *es, const void *arg)
+{
+	es->s_errors = cpu_to_le16(*(__u16 *)arg);
+}
+
 static
 int ext4_update_primary_sb(struct super_block *sb, handle_t *handle,
 			   ext4_update_sb_callback func,
@@ -1220,6 +1225,32 @@ static int ext4_ioctl_setuuid(struct file *filp,
 	return ret;
 }

+static int ext4_ioctl_set_error_behavior(struct file *filp,
+			const __u16 __user *uerror_behavior)
+{
+	int ret = 0;
+	struct super_block *sb = file_inode(filp)->i_sb;
+	__u16 error_behavior;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+ if (copy_from_user(&error_behavior, uerror_behavior, sizeof(error_behavior)))
+		return -EFAULT;
+
+ if (error_behavior < EXT4_ERRORS_CONTINUE || error_behavior > EXT4_ERRORS_PANIC)
+		return -EINVAL;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;
+
+ ret = ext4_update_superblocks_fn(sb, ext4_sb_set_error_behavior, &error_behavior);
+	mnt_drop_write_file(filp);
+
+	return ret;
+}
+
static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct inode *inode = file_inode(filp);
@@ -1607,6 +1638,8 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return ext4_ioctl_getuuid(EXT4_SB(sb), (void __user *)arg);
 	case EXT4_IOC_SETFSUUID:
 		return ext4_ioctl_setuuid(filp, (const void __user *)arg);
+	case EXT4_IOC_SET_ERROR_BEHAVIOR:
+		return ext4_ioctl_set_error_behavior(filp, (const void __user *)arg);
 	default:
 		return -ENOTTY;
 	}
diff --git a/include/uapi/linux/ext4.h b/include/uapi/linux/ext4.h
index 1c4c2dd29112..68329d51a8a7 100644
--- a/include/uapi/linux/ext4.h
+++ b/include/uapi/linux/ext4.h
@@ -33,6 +33,7 @@
 #define EXT4_IOC_CHECKPOINT		_IOW('f', 43, __u32)
 #define EXT4_IOC_GETFSUUID		_IOR('f', 44, struct fsuuid)
 #define EXT4_IOC_SETFSUUID		_IOW('f', 44, struct fsuuid)
+#define EXT4_IOC_SET_ERROR_BEHAVIOR	_IOW('f', 45, __u16)

 #define EXT4_IOC_SHUTDOWN _IOR('X', 125, __u32)



Thanks,
 - bin.




[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux