diff options
Diffstat (limited to 'extent_io.c')
-rw-r--r-- | extent_io.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/extent_io.c b/extent_io.c index 5093aeb2..592acd61 100644 --- a/extent_io.c +++ b/extent_io.c @@ -747,6 +747,93 @@ int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset, return 0; } +int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset, + u64 bytes, int mirror) +{ + struct btrfs_multi_bio *multi = NULL; + struct btrfs_device *device; + u64 bytes_left = bytes; + u64 this_len; + u64 total_write = 0; + u64 *raid_map = NULL; + u64 dev_bytenr; + int dev_nr; + int ret = 0; + + while (bytes_left > 0) { + this_len = bytes_left; + dev_nr = 0; + + ret = btrfs_map_block(&info->mapping_tree, WRITE, offset, + &this_len, &multi, mirror, &raid_map); + if (ret) { + fprintf(stderr, "Couldn't map the block %Lu\n", + offset); + return -EIO; + } + + if (raid_map) { + struct extent_buffer *eb; + u64 stripe_len = this_len; + + this_len = min(this_len, bytes_left); + this_len = min(this_len, (u64)info->tree_root->leafsize); + + eb = malloc(sizeof(struct extent_buffer) + this_len); + BUG_ON(!eb); + + memset(eb, 0, sizeof(struct extent_buffer) + this_len); + eb->start = offset; + eb->len = this_len; + + memcpy(eb->data, buf + total_write, this_len); + ret = write_raid56_with_parity(info, eb, multi, + stripe_len, raid_map); + BUG_ON(ret); + + free(eb); + kfree(raid_map); + raid_map = NULL; + } else while (dev_nr < multi->num_stripes) { + device = multi->stripes[dev_nr].dev; + if (device->fd == 0) { + kfree(multi); + return -EIO; + } + + dev_bytenr = multi->stripes[dev_nr].physical; + this_len = min(this_len, bytes_left); + dev_nr++; + + ret = pwrite(device->fd, buf + total_write, this_len, dev_bytenr); + if (ret != this_len) { + if (ret < 0) { + fprintf(stderr, "Error writing to " + "device %d\n", errno); + ret = errno; + kfree(multi); + return ret; + } else { + fprintf(stderr, "Short write\n"); + kfree(multi); + return -EIO; + } + } + } + + BUG_ON(bytes_left < this_len); + + bytes_left -= this_len; + offset += this_len; + total_write += this_len; + + kfree(multi); + multi = NULL; + } + return 0; +} + + int set_extent_buffer_uptodate(struct extent_buffer *eb) { eb->flags |= EXTENT_UPTODATE; |