Skip to content

Commit 0966aa2

Browse files
maharmstonekdave
authored andcommitted
btrfs-progs: mkfs: refactor add_file_items()
There were two major problems with add_file_items(): it was writing all files sector-by-sector, making compression impossible, and it was assuming that pread would never do a short read. Fix these problems, and create a new helper add_file_item_extent(). Signed-off-by: Mark Harmstone <maharmstone@fb.com>
1 parent 57512f9 commit 0966aa2

File tree

1 file changed

+100
-77
lines changed

1 file changed

+100
-77
lines changed

mkfs/rootdir.c

Lines changed: 100 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,90 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
455455
return ret;
456456
}
457457

458+
/*
459+
* keep our extent size at 1MB max, this makes it easier to work
460+
* inside the tiny block groups created during mkfs
461+
*/
462+
#define MAX_EXTENT_SIZE SZ_1M
463+
464+
struct source_descriptor {
465+
int fd;
466+
char *buf;
467+
u64 size;
468+
const char *path_name;
469+
};
470+
471+
static int add_file_item_extent(struct btrfs_trans_handle *trans,
472+
struct btrfs_root *root,
473+
struct btrfs_inode_item *btrfs_inode,
474+
u64 objectid,
475+
const struct source_descriptor *source,
476+
u64 file_pos)
477+
{
478+
int ret;
479+
u32 sectorsize = root->fs_info->sectorsize;
480+
u64 bytes_read, first_block, to_read, to_write;
481+
struct btrfs_key key;
482+
struct btrfs_file_extent_item stack_fi = { 0 };
483+
484+
to_read = min(file_pos + MAX_EXTENT_SIZE, source->size) - file_pos;
485+
486+
bytes_read = 0;
487+
488+
while (bytes_read < to_read) {
489+
ssize_t ret_read;
490+
491+
ret_read = pread(source->fd, source->buf + bytes_read,
492+
to_read - bytes_read, file_pos + bytes_read);
493+
if (ret_read < 0) {
494+
error("cannot read %s at offset %llu length %llu: %m",
495+
source->path_name, file_pos + bytes_read,
496+
to_read - bytes_read);
497+
return -errno;
498+
}
499+
500+
bytes_read += ret_read;
501+
}
502+
503+
to_write = round_up(to_read, sectorsize);
504+
memset(source->buf + to_read, 0, to_write - to_read);
505+
506+
ret = btrfs_reserve_extent(trans, root, to_write, 0, 0,
507+
(u64)-1, &key, 1);
508+
if (ret)
509+
return ret;
510+
511+
first_block = key.objectid;
512+
513+
ret = write_data_to_disk(root->fs_info, source->buf, first_block,
514+
to_write);
515+
if (ret) {
516+
error("failed to write %s", source->path_name);
517+
return ret;
518+
}
519+
520+
for (unsigned int i = 0; i < to_write / sectorsize; i++) {
521+
ret = btrfs_csum_file_block(trans, first_block + (i * sectorsize),
522+
BTRFS_EXTENT_CSUM_OBJECTID,
523+
root->fs_info->csum_type,
524+
source->buf + (i * sectorsize));
525+
if (ret)
526+
return ret;
527+
}
528+
529+
btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_REG);
530+
btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, first_block);
531+
btrfs_set_stack_file_extent_disk_num_bytes(&stack_fi, to_write);
532+
btrfs_set_stack_file_extent_num_bytes(&stack_fi, to_write);
533+
btrfs_set_stack_file_extent_ram_bytes(&stack_fi, to_write);
534+
ret = insert_reserved_file_extent(trans, root, objectid, btrfs_inode,
535+
file_pos, &stack_fi);
536+
if (ret)
537+
return ret;
538+
539+
return to_read;
540+
}
541+
458542
static int add_file_items(struct btrfs_trans_handle *trans,
459543
struct btrfs_root *root,
460544
struct btrfs_inode_item *btrfs_inode, u64 objectid,
@@ -463,15 +547,10 @@ static int add_file_items(struct btrfs_trans_handle *trans,
463547
struct btrfs_fs_info *fs_info = trans->fs_info;
464548
int ret = -1;
465549
ssize_t ret_read;
466-
u64 bytes_read = 0;
467-
struct btrfs_key key;
468-
int blocks;
469550
u32 sectorsize = fs_info->sectorsize;
470-
u64 first_block = 0;
471551
u64 file_pos = 0;
472-
u64 cur_bytes;
473-
u64 total_bytes;
474-
void *buf = NULL;
552+
char *buf = NULL;
553+
struct source_descriptor source;
475554
int fd;
476555

477556
if (st->st_size == 0)
@@ -483,10 +562,6 @@ static int add_file_items(struct btrfs_trans_handle *trans,
483562
return ret;
484563
}
485564

486-
blocks = st->st_size / sectorsize;
487-
if (st->st_size % sectorsize)
488-
blocks += 1;
489-
490565
if (st->st_size <= BTRFS_MAX_INLINE_DATA_SIZE(fs_info) &&
491566
st->st_size < sectorsize) {
492567
char *buffer = malloc(st->st_size);
@@ -496,10 +571,10 @@ static int add_file_items(struct btrfs_trans_handle *trans,
496571
goto end;
497572
}
498573

499-
ret_read = pread(fd, buffer, st->st_size, bytes_read);
574+
ret_read = pread(fd, buffer, st->st_size, 0);
500575
if (ret_read == -1) {
501-
error("cannot read %s at offset %llu length %llu: %m",
502-
path_name, bytes_read, (unsigned long long)st->st_size);
576+
error("cannot read %s at offset %u length %zu: %m",
577+
path_name, 0, st->st_size);
503578
free(buffer);
504579
goto end;
505580
}
@@ -512,78 +587,26 @@ static int add_file_items(struct btrfs_trans_handle *trans,
512587
goto end;
513588
}
514589

515-
/* round up our st_size to the FS blocksize */
516-
total_bytes = (u64)blocks * sectorsize;
517-
518-
buf = malloc(sectorsize);
590+
buf = malloc(MAX_EXTENT_SIZE);
519591
if (!buf) {
520592
ret = -ENOMEM;
521593
goto end;
522594
}
523595

524-
again:
525-
526-
/*
527-
* keep our extent size at 1MB max, this makes it easier to work inside
528-
* the tiny block groups created during mkfs
529-
*/
530-
cur_bytes = min(total_bytes, (u64)SZ_1M);
531-
ret = btrfs_reserve_extent(trans, root, cur_bytes, 0, 0, (u64)-1,
532-
&key, 1);
533-
if (ret)
534-
goto end;
535-
536-
first_block = key.objectid;
537-
bytes_read = 0;
538-
539-
while (bytes_read < cur_bytes) {
596+
source.fd = fd;
597+
source.buf = buf;
598+
source.size = st->st_size;
599+
source.path_name = path_name;
540600

541-
memset(buf, 0, sectorsize);
601+
while (file_pos < st->st_size) {
602+
ret = add_file_item_extent(trans, root, btrfs_inode, objectid,
603+
&source, file_pos);
604+
if (ret < 0)
605+
break;
542606

543-
ret_read = pread(fd, buf, sectorsize, file_pos + bytes_read);
544-
if (ret_read == -1) {
545-
error("cannot read %s at offset %llu length %u: %m",
546-
path_name, file_pos + bytes_read, sectorsize);
547-
goto end;
548-
}
549-
550-
ret = write_data_to_disk(root->fs_info, buf,
551-
first_block + bytes_read, sectorsize);
552-
if (ret) {
553-
error("failed to write %s", path_name);
554-
goto end;
555-
}
556-
557-
ret = btrfs_csum_file_block(trans, first_block + bytes_read,
558-
BTRFS_EXTENT_CSUM_OBJECTID,
559-
fs_info->csum_type, buf);
560-
if (ret)
561-
goto end;
562-
563-
bytes_read += sectorsize;
607+
file_pos += ret;
564608
}
565609

566-
if (bytes_read) {
567-
struct btrfs_file_extent_item stack_fi = { 0 };
568-
569-
btrfs_set_stack_file_extent_type(&stack_fi, BTRFS_FILE_EXTENT_REG);
570-
btrfs_set_stack_file_extent_disk_bytenr(&stack_fi, first_block);
571-
btrfs_set_stack_file_extent_disk_num_bytes(&stack_fi, cur_bytes);
572-
btrfs_set_stack_file_extent_num_bytes(&stack_fi, cur_bytes);
573-
btrfs_set_stack_file_extent_ram_bytes(&stack_fi, cur_bytes);
574-
ret = insert_reserved_file_extent(trans, root, objectid,
575-
btrfs_inode, file_pos, &stack_fi);
576-
if (ret)
577-
goto end;
578-
579-
}
580-
581-
file_pos += cur_bytes;
582-
total_bytes -= cur_bytes;
583-
584-
if (total_bytes)
585-
goto again;
586-
587610
end:
588611
free(buf);
589612
close(fd);

0 commit comments

Comments
 (0)