20
20
#include <linux/delay.h>
21
21
#include <linux/iversion.h>
22
22
#include <linux/fileattr.h>
23
+ #include <linux/uuid.h>
23
24
#include "ext4_jbd2.h"
24
25
#include "ext4.h"
25
26
#include <linux/fsmap.h>
@@ -41,6 +42,15 @@ static void ext4_sb_setlabel(struct ext4_super_block *es, const void *arg)
41
42
memcpy (es -> s_volume_name , (char * )arg , EXT4_LABEL_MAX );
42
43
}
43
44
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
+
44
54
static
45
55
int ext4_update_primary_sb (struct super_block * sb , handle_t * handle ,
46
56
ext4_update_sb_callback func ,
@@ -1133,6 +1143,73 @@ static int ext4_ioctl_getlabel(struct ext4_sb_info *sbi, char __user *user_label
1133
1143
return 0 ;
1134
1144
}
1135
1145
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
+
1136
1213
static long __ext4_ioctl (struct file * filp , unsigned int cmd , unsigned long arg )
1137
1214
{
1138
1215
struct inode * inode = file_inode (filp );
@@ -1515,6 +1592,10 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1515
1592
return ext4_ioctl_setlabel (filp ,
1516
1593
(const void __user * )arg );
1517
1594
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 );
1518
1599
default :
1519
1600
return - ENOTTY ;
1520
1601
}
@@ -1592,6 +1673,8 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1592
1673
case EXT4_IOC_CHECKPOINT :
1593
1674
case FS_IOC_GETFSLABEL :
1594
1675
case FS_IOC_SETFSLABEL :
1676
+ case EXT4_IOC_GETFSUUID :
1677
+ case EXT4_IOC_SETFSUUID :
1595
1678
break ;
1596
1679
default :
1597
1680
return - ENOIOCTLCMD ;
0 commit comments