Skip to content

Commit 0693834

Browse files
maharmstonekdave
authored andcommitted
btrfs-progs: mkfs: discard free space
When we've finished creating a new filesystem, walk the free-space tree and call discard for what we find - this is the approach that we use with FITRIM in the kernel. The ranges that are free but not already discarded are the metadata blocks that mkfs.btrfs creates with its intermediate transactions. Pull-request: #1021 Signed-off-by: Mark Harmstone <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 3161f76 commit 0693834

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

mkfs/main.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,106 @@ static int parse_inode_flags(const char *option, struct list_head *inode_flags_l
12911291
return ret;
12921292
}
12931293

1294+
static int discard_free_space(struct btrfs_fs_info *fs_info, u64 metadata_profile)
1295+
{
1296+
struct btrfs_root *free_space_root;
1297+
struct btrfs_path path = { 0 };
1298+
struct extent_buffer *leaf;
1299+
int ret;
1300+
struct btrfs_key key = {
1301+
.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID,
1302+
.type = BTRFS_ROOT_ITEM_KEY,
1303+
.offset = 0,
1304+
};
1305+
1306+
if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE))
1307+
return 0;
1308+
1309+
/*
1310+
* Follow the kernel in not doing discard for RAID5 or 6.
1311+
* We don't have to worry about data here, as --rootdir only works
1312+
* with single-device filesystems, and the data block groups are
1313+
* empty otherwise.
1314+
*/
1315+
1316+
if (metadata_profile & BTRFS_BLOCK_GROUP_RAID56_MASK)
1317+
return 0;
1318+
1319+
free_space_root = btrfs_global_root(fs_info, &key);
1320+
1321+
key.objectid = 0;
1322+
key.type = 0;
1323+
key.offset = 0;
1324+
1325+
ret = btrfs_search_slot(NULL, free_space_root, &key, &path, 0, 0);
1326+
if (ret < 0)
1327+
return ret;
1328+
1329+
while (true) {
1330+
leaf = path.nodes[0];
1331+
1332+
if (path.slots[0] >= btrfs_header_nritems(leaf)) {
1333+
ret = btrfs_next_leaf(free_space_root, &path);
1334+
if (ret)
1335+
break;
1336+
1337+
leaf = path.nodes[0];
1338+
}
1339+
1340+
btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
1341+
1342+
if (key.type == BTRFS_FREE_SPACE_EXTENT_KEY) {
1343+
ret = discard_logical_range(fs_info, key.objectid, key.offset);
1344+
if (ret < 0)
1345+
goto out;
1346+
} else if (key.type == BTRFS_FREE_SPACE_BITMAP_KEY) {
1347+
int size, nrbits;
1348+
void *bitmap;
1349+
unsigned long start_bit, end_bit;
1350+
1351+
size = btrfs_item_size(leaf, path.slots[0]);
1352+
bitmap = malloc(size);
1353+
if (!bitmap) {
1354+
ret = -ENOMEM;
1355+
goto out;
1356+
}
1357+
1358+
read_extent_buffer(leaf, bitmap,
1359+
btrfs_item_ptr_offset(leaf, path.slots[0]),
1360+
size);
1361+
1362+
nrbits = div_u64(key.offset, fs_info->sectorsize);
1363+
start_bit = find_next_bit_le(bitmap, nrbits, 0);
1364+
1365+
while (start_bit < nrbits) {
1366+
u64 addr, length;
1367+
1368+
end_bit = find_next_zero_bit_le(bitmap, nrbits, start_bit);
1369+
addr = key.objectid + (start_bit * fs_info->sectorsize);
1370+
length = (end_bit - start_bit) * fs_info->sectorsize;
1371+
1372+
ret = discard_logical_range(fs_info, addr, length);
1373+
if (ret < 0) {
1374+
free(bitmap);
1375+
goto out;
1376+
}
1377+
1378+
start_bit = find_next_bit_le(bitmap, nrbits, end_bit);
1379+
}
1380+
1381+
free(bitmap);
1382+
}
1383+
1384+
path.slots[0]++;
1385+
}
1386+
1387+
ret = 0;
1388+
1389+
out:
1390+
btrfs_release_path(&path);
1391+
return ret;
1392+
}
1393+
12941394
int BOX_MAIN(mkfs)(int argc, char **argv)
12951395
{
12961396
char *file;
@@ -2312,6 +2412,15 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
23122412
}
23132413
}
23142414

2415+
if (opt_discard) {
2416+
ret = discard_free_space(fs_info, metadata_profile);
2417+
if (ret < 0) {
2418+
errno = -ret;
2419+
error("failed to discard free space: %m");
2420+
goto out;
2421+
}
2422+
}
2423+
23152424
/*
23162425
* The filesystem is now fully set up, commit the remaining changes and
23172426
* fix the signature as the last step before closing the devices.

0 commit comments

Comments
 (0)