@@ -1164,6 +1164,63 @@ static int parse_subvolume(const char *path, struct list_head *subvols,
11641164 return 0 ;
11651165}
11661166
1167+ static int parse_inode_flags (const char * option , struct list_head * inode_flags_list )
1168+ {
1169+ struct rootdir_inode_flags_entry * entry = NULL ;
1170+ char * colon ;
1171+ char * dumpped = NULL ;
1172+ char * token ;
1173+ int ret ;
1174+
1175+ dumpped = strdup (option );
1176+ if (!dumpped ) {
1177+ ret = - ENOMEM ;
1178+ error_msg (ERROR_MSG_MEMORY , NULL );
1179+ goto cleanup ;
1180+ }
1181+ entry = calloc (1 , sizeof (* entry ));
1182+ if (!entry ) {
1183+ ret = - ENOMEM ;
1184+ error_msg (ERROR_MSG_MEMORY , NULL );
1185+ goto cleanup ;
1186+ }
1187+ colon = strstr (dumpped , ":" );
1188+ if (!colon ) {
1189+ error ("invalid inode flags: %s" , option );
1190+ ret = - EINVAL ;
1191+ goto cleanup ;
1192+ }
1193+ * colon = '\0' ;
1194+
1195+ token = strtok (dumpped , "," );
1196+ while (token ) {
1197+ if (token == NULL )
1198+ break ;
1199+ if (strcmp (token , "nodatacow" ) == 0 ) {
1200+ entry -> nodatacow = true;
1201+ } else if (strcmp (token , "nodatasum" ) == 0 ) {
1202+ entry -> nodatasum = true;
1203+ } else {
1204+ error ("unknown flag: %s" , token );
1205+ ret = - EINVAL ;
1206+ goto cleanup ;
1207+ }
1208+ token = strtok (NULL , "," );
1209+ }
1210+
1211+ if (arg_copy_path (entry -> inode_path , colon + 1 , sizeof (entry -> inode_path ))) {
1212+ error ("--inode-flags path too long" );
1213+ ret = - E2BIG ;
1214+ goto cleanup ;
1215+ }
1216+ list_add_tail (& entry -> list , inode_flags_list );
1217+ return 0 ;
1218+ cleanup :
1219+ free (dumpped );
1220+ free (entry );
1221+ return ret ;
1222+ }
1223+
11671224int BOX_MAIN (mkfs )(int argc , char * * argv )
11681225{
11691226 char * file ;
@@ -1206,10 +1263,12 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
12061263 int nr_global_roots = sysconf (_SC_NPROCESSORS_ONLN );
12071264 char * source_dir = NULL ;
12081265 struct rootdir_subvol * rds ;
1266+ struct rootdir_inode_flags_entry * rif ;
12091267 bool has_default_subvol = false;
12101268 enum btrfs_compression_type compression = BTRFS_COMPRESS_NONE ;
12111269 unsigned int compression_level = 0 ;
12121270 LIST_HEAD (subvols );
1271+ LIST_HEAD (inode_flags_list );
12131272
12141273 cpu_detect_flags ();
12151274 hash_init_accel ();
@@ -1223,6 +1282,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
12231282 GETOPT_VAL_CHECKSUM ,
12241283 GETOPT_VAL_GLOBAL_ROOTS ,
12251284 GETOPT_VAL_DEVICE_UUID ,
1285+ GETOPT_VAL_INODE_FLAGS ,
12261286 GETOPT_VAL_COMPRESS ,
12271287 };
12281288 static const struct option long_options [] = {
@@ -1241,6 +1301,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
12411301 { "version" , no_argument , NULL , 'V' },
12421302 { "rootdir" , required_argument , NULL , 'r' },
12431303 { "subvol" , required_argument , NULL , 'u' },
1304+ { "inode-flags" , required_argument , NULL , GETOPT_VAL_INODE_FLAGS },
12441305 { "nodiscard" , no_argument , NULL , 'K' },
12451306 { "features" , required_argument , NULL , 'O' },
12461307 { "runtime-features" , required_argument , NULL , 'R' },
@@ -1374,6 +1435,11 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
13741435 case 'q' :
13751436 bconf_be_quiet ();
13761437 break ;
1438+ case GETOPT_VAL_INODE_FLAGS :
1439+ ret = parse_inode_flags (optarg , & inode_flags_list );
1440+ if (ret )
1441+ goto error ;
1442+ break ;
13771443 case GETOPT_VAL_COMPRESS :
13781444 if (parse_compression (optarg , & compression , & compression_level )) {
13791445 ret = 1 ;
@@ -1438,6 +1504,11 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
14381504 ret = 1 ;
14391505 goto error ;
14401506 }
1507+ if (!list_empty (& inode_flags_list ) && source_dir == NULL ) {
1508+ error ("option --inode-flags must be used with --rootdir" );
1509+ ret = 1 ;
1510+ goto error ;
1511+ }
14411512
14421513 if (source_dir ) {
14431514 char * canonical = realpath (source_dir , NULL );
@@ -1503,6 +1574,41 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
15031574 }
15041575 }
15051576
1577+ list_for_each_entry (rif , & inode_flags_list , list ) {
1578+ char path [PATH_MAX ];
1579+ struct rootdir_inode_flags_entry * rif2 ;
1580+
1581+ if (path_cat_out (path , source_dir , rif -> inode_path )) {
1582+ ret = - EINVAL ;
1583+ error ("path invalid: %s" , path );
1584+ goto error ;
1585+ }
1586+ if (!realpath (path , rif -> full_path )) {
1587+ ret = - errno ;
1588+ error ("could not get canonical path: %s: %m" , path );
1589+ goto error ;
1590+ }
1591+ if (!path_exists (rif -> full_path )) {
1592+ ret = - ENOENT ;
1593+ error ("inode path does not exist: %s" , rif -> full_path );
1594+ goto error ;
1595+ }
1596+ list_for_each_entry (rif2 , & inode_flags_list , list ) {
1597+ /*
1598+ * Only compare entries before us. So we won't compare
1599+ * the same pair twice.
1600+ */
1601+ if (rif2 == rif )
1602+ break ;
1603+ if (strcmp (rif2 -> full_path , rif -> full_path ) == 0 ) {
1604+ error ("duplicated inode flag entries for %s" ,
1605+ rif -> full_path );
1606+ ret = - EEXIST ;
1607+ goto error ;
1608+ }
1609+ }
1610+ }
1611+
15061612 if (* fs_uuid ) {
15071613 uuid_t dummy_uuid ;
15081614
@@ -2084,10 +2190,15 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
20842190 rds -> is_default ? "" : " " ,
20852191 rds -> dir );
20862192 }
2193+ list_for_each_entry (rif , & inode_flags_list , list ) {
2194+ pr_verbose (LOG_DEFAULT , " Inode flags (%s): %s\n" ,
2195+ rif -> nodatacow ? "NODATACOW" : "" ,
2196+ rif -> inode_path );
2197+ }
20872198
20882199 ret = btrfs_mkfs_fill_dir (trans , source_dir , root ,
2089- & subvols , compression ,
2090- compression_level );
2200+ & subvols , & inode_flags_list ,
2201+ compression , compression_level );
20912202 if (ret ) {
20922203 errno = - ret ;
20932204 error ("error while filling filesystem: %m" );
@@ -2229,6 +2340,12 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
22292340 list_del (& head -> list );
22302341 free (head );
22312342 }
2343+ while (!list_empty (& inode_flags_list )) {
2344+ rif = list_entry (inode_flags_list .next ,
2345+ struct rootdir_inode_flags_entry , list );
2346+ list_del (& rif -> list );
2347+ free (rif );
2348+ }
22322349
22332350 return !!ret ;
22342351
0 commit comments