]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-4.13-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Jul 2017 05:55:52 +0000 (22:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Jul 2017 05:55:52 +0000 (22:55 -0700)
Pull btrfs fixes from David Sterba:
 "We've identified and fixed a silent corruption (introduced by code in
  the first pull), a fixup after the blk_status_t merge and two fixes to
  incremental send that Filipe has been hunting for some time"

* 'for-4.13-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  Btrfs: fix unexpected return value of bio_readpage_error
  btrfs: btrfs_create_repair_bio never fails, skip error handling
  btrfs: cloned bios must not be iterated by bio_for_each_segment_all
  Btrfs: fix write corruption due to bio cloning on raid5/6
  Btrfs: incremental send, fix invalid memory access
  Btrfs: incremental send, fix invalid path for link commands

fs/btrfs/compression.c
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c
fs/btrfs/raid56.c
fs/btrfs/send.c

index 2c0b7b57fcd5525f826f40041da230b5fe212fcf..d2ef9ac2a63038e279239012fdec7de0cf9573e3 100644 (file)
@@ -152,6 +152,7 @@ csum_failed:
                 * we have verified the checksum already, set page
                 * checked so the end_io handlers know about it
                 */
+               ASSERT(!bio_flagged(bio, BIO_CLONED));
                bio_for_each_segment_all(bvec, cb->orig_bio, i)
                        SetPageChecked(bvec->bv_page);
 
index 086dcbadce0971a43cd099fa6e0bbcd23bcc17e1..080e2ebb8aa0137baef69edda45aa895bf8b7c7c 100644 (file)
@@ -964,6 +964,7 @@ static blk_status_t btree_csum_one_bio(struct bio *bio)
        struct btrfs_root *root;
        int i, ret = 0;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                root = BTRFS_I(bvec->bv_page->mapping->host)->root;
                ret = csum_dirty_buffer(root->fs_info, bvec->bv_page);
index 556484cf5d9338d3383a23de7d484df2b5348d73..0aff9b278c1990f55feb2693a9fff65d5bf693ed 100644 (file)
@@ -2258,7 +2258,7 @@ int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
        return 0;
 }
 
-int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
+bool btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
                           struct io_failure_record *failrec, int failed_mirror)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
@@ -2274,7 +2274,7 @@ int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
                btrfs_debug(fs_info,
                        "Check Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d",
                        num_copies, failrec->this_mirror, failed_mirror);
-               return 0;
+               return false;
        }
 
        /*
@@ -2315,10 +2315,10 @@ int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
                btrfs_debug(fs_info,
                        "Check Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d",
                        num_copies, failrec->this_mirror, failed_mirror);
-               return 0;
+               return false;
        }
 
-       return 1;
+       return true;
 }
 
 
@@ -2382,8 +2382,8 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
        if (ret)
                return ret;
 
-       ret = btrfs_check_repairable(inode, failed_bio, failrec, failed_mirror);
-       if (!ret) {
+       if (!btrfs_check_repairable(inode, failed_bio, failrec,
+                                   failed_mirror)) {
                free_io_failure(failure_tree, tree, failrec);
                return -EIO;
        }
@@ -2396,10 +2396,6 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                                      start - page_offset(page),
                                      (int)phy_offset, failed_bio->bi_end_io,
                                      NULL);
-       if (!bio) {
-               free_io_failure(failure_tree, tree, failrec);
-               return -EIO;
-       }
        bio_set_op_attrs(bio, REQ_OP_READ, read_mode);
 
        btrfs_debug(btrfs_sb(inode->i_sb),
@@ -2456,6 +2452,7 @@ static void end_bio_extent_writepage(struct bio *bio)
        u64 end;
        int i;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
@@ -2526,6 +2523,7 @@ static void end_bio_extent_readpage(struct bio *bio)
        int ret;
        int i;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
@@ -3680,6 +3678,7 @@ static void end_bio_extent_buffer_writepage(struct bio *bio)
        struct extent_buffer *eb;
        int i, done;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
index 3fb8513bf02e27d97eed1f1529aa456b919eeca6..4f030912f3efe784cfec3117a4459c07d77518c8 100644 (file)
@@ -539,8 +539,8 @@ void btrfs_free_io_failure_record(struct btrfs_inode *inode, u64 start,
                u64 end);
 int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
                                struct io_failure_record **failrec_ret);
-int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
-                          struct io_failure_record *failrec, int fail_mirror);
+bool btrfs_check_repairable(struct inode *inode, struct bio *failed_bio,
+                           struct io_failure_record *failrec, int fail_mirror);
 struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio,
                                    struct io_failure_record *failrec,
                                    struct page *page, int pg_offset, int icsum,
index 06dea7c89bbde5866664294a8d639b13d6dcf7bb..95c212037095fea727f4a35ea19d9d7e54ad8cfe 100644 (file)
@@ -8016,10 +8016,6 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
        isector >>= inode->i_sb->s_blocksize_bits;
        bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
                                pgoff, isector, repair_endio, repair_arg);
-       if (!bio) {
-               free_io_failure(failure_tree, io_tree, failrec);
-               return -EIO;
-       }
        bio_set_op_attrs(bio, REQ_OP_READ, read_mode);
 
        btrfs_debug(BTRFS_I(inode)->root->fs_info,
@@ -8059,6 +8055,7 @@ static void btrfs_retry_endio_nocsum(struct bio *bio)
        ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode));
 
        done->uptodate = 1;
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i)
                clean_io_failure(BTRFS_I(inode)->root->fs_info, failure_tree,
                                 io_tree, done->start, bvec->bv_page,
@@ -8150,6 +8147,7 @@ static void btrfs_retry_endio(struct bio *bio)
        io_tree = &BTRFS_I(inode)->io_tree;
        failure_tree = &BTRFS_I(inode)->io_failure_tree;
 
+       ASSERT(!bio_flagged(bio, BIO_CLONED));
        bio_for_each_segment_all(bvec, bio, i) {
                ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page,
                                             bvec->bv_offset, done->start,
index 6f845d219cd6d0c6d8a8dfc26019ca6c7be122af..208638384cd2abfb1206b2f5927b5763a6330283 100644 (file)
@@ -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;
+
+       if (bio_flagged(bio, BIO_CLONED))
+               bio->bi_iter = btrfs_io_bio(bio)->iter;
 
-       bio_for_each_segment_all(bvec, bio, i)
-               SetPageUptodate(bvec->bv_page);
+       bio_for_each_segment(bvec, bio, iter)
+               SetPageUptodate(bvec.bv_page);
 }
 
 /*
index e937c10b8287594ff8ff1509599bfe6a0559376c..b082210df9c8b44d822dcb20ae07fb56a76fdde3 100644 (file)
@@ -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;
-                                               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);
+                                       ret = update_ref_path(sctx, cur);
+                                       if (ret < 0)
                                                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. */