Merge branch 'next/filipe' into for-4.13-part2

- incremental send fixes
- raid56 corruption fix (cloned bio iteration)
This commit is contained in:
David Sterba 2017-07-14 20:37:38 +02:00
Родитель 848c23b78f 6592e58c6b
Коммит 1014f3d68f
2 изменённых файлов: 73 добавлений и 41 удалений

Просмотреть файл

@ -1136,20 +1136,27 @@ static void validate_rbio_for_rmw(struct btrfs_raid_bio *rbio)
static void index_rbio_pages(struct btrfs_raid_bio *rbio)
{
struct bio *bio;
struct bio_vec *bvec;
u64 start;
unsigned long stripe_offset;
unsigned long page_index;
int i;
spin_lock_irq(&rbio->bio_list_lock);
bio_list_for_each(bio, &rbio->bio_list) {
struct bio_vec bvec;
struct bvec_iter iter;
int i = 0;
start = (u64)bio->bi_iter.bi_sector << 9;
stripe_offset = start - rbio->bbio->raid_map[0];
page_index = stripe_offset >> PAGE_SHIFT;
bio_for_each_segment_all(bvec, bio, i)
rbio->bio_pages[page_index + i] = bvec->bv_page;
if (bio_flagged(bio, BIO_CLONED))
bio->bi_iter = btrfs_io_bio(bio)->iter;
bio_for_each_segment(bvec, bio, iter) {
rbio->bio_pages[page_index + i] = bvec.bv_page;
i++;
}
}
spin_unlock_irq(&rbio->bio_list_lock);
}
@ -1423,11 +1430,14 @@ static int fail_bio_stripe(struct btrfs_raid_bio *rbio,
*/
static void set_bio_pages_uptodate(struct bio *bio)
{
struct bio_vec *bvec;
int i;
struct bio_vec bvec;
struct bvec_iter iter;
bio_for_each_segment_all(bvec, bio, i)
SetPageUptodate(bvec->bv_page);
if (bio_flagged(bio, BIO_CLONED))
bio->bi_iter = btrfs_io_bio(bio)->iter;
bio_for_each_segment(bvec, bio, iter)
SetPageUptodate(bvec.bv_page);
}
/*

Просмотреть файл

@ -1856,7 +1856,7 @@ out:
*/
static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
const char *name, int name_len,
u64 *who_ino, u64 *who_gen)
u64 *who_ino, u64 *who_gen, u64 *who_mode)
{
int ret = 0;
u64 gen;
@ -1905,7 +1905,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
if (other_inode > sctx->send_progress ||
is_waiting_for_move(sctx, other_inode)) {
ret = get_inode_info(sctx->parent_root, other_inode, NULL,
who_gen, NULL, NULL, NULL, NULL);
who_gen, who_mode, NULL, NULL, NULL);
if (ret < 0)
goto out;
@ -3683,6 +3683,36 @@ out:
return ret;
}
static int update_ref_path(struct send_ctx *sctx, struct recorded_ref *ref)
{
int ret;
struct fs_path *new_path;
/*
* Our reference's name member points to its full_path member string, so
* we use here a new path.
*/
new_path = fs_path_alloc();
if (!new_path)
return -ENOMEM;
ret = get_cur_path(sctx, ref->dir, ref->dir_gen, new_path);
if (ret < 0) {
fs_path_free(new_path);
return ret;
}
ret = fs_path_add(new_path, ref->name, ref->name_len);
if (ret < 0) {
fs_path_free(new_path);
return ret;
}
fs_path_free(ref->full_path);
set_ref_path(ref, new_path);
return 0;
}
/*
* This does all the move/link/unlink/rmdir magic.
*/
@ -3696,10 +3726,12 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
struct fs_path *valid_path = NULL;
u64 ow_inode = 0;
u64 ow_gen;
u64 ow_mode;
int did_overwrite = 0;
int is_orphan = 0;
u64 last_dir_ino_rm = 0;
bool can_rename = true;
bool orphanized_dir = false;
bool orphanized_ancestor = false;
btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino);
@ -3798,7 +3830,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
*/
ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen,
cur->name, cur->name_len,
&ow_inode, &ow_gen);
&ow_inode, &ow_gen, &ow_mode);
if (ret < 0)
goto out;
if (ret) {
@ -3815,6 +3847,8 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
cur->full_path);
if (ret < 0)
goto out;
if (S_ISDIR(ow_mode))
orphanized_dir = true;
/*
* If ow_inode has its rename operation delayed
@ -3920,6 +3954,18 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
if (ret < 0)
goto out;
} else {
/*
* We might have previously orphanized an inode
* which is an ancestor of our current inode,
* so our reference's full path, which was
* computed before any such orphanizations, must
* be updated.
*/
if (orphanized_dir) {
ret = update_ref_path(sctx, cur);
if (ret < 0)
goto out;
}
ret = send_link(sctx, cur->full_path,
valid_path);
if (ret < 0)
@ -3990,34 +4036,9 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
* ancestor inode.
*/
if (orphanized_ancestor) {
struct fs_path *new_path;
/*
* Our reference's name member points to
* its full_path member string, so we
* use here a new path.
*/
new_path = fs_path_alloc();
if (!new_path) {
ret = -ENOMEM;
ret = update_ref_path(sctx, cur);
if (ret < 0)
goto out;
}
ret = get_cur_path(sctx, cur->dir,
cur->dir_gen,
new_path);
if (ret < 0) {
fs_path_free(new_path);
goto out;
}
ret = fs_path_add(new_path,
cur->name,
cur->name_len);
if (ret < 0) {
fs_path_free(new_path);
goto out;
}
fs_path_free(cur->full_path);
set_ref_path(cur, new_path);
}
ret = send_unlink(sctx, cur->full_path);
if (ret < 0)
@ -5249,15 +5270,12 @@ static int is_extent_unchanged(struct send_ctx *sctx,
goto out;
}
right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
if (right_type == BTRFS_FILE_EXTENT_INLINE) {
right_len = btrfs_file_extent_inline_len(eb, slot, ei);
right_len = PAGE_ALIGN(right_len);
} else {
right_len = btrfs_file_extent_num_bytes(eb, ei);
}
right_offset = btrfs_file_extent_offset(eb, ei);
right_gen = btrfs_file_extent_generation(eb, ei);
/*
* Are we at extent 8? If yes, we know the extent is changed.
@ -5282,6 +5300,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
goto out;
}
right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
right_offset = btrfs_file_extent_offset(eb, ei);
right_gen = btrfs_file_extent_generation(eb, ei);
left_offset_fixed = left_offset;
if (key.offset < ekey->offset) {
/* Fix the right offset for 2a and 7. */