2020#include <linux/delay.h>
2121#include <linux/iversion.h>
2222#include <linux/fileattr.h>
23+ #include <linux/uuid.h>
2324#include "ext4_jbd2.h"
2425#include "ext4.h"
2526#include <linux/fsmap.h>
@@ -41,6 +42,15 @@ static void ext4_sb_setlabel(struct ext4_super_block *es, const void *arg)
4142 memcpy (es -> s_volume_name , (char * )arg , EXT4_LABEL_MAX );
4243}
4344
45+ /*
46+ * Superblock modification callback function for changing file system
47+ * UUID.
48+ */
49+ static void ext4_sb_setuuid (struct ext4_super_block * es , const void * arg )
50+ {
51+ memcpy (es -> s_uuid , (__u8 * )arg , UUID_SIZE );
52+ }
53+
4454static
4555int ext4_update_primary_sb (struct super_block * sb , handle_t * handle ,
4656 ext4_update_sb_callback func ,
@@ -1133,6 +1143,73 @@ static int ext4_ioctl_getlabel(struct ext4_sb_info *sbi, char __user *user_label
11331143 return 0 ;
11341144}
11351145
1146+ static int ext4_ioctl_getuuid (struct ext4_sb_info * sbi ,
1147+ struct fsuuid __user * ufsuuid )
1148+ {
1149+ struct fsuuid fsuuid ;
1150+ __u8 uuid [UUID_SIZE ];
1151+
1152+ if (copy_from_user (& fsuuid , ufsuuid , sizeof (fsuuid )))
1153+ return - EFAULT ;
1154+
1155+ if (fsuuid .fsu_len == 0 ) {
1156+ fsuuid .fsu_len = UUID_SIZE ;
1157+ if (copy_to_user (ufsuuid , & fsuuid , sizeof (fsuuid .fsu_len )))
1158+ return - EFAULT ;
1159+ return - EINVAL ;
1160+ }
1161+
1162+ if (fsuuid .fsu_len != UUID_SIZE || fsuuid .fsu_flags != 0 )
1163+ return - EINVAL ;
1164+
1165+ lock_buffer (sbi -> s_sbh );
1166+ memcpy (uuid , sbi -> s_es -> s_uuid , UUID_SIZE );
1167+ unlock_buffer (sbi -> s_sbh );
1168+
1169+ if (copy_to_user (& ufsuuid -> fsu_uuid [0 ], uuid , UUID_SIZE ))
1170+ return - EFAULT ;
1171+ return 0 ;
1172+ }
1173+
1174+ static int ext4_ioctl_setuuid (struct file * filp ,
1175+ const struct fsuuid __user * ufsuuid )
1176+ {
1177+ int ret = 0 ;
1178+ struct super_block * sb = file_inode (filp )-> i_sb ;
1179+ struct fsuuid fsuuid ;
1180+ __u8 uuid [UUID_SIZE ];
1181+
1182+ if (!capable (CAP_SYS_ADMIN ))
1183+ return - EPERM ;
1184+
1185+ /*
1186+ * If any checksums (group descriptors or metadata) are being used
1187+ * then the checksum seed feature is required to change the UUID.
1188+ */
1189+ if (((ext4_has_feature_gdt_csum (sb ) || ext4_has_metadata_csum (sb ))
1190+ && !ext4_has_feature_csum_seed (sb ))
1191+ || ext4_has_feature_stable_inodes (sb ))
1192+ return - EOPNOTSUPP ;
1193+
1194+ if (copy_from_user (& fsuuid , ufsuuid , sizeof (fsuuid )))
1195+ return - EFAULT ;
1196+
1197+ if (fsuuid .fsu_len != UUID_SIZE || fsuuid .fsu_flags != 0 )
1198+ return - EINVAL ;
1199+
1200+ if (copy_from_user (uuid , & ufsuuid -> fsu_uuid [0 ], UUID_SIZE ))
1201+ return - EFAULT ;
1202+
1203+ ret = mnt_want_write_file (filp );
1204+ if (ret )
1205+ return ret ;
1206+
1207+ ret = ext4_update_superblocks_fn (sb , ext4_sb_setuuid , & uuid );
1208+ mnt_drop_write_file (filp );
1209+
1210+ return ret ;
1211+ }
1212+
11361213static long __ext4_ioctl (struct file * filp , unsigned int cmd , unsigned long arg )
11371214{
11381215 struct inode * inode = file_inode (filp );
@@ -1515,6 +1592,10 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
15151592 return ext4_ioctl_setlabel (filp ,
15161593 (const void __user * )arg );
15171594
1595+ case EXT4_IOC_GETFSUUID :
1596+ return ext4_ioctl_getuuid (EXT4_SB (sb ), (void __user * )arg );
1597+ case EXT4_IOC_SETFSUUID :
1598+ return ext4_ioctl_setuuid (filp , (const void __user * )arg );
15181599 default :
15191600 return - ENOTTY ;
15201601 }
@@ -1592,6 +1673,8 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
15921673 case EXT4_IOC_CHECKPOINT :
15931674 case FS_IOC_GETFSLABEL :
15941675 case FS_IOC_SETFSLABEL :
1676+ case EXT4_IOC_GETFSUUID :
1677+ case EXT4_IOC_SETFSUUID :
15951678 break ;
15961679 default :
15971680 return - ENOIOCTLCMD ;
0 commit comments