2727#include "fsmap.h"
2828#include <trace/events/ext4.h>
2929
30- typedef void ext4_update_sb_callback (struct ext4_super_block * es ,
31- const void * arg );
30+ typedef void ext4_update_sb_callback (struct ext4_sb_info * sbi ,
31+ struct ext4_super_block * es ,
32+ const void * arg );
3233
3334/*
3435 * Superblock modification callback function for changing file system
3536 * label
3637 */
37- static void ext4_sb_setlabel (struct ext4_super_block * es , const void * arg )
38+ static void ext4_sb_setlabel (struct ext4_sb_info * sbi ,
39+ struct ext4_super_block * es , const void * arg )
3840{
3941 /* Sanity check, this should never happen */
4042 BUILD_BUG_ON (sizeof (es -> s_volume_name ) < EXT4_LABEL_MAX );
@@ -46,7 +48,8 @@ static void ext4_sb_setlabel(struct ext4_super_block *es, const void *arg)
4648 * Superblock modification callback function for changing file system
4749 * UUID.
4850 */
49- static void ext4_sb_setuuid (struct ext4_super_block * es , const void * arg )
51+ static void ext4_sb_setuuid (struct ext4_sb_info * sbi ,
52+ struct ext4_super_block * es , const void * arg )
5053{
5154 memcpy (es -> s_uuid , (__u8 * )arg , UUID_SIZE );
5255}
@@ -71,7 +74,7 @@ int ext4_update_primary_sb(struct super_block *sb, handle_t *handle,
7174 goto out_err ;
7275
7376 lock_buffer (bh );
74- func (es , arg );
77+ func (sbi , es , arg );
7578 ext4_superblock_csum_set (sb );
7679 unlock_buffer (bh );
7780
@@ -149,7 +152,7 @@ static int ext4_update_backup_sb(struct super_block *sb,
149152 unlock_buffer (bh );
150153 goto out_bh ;
151154 }
152- func (es , arg );
155+ func (EXT4_SB ( sb ), es , arg );
153156 if (ext4_has_feature_metadata_csum (sb ))
154157 es -> s_checksum = ext4_superblock_csum (es );
155158 set_buffer_uptodate (bh );
@@ -1230,6 +1233,295 @@ static int ext4_ioctl_setuuid(struct file *filp,
12301233 return ret ;
12311234}
12321235
1236+
1237+ #define TUNE_OPS_SUPPORTED (EXT4_TUNE_FL_ERRORS_BEHAVIOR | \
1238+ EXT4_TUNE_FL_MNT_COUNT | EXT4_TUNE_FL_MAX_MNT_COUNT | \
1239+ EXT4_TUNE_FL_CHECKINTRVAL | EXT4_TUNE_FL_LAST_CHECK_TIME | \
1240+ EXT4_TUNE_FL_RESERVED_BLOCKS | EXT4_TUNE_FL_RESERVED_UID | \
1241+ EXT4_TUNE_FL_RESERVED_GID | EXT4_TUNE_FL_DEFAULT_MNT_OPTS | \
1242+ EXT4_TUNE_FL_DEF_HASH_ALG | EXT4_TUNE_FL_RAID_STRIDE | \
1243+ EXT4_TUNE_FL_RAID_STRIPE_WIDTH | EXT4_TUNE_FL_MOUNT_OPTS | \
1244+ EXT4_TUNE_FL_FEATURES | EXT4_TUNE_FL_EDIT_FEATURES | \
1245+ EXT4_TUNE_FL_FORCE_FSCK | EXT4_TUNE_FL_ENCODING | \
1246+ EXT4_TUNE_FL_ENCODING_FLAGS)
1247+
1248+ #define EXT4_TUNE_SET_COMPAT_SUPP \
1249+ (EXT4_FEATURE_COMPAT_DIR_INDEX | \
1250+ EXT4_FEATURE_COMPAT_STABLE_INODES)
1251+ #define EXT4_TUNE_SET_INCOMPAT_SUPP \
1252+ (EXT4_FEATURE_INCOMPAT_EXTENTS | \
1253+ EXT4_FEATURE_INCOMPAT_EA_INODE | \
1254+ EXT4_FEATURE_INCOMPAT_ENCRYPT | \
1255+ EXT4_FEATURE_INCOMPAT_CSUM_SEED | \
1256+ EXT4_FEATURE_INCOMPAT_LARGEDIR | \
1257+ EXT4_FEATURE_INCOMPAT_CASEFOLD)
1258+ #define EXT4_TUNE_SET_RO_COMPAT_SUPP \
1259+ (EXT4_FEATURE_RO_COMPAT_LARGE_FILE | \
1260+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
1261+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
1262+ EXT4_FEATURE_RO_COMPAT_PROJECT | \
1263+ EXT4_FEATURE_RO_COMPAT_VERITY)
1264+
1265+ #define EXT4_TUNE_CLEAR_COMPAT_SUPP (0)
1266+ #define EXT4_TUNE_CLEAR_INCOMPAT_SUPP (0)
1267+ #define EXT4_TUNE_CLEAR_RO_COMPAT_SUPP (0)
1268+
1269+ #define SB_ENC_SUPP_MASK (SB_ENC_STRICT_MODE_FL | \
1270+ SB_ENC_NO_COMPAT_FALLBACK_FL)
1271+
1272+ static int ext4_ioctl_get_tune_sb (struct ext4_sb_info * sbi ,
1273+ struct ext4_tune_sb_params __user * params )
1274+ {
1275+ struct ext4_tune_sb_params ret ;
1276+ struct ext4_super_block * es = sbi -> s_es ;
1277+
1278+ memset (& ret , 0 , sizeof (ret ));
1279+ ret .set_flags = TUNE_OPS_SUPPORTED ;
1280+ ret .errors_behavior = le16_to_cpu (es -> s_errors );
1281+ ret .mnt_count = le16_to_cpu (es -> s_mnt_count );
1282+ ret .max_mnt_count = le16_to_cpu (es -> s_max_mnt_count );
1283+ ret .checkinterval = le32_to_cpu (es -> s_checkinterval );
1284+ ret .last_check_time = le32_to_cpu (es -> s_lastcheck );
1285+ ret .reserved_blocks = ext4_r_blocks_count (es );
1286+ ret .blocks_count = ext4_blocks_count (es );
1287+ ret .reserved_uid = ext4_get_resuid (es );
1288+ ret .reserved_gid = ext4_get_resgid (es );
1289+ ret .default_mnt_opts = le32_to_cpu (es -> s_default_mount_opts );
1290+ ret .def_hash_alg = es -> s_def_hash_version ;
1291+ ret .raid_stride = le16_to_cpu (es -> s_raid_stride );
1292+ ret .raid_stripe_width = le32_to_cpu (es -> s_raid_stripe_width );
1293+ ret .encoding = le16_to_cpu (es -> s_encoding );
1294+ ret .encoding_flags = le16_to_cpu (es -> s_encoding_flags );
1295+ strscpy_pad (ret .mount_opts , es -> s_mount_opts );
1296+ ret .feature_compat = le32_to_cpu (es -> s_feature_compat );
1297+ ret .feature_incompat = le32_to_cpu (es -> s_feature_incompat );
1298+ ret .feature_ro_compat = le32_to_cpu (es -> s_feature_ro_compat );
1299+ ret .set_feature_compat_mask = EXT4_TUNE_SET_COMPAT_SUPP ;
1300+ ret .set_feature_incompat_mask = EXT4_TUNE_SET_INCOMPAT_SUPP ;
1301+ ret .set_feature_ro_compat_mask = EXT4_TUNE_SET_RO_COMPAT_SUPP ;
1302+ ret .clear_feature_compat_mask = EXT4_TUNE_CLEAR_COMPAT_SUPP ;
1303+ ret .clear_feature_incompat_mask = EXT4_TUNE_CLEAR_INCOMPAT_SUPP ;
1304+ ret .clear_feature_ro_compat_mask = EXT4_TUNE_CLEAR_RO_COMPAT_SUPP ;
1305+ if (copy_to_user (params , & ret , sizeof (ret )))
1306+ return - EFAULT ;
1307+ return 0 ;
1308+ }
1309+
1310+ static void ext4_sb_setparams (struct ext4_sb_info * sbi ,
1311+ struct ext4_super_block * es , const void * arg )
1312+ {
1313+ const struct ext4_tune_sb_params * params = arg ;
1314+
1315+ if (params -> set_flags & EXT4_TUNE_FL_ERRORS_BEHAVIOR )
1316+ es -> s_errors = cpu_to_le16 (params -> errors_behavior );
1317+ if (params -> set_flags & EXT4_TUNE_FL_MNT_COUNT )
1318+ es -> s_mnt_count = cpu_to_le16 (params -> mnt_count );
1319+ if (params -> set_flags & EXT4_TUNE_FL_MAX_MNT_COUNT )
1320+ es -> s_max_mnt_count = cpu_to_le16 (params -> max_mnt_count );
1321+ if (params -> set_flags & EXT4_TUNE_FL_CHECKINTRVAL )
1322+ es -> s_checkinterval = cpu_to_le32 (params -> checkinterval );
1323+ if (params -> set_flags & EXT4_TUNE_FL_LAST_CHECK_TIME )
1324+ es -> s_lastcheck = cpu_to_le32 (params -> last_check_time );
1325+ if (params -> set_flags & EXT4_TUNE_FL_RESERVED_BLOCKS ) {
1326+ ext4_fsblk_t blk = params -> reserved_blocks ;
1327+
1328+ es -> s_r_blocks_count_lo = cpu_to_le32 ((u32 )blk );
1329+ es -> s_r_blocks_count_hi = cpu_to_le32 (blk >> 32 );
1330+ }
1331+ if (params -> set_flags & EXT4_TUNE_FL_RESERVED_UID ) {
1332+ int uid = params -> reserved_uid ;
1333+
1334+ es -> s_def_resuid = cpu_to_le16 (uid & 0xFFFF );
1335+ es -> s_def_resuid_hi = cpu_to_le16 (uid >> 16 );
1336+ }
1337+ if (params -> set_flags & EXT4_TUNE_FL_RESERVED_GID ) {
1338+ int gid = params -> reserved_gid ;
1339+
1340+ es -> s_def_resgid = cpu_to_le16 (gid & 0xFFFF );
1341+ es -> s_def_resgid_hi = cpu_to_le16 (gid >> 16 );
1342+ }
1343+ if (params -> set_flags & EXT4_TUNE_FL_DEFAULT_MNT_OPTS )
1344+ es -> s_default_mount_opts = cpu_to_le32 (params -> default_mnt_opts );
1345+ if (params -> set_flags & EXT4_TUNE_FL_DEF_HASH_ALG )
1346+ es -> s_def_hash_version = params -> def_hash_alg ;
1347+ if (params -> set_flags & EXT4_TUNE_FL_RAID_STRIDE )
1348+ es -> s_raid_stride = cpu_to_le16 (params -> raid_stride );
1349+ if (params -> set_flags & EXT4_TUNE_FL_RAID_STRIPE_WIDTH )
1350+ es -> s_raid_stripe_width =
1351+ cpu_to_le32 (params -> raid_stripe_width );
1352+ if (params -> set_flags & EXT4_TUNE_FL_ENCODING )
1353+ es -> s_encoding = cpu_to_le16 (params -> encoding );
1354+ if (params -> set_flags & EXT4_TUNE_FL_ENCODING_FLAGS )
1355+ es -> s_encoding_flags = cpu_to_le16 (params -> encoding_flags );
1356+ strscpy_pad (es -> s_mount_opts , params -> mount_opts );
1357+ if (params -> set_flags & EXT4_TUNE_FL_EDIT_FEATURES ) {
1358+ es -> s_feature_compat |=
1359+ cpu_to_le32 (params -> set_feature_compat_mask );
1360+ es -> s_feature_incompat |=
1361+ cpu_to_le32 (params -> set_feature_incompat_mask );
1362+ es -> s_feature_ro_compat |=
1363+ cpu_to_le32 (params -> set_feature_ro_compat_mask );
1364+ es -> s_feature_compat &=
1365+ ~cpu_to_le32 (params -> clear_feature_compat_mask );
1366+ es -> s_feature_incompat &=
1367+ ~cpu_to_le32 (params -> clear_feature_incompat_mask );
1368+ es -> s_feature_ro_compat &=
1369+ ~cpu_to_le32 (params -> clear_feature_ro_compat_mask );
1370+ if (params -> set_feature_compat_mask &
1371+ EXT4_FEATURE_COMPAT_DIR_INDEX )
1372+ es -> s_def_hash_version = sbi -> s_def_hash_version ;
1373+ if (params -> set_feature_incompat_mask &
1374+ EXT4_FEATURE_INCOMPAT_CSUM_SEED )
1375+ es -> s_checksum_seed = cpu_to_le32 (sbi -> s_csum_seed );
1376+ }
1377+ if (params -> set_flags & EXT4_TUNE_FL_FORCE_FSCK )
1378+ es -> s_state |= cpu_to_le16 (EXT4_ERROR_FS );
1379+ }
1380+
1381+ static int ext4_ioctl_set_tune_sb (struct file * filp ,
1382+ struct ext4_tune_sb_params __user * in )
1383+ {
1384+ struct ext4_tune_sb_params params ;
1385+ struct super_block * sb = file_inode (filp )-> i_sb ;
1386+ struct ext4_sb_info * sbi = EXT4_SB (sb );
1387+ struct ext4_super_block * es = sbi -> s_es ;
1388+ int enabling_casefold = 0 ;
1389+ int ret ;
1390+
1391+ if (!capable (CAP_SYS_ADMIN ))
1392+ return - EPERM ;
1393+
1394+ if (copy_from_user (& params , in , sizeof (params )))
1395+ return - EFAULT ;
1396+
1397+ if ((params .set_flags & ~TUNE_OPS_SUPPORTED ) != 0 )
1398+ return - EOPNOTSUPP ;
1399+
1400+ if ((params .set_flags & EXT4_TUNE_FL_ERRORS_BEHAVIOR ) &&
1401+ (params .errors_behavior > EXT4_ERRORS_PANIC ))
1402+ return - EINVAL ;
1403+
1404+ if ((params .set_flags & EXT4_TUNE_FL_RESERVED_BLOCKS ) &&
1405+ (params .reserved_blocks > ext4_blocks_count (sbi -> s_es ) / 2 ))
1406+ return - EINVAL ;
1407+ if ((params .set_flags & EXT4_TUNE_FL_DEF_HASH_ALG ) &&
1408+ ((params .def_hash_alg > DX_HASH_LAST ) ||
1409+ (params .def_hash_alg == DX_HASH_SIPHASH )))
1410+ return - EINVAL ;
1411+ if ((params .set_flags & EXT4_TUNE_FL_FEATURES ) &&
1412+ (params .set_flags & EXT4_TUNE_FL_EDIT_FEATURES ))
1413+ return - EINVAL ;
1414+
1415+ if (params .set_flags & EXT4_TUNE_FL_FEATURES ) {
1416+ params .set_feature_compat_mask =
1417+ params .feature_compat &
1418+ ~le32_to_cpu (es -> s_feature_compat );
1419+ params .set_feature_incompat_mask =
1420+ params .feature_incompat &
1421+ ~le32_to_cpu (es -> s_feature_incompat );
1422+ params .set_feature_ro_compat_mask =
1423+ params .feature_ro_compat &
1424+ ~le32_to_cpu (es -> s_feature_ro_compat );
1425+ params .clear_feature_compat_mask =
1426+ ~params .feature_compat &
1427+ le32_to_cpu (es -> s_feature_compat );
1428+ params .clear_feature_incompat_mask =
1429+ ~params .feature_incompat &
1430+ le32_to_cpu (es -> s_feature_incompat );
1431+ params .clear_feature_ro_compat_mask =
1432+ ~params .feature_ro_compat &
1433+ le32_to_cpu (es -> s_feature_ro_compat );
1434+ params .set_flags |= EXT4_TUNE_FL_EDIT_FEATURES ;
1435+ }
1436+ if (params .set_flags & EXT4_TUNE_FL_EDIT_FEATURES ) {
1437+ if ((params .set_feature_compat_mask &
1438+ ~EXT4_TUNE_SET_COMPAT_SUPP ) ||
1439+ (params .set_feature_incompat_mask &
1440+ ~EXT4_TUNE_SET_INCOMPAT_SUPP ) ||
1441+ (params .set_feature_ro_compat_mask &
1442+ ~EXT4_TUNE_SET_RO_COMPAT_SUPP ) ||
1443+ (params .clear_feature_compat_mask &
1444+ ~EXT4_TUNE_CLEAR_COMPAT_SUPP ) ||
1445+ (params .clear_feature_incompat_mask &
1446+ ~EXT4_TUNE_CLEAR_INCOMPAT_SUPP ) ||
1447+ (params .clear_feature_ro_compat_mask &
1448+ ~EXT4_TUNE_CLEAR_RO_COMPAT_SUPP ))
1449+ return - EOPNOTSUPP ;
1450+
1451+ /*
1452+ * Filter out the features that are already set from
1453+ * the set_mask.
1454+ */
1455+ params .set_feature_compat_mask &=
1456+ ~le32_to_cpu (es -> s_feature_compat );
1457+ params .set_feature_incompat_mask &=
1458+ ~le32_to_cpu (es -> s_feature_incompat );
1459+ params .set_feature_ro_compat_mask &=
1460+ ~le32_to_cpu (es -> s_feature_ro_compat );
1461+ if ((params .set_feature_incompat_mask &
1462+ EXT4_FEATURE_INCOMPAT_CASEFOLD )) {
1463+ enabling_casefold = 1 ;
1464+ if (!(params .set_flags & EXT4_TUNE_FL_ENCODING )) {
1465+ params .encoding = EXT4_ENC_UTF8_12_1 ;
1466+ params .set_flags |= EXT4_TUNE_FL_ENCODING ;
1467+ }
1468+ if (!(params .set_flags & EXT4_TUNE_FL_ENCODING_FLAGS )) {
1469+ params .encoding_flags = 0 ;
1470+ params .set_flags |= EXT4_TUNE_FL_ENCODING_FLAGS ;
1471+ }
1472+ }
1473+ if ((params .set_feature_compat_mask &
1474+ EXT4_FEATURE_COMPAT_DIR_INDEX )) {
1475+ uuid_t uu ;
1476+
1477+ memcpy (& uu , sbi -> s_hash_seed , UUID_SIZE );
1478+ if (uuid_is_null (& uu ))
1479+ generate_random_uuid ((char * )
1480+ & sbi -> s_hash_seed );
1481+ if (params .set_flags & EXT4_TUNE_FL_DEF_HASH_ALG )
1482+ sbi -> s_def_hash_version = params .def_hash_alg ;
1483+ else if (sbi -> s_def_hash_version == 0 )
1484+ sbi -> s_def_hash_version = DX_HASH_HALF_MD4 ;
1485+ if (!(es -> s_flags &
1486+ cpu_to_le32 (EXT2_FLAGS_UNSIGNED_HASH )) &&
1487+ !(es -> s_flags &
1488+ cpu_to_le32 (EXT2_FLAGS_SIGNED_HASH ))) {
1489+ #ifdef __CHAR_UNSIGNED__
1490+ sbi -> s_hash_unsigned = 3 ;
1491+ #else
1492+ sbi -> s_hash_unsigned = 0 ;
1493+ #endif
1494+ }
1495+ }
1496+ }
1497+ if (params .set_flags & EXT4_TUNE_FL_ENCODING ) {
1498+ if (!enabling_casefold )
1499+ return - EINVAL ;
1500+ if (params .encoding == 0 )
1501+ params .encoding = EXT4_ENC_UTF8_12_1 ;
1502+ else if (params .encoding != EXT4_ENC_UTF8_12_1 )
1503+ return - EINVAL ;
1504+ }
1505+ if (params .set_flags & EXT4_TUNE_FL_ENCODING_FLAGS ) {
1506+ if (!enabling_casefold )
1507+ return - EINVAL ;
1508+ if (params .encoding_flags & ~SB_ENC_SUPP_MASK )
1509+ return - EINVAL ;
1510+ }
1511+
1512+ ret = mnt_want_write_file (filp );
1513+ if (ret )
1514+ return ret ;
1515+
1516+ ret = ext4_update_superblocks_fn (sb , ext4_sb_setparams , & params );
1517+ mnt_drop_write_file (filp );
1518+
1519+ if (params .set_flags & EXT4_TUNE_FL_DEF_HASH_ALG )
1520+ sbi -> s_def_hash_version = params .def_hash_alg ;
1521+
1522+ return ret ;
1523+ }
1524+
12331525static long __ext4_ioctl (struct file * filp , unsigned int cmd , unsigned long arg )
12341526{
12351527 struct inode * inode = file_inode (filp );
@@ -1616,6 +1908,11 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
16161908 return ext4_ioctl_getuuid (EXT4_SB (sb ), (void __user * )arg );
16171909 case EXT4_IOC_SETFSUUID :
16181910 return ext4_ioctl_setuuid (filp , (const void __user * )arg );
1911+ case EXT4_IOC_GET_TUNE_SB_PARAM :
1912+ return ext4_ioctl_get_tune_sb (EXT4_SB (sb ),
1913+ (void __user * )arg );
1914+ case EXT4_IOC_SET_TUNE_SB_PARAM :
1915+ return ext4_ioctl_set_tune_sb (filp , (void __user * )arg );
16191916 default :
16201917 return - ENOTTY ;
16211918 }
@@ -1703,7 +2000,8 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
17032000}
17042001#endif
17052002
1706- static void set_overhead (struct ext4_super_block * es , const void * arg )
2003+ static void set_overhead (struct ext4_sb_info * sbi ,
2004+ struct ext4_super_block * es , const void * arg )
17072005{
17082006 es -> s_overhead_clusters = cpu_to_le32 (* ((unsigned long * ) arg ));
17092007}
0 commit comments