btrfs: fix check_shared for fiemap ioctl
[sfrench/cifs-2.6.git] / fs / btrfs / extent_io.c
index cee4cb99b8ce7b436c60f394b518e22256ecbf97..8644df8ba5277db3b6d2adc04d4e8d7c6394bca5 100644 (file)
@@ -20,6 +20,7 @@
 #include "locking.h"
 #include "rcu-string.h"
 #include "backref.h"
+#include "transaction.h"
 
 static struct kmem_cache *extent_state_cache;
 static struct kmem_cache *extent_buffer_cache;
@@ -163,13 +164,13 @@ int __init extent_io_init(void)
 {
        extent_state_cache = kmem_cache_create("btrfs_extent_state",
                        sizeof(struct extent_state), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!extent_state_cache)
                return -ENOMEM;
 
        extent_buffer_cache = kmem_cache_create("btrfs_extent_buffer",
                        sizeof(struct extent_buffer), 0,
-                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
+                       SLAB_MEM_SPREAD, NULL);
        if (!extent_buffer_cache)
                goto free_state_cache;
 
@@ -2049,7 +2050,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,
                return -EIO;
        }
        bio->bi_bdev = dev->bdev;
-       bio->bi_rw = WRITE_SYNC;
+       bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_SYNC);
        bio_add_page(bio, page, length, pg_offset);
 
        if (btrfsic_submit_bio_wait(bio)) {
@@ -2697,12 +2698,6 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
                btrfs_bio->csum = NULL;
                btrfs_bio->csum_allocated = NULL;
                btrfs_bio->end_io = NULL;
-
-#ifdef CONFIG_BLK_CGROUP
-               /* FIXME, put this into bio_clone_bioset */
-               if (bio->bi_css)
-                       bio_associate_blkcg(new, bio->bi_css);
-#endif
        }
        return new;
 }
@@ -2756,7 +2751,6 @@ static int merge_bio(struct extent_io_tree *tree, struct page *page,
        if (tree->ops && tree->ops->merge_bio_hook)
                ret = tree->ops->merge_bio_hook(page, offset, size, bio,
                                                bio_flags);
-       BUG_ON(ret < 0);
        return ret;
 
 }
@@ -2879,6 +2873,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
  * into the tree that are removed when the IO is done (by the end_io
  * handlers)
  * XXX JDM: This needs looking at to ensure proper page locking
+ * return 0 on success, otherwise return error
  */
 static int __do_readpage(struct extent_io_tree *tree,
                         struct page *page,
@@ -2900,7 +2895,7 @@ static int __do_readpage(struct extent_io_tree *tree,
        sector_t sector;
        struct extent_map *em;
        struct block_device *bdev;
-       int ret;
+       int ret = 0;
        int nr = 0;
        size_t pg_offset = 0;
        size_t iosize;
@@ -3081,6 +3076,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                } else {
                        SetPageError(page);
                        unlock_extent(tree, cur, cur + iosize - 1);
+                       goto out;
                }
                cur = cur + iosize;
                pg_offset += iosize;
@@ -3091,7 +3087,7 @@ out:
                        SetPageUptodate(page);
                unlock_page(page);
        }
-       return 0;
+       return ret;
 }
 
 static inline void __do_contiguous_readpages(struct extent_io_tree *tree,
@@ -4492,11 +4488,24 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        flags |= (FIEMAP_EXTENT_DELALLOC |
                                  FIEMAP_EXTENT_UNKNOWN);
                } else if (fieinfo->fi_extents_max) {
+                       struct btrfs_trans_handle *trans;
+
                        u64 bytenr = em->block_start -
                                (em->start - em->orig_start);
 
                        disko = em->block_start + offset_in_extent;
 
+                       /*
+                        * We need a trans handle to get delayed refs
+                        */
+                       trans = btrfs_join_transaction(root);
+                       /*
+                        * It's OK if we can't start a trans we can still check
+                        * from commit_root
+                        */
+                       if (IS_ERR(trans))
+                               trans = NULL;
+
                        /*
                         * As btrfs supports shared space, this information
                         * can be exported to userspace tools via
@@ -4504,9 +4513,11 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                         * then we're just getting a count and we can skip the
                         * lookup stuff.
                         */
-                       ret = btrfs_check_shared(NULL, root->fs_info,
+                       ret = btrfs_check_shared(trans, root->fs_info,
                                                 root->objectid,
                                                 btrfs_ino(inode), bytenr);
+                       if (trans)
+                               btrfs_end_transaction(trans, root);
                        if (ret < 0)
                                goto out_free;
                        if (ret)
@@ -5230,14 +5241,31 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
        atomic_set(&eb->io_pages, num_reads);
        for (i = start_i; i < num_pages; i++) {
                page = eb->pages[i];
+
                if (!PageUptodate(page)) {
+                       if (ret) {
+                               atomic_dec(&eb->io_pages);
+                               unlock_page(page);
+                               continue;
+                       }
+
                        ClearPageError(page);
                        err = __extent_read_full_page(tree, page,
                                                      get_extent, &bio,
                                                      mirror_num, &bio_flags,
                                                      REQ_META);
-                       if (err)
+                       if (err) {
                                ret = err;
+                               /*
+                                * We use &bio in above __extent_read_full_page,
+                                * so we ensure that if it returns error, the
+                                * current page fails to add itself to bio and
+                                * it's been unlocked.
+                                *
+                                * We must dec io_pages by ourselves.
+                                */
+                               atomic_dec(&eb->io_pages);
+                       }
                } else {
                        unlock_page(page);
                }