]> git.hungrycats.org Git - linux/commitdiff
Revert "Btrfs: fix memory corruption on failure to submit bio for direct IO"
authorZygo Blaxell <zblaxell@serenity.furryterror.org>
Mon, 27 Jul 2015 17:19:03 +0000 (13:19 -0400)
committerZygo Blaxell <zblaxell@serenity.furryterror.org>
Mon, 27 Jul 2015 17:19:03 +0000 (13:19 -0400)
This reverts commit b46185e567da0f1c2c8e4905a8ded6b7e1003cd3.

fs/btrfs/inode.c
fs/btrfs/ordered-data.c

index 6ff499c5f1382baede043637131cb14e50f40294..8474b8b617d1aa77f44e6cace90b343ebb7bdd4f 100644 (file)
@@ -8162,8 +8162,9 @@ out_err:
 static void btrfs_submit_direct(int rw, struct bio *dio_bio,
                                struct inode *inode, loff_t file_offset)
 {
-       struct btrfs_dio_private *dip = NULL;
-       struct bio *io_bio = NULL;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_dio_private *dip;
+       struct bio *io_bio;
        struct btrfs_io_bio *btrfs_bio;
        int skip_sum;
        int write = rw & REQ_WRITE;
@@ -8180,7 +8181,7 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
        dip = kzalloc(sizeof(*dip), GFP_NOFS);
        if (!dip) {
                ret = -ENOMEM;
-               goto free_ordered;
+               goto free_io_bio;
        }
 
        dip->private = dio_bio->bi_private;
@@ -8208,55 +8209,25 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
 
        if (btrfs_bio->end_io)
                btrfs_bio->end_io(btrfs_bio, ret);
+free_io_bio:
+       bio_put(io_bio);
 
 free_ordered:
        /*
-        * If we arrived here it means either we failed to submit the dip
-        * or we either failed to clone the dio_bio or failed to allocate the
-        * dip. If we cloned the dio_bio and allocated the dip, we can just
-        * call bio_endio against our io_bio so that we get proper resource
-        * cleanup if we fail to submit the dip, otherwise, we must do the
-        * same as btrfs_endio_direct_[write|read] because we can't call these
-        * callbacks - they require an allocated dip and a clone of dio_bio.
+        * If this is a write, we need to clean up the reserved space and kill
+        * the ordered extent.
         */
-       if (io_bio && dip) {
-               bio_endio(io_bio, ret);
-               /*
-                * The end io callbacks free our dip, do the final put on io_bio
-                * and all the cleanup and final put for dio_bio (through
-                * dio_end_io()).
-                */
-               dip = NULL;
-               io_bio = NULL;
-       } else {
-               if (write) {
-                       struct btrfs_ordered_extent *ordered;
-
-                       ordered = btrfs_lookup_ordered_extent(inode,
-                                                             file_offset);
-                       set_bit(BTRFS_ORDERED_IOERR, &ordered->flags);
-                       /*
-                        * Decrements our ref on the ordered extent and removes
-                        * the ordered extent from the inode's ordered tree,
-                        * doing all the proper resource cleanup such as for the
-                        * reserved space and waking up any waiters for this
-                        * ordered extent (through btrfs_remove_ordered_extent).
-                        */
-                       btrfs_finish_ordered_io(ordered);
-               } else {
-                       unlock_extent(&BTRFS_I(inode)->io_tree, file_offset,
-                             file_offset + dio_bio->bi_iter.bi_size - 1);
-               }
-               clear_bit(BIO_UPTODATE, &dio_bio->bi_flags);
-               /*
-                * Releases and cleans up our dio_bio, no need to bio_put()
-                * nor bio_endio()/bio_io_error() against dio_bio.
-                */
-               dio_end_io(dio_bio, ret);
+       if (write) {
+               struct btrfs_ordered_extent *ordered;
+               ordered = btrfs_lookup_ordered_extent(inode, file_offset);
+               if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
+                   !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
+                       btrfs_free_reserved_extent(root, ordered->start,
+                                                  ordered->disk_len, 1);
+               btrfs_put_ordered_extent(ordered);
+               btrfs_put_ordered_extent(ordered);
        }
-       if (io_bio)
-               bio_put(io_bio);
-       kfree(dip);
+       bio_endio(dio_bio, ret);
 }
 
 static ssize_t check_direct_IO(struct btrfs_root *root, struct kiocb *iocb,
index 98e2ce42879945834297779bb8d9513fffd98c03..760c4a5e096b4d5a403f7923ad4b65537a085886 100644 (file)
@@ -545,10 +545,6 @@ void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
        trace_btrfs_ordered_extent_put(entry->inode, entry);
 
        if (atomic_dec_and_test(&entry->refs)) {
-               ASSERT(list_empty(&entry->log_list));
-               ASSERT(list_empty(&entry->trans_list));
-               ASSERT(list_empty(&entry->root_extent_list));
-               ASSERT(RB_EMPTY_NODE(&entry->rb_node));
                if (entry->inode)
                        btrfs_add_delayed_iput(entry->inode);
                while (!list_empty(&entry->list)) {
@@ -576,7 +572,6 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        spin_lock_irq(&tree->lock);
        node = &entry->rb_node;
        rb_erase(node, &tree->tree);
-       RB_CLEAR_NODE(node);
        if (tree->last == node)
                tree->last = NULL;
        set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);