]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 6 May 2012 17:20:07 +0000 (10:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 6 May 2012 17:20:07 +0000 (10:20 -0700)
Pull btrfs fixes from Chris Mason:
 "The big ones here are a memory leak we introduced in rc1, and a
  scheduling while atomic if the transid on disk doesn't match the
  transid we expected.  This happens for corrupt blocks, or out of date
  disks.

  It also fixes up the ioctl definition for our ioctl to resolve logical
  inode numbers.  The __u32 was a merging error and doesn't match what
  we ship in the progs."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: avoid sleeping in verify_parent_transid while atomic
  Btrfs: fix crash in scrub repair code when device is missing
  btrfs: Fix mismatching struct members in ioctl.h
  Btrfs: fix page leak when allocing extent buffers
  Btrfs: Add properly locking around add_root_to_dirty_list

fs/btrfs/ctree.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/ioctl.h
fs/btrfs/scrub.c
fs/btrfs/tree-log.c

index e801f226d7e028b72ca08b5726ed409215c27b84..4106264fbc655ac79b26efa1177384ea92b72988 100644 (file)
@@ -220,10 +220,12 @@ struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
  */
 static void add_root_to_dirty_list(struct btrfs_root *root)
 {
+       spin_lock(&root->fs_info->trans_lock);
        if (root->track_dirty && list_empty(&root->dirty_list)) {
                list_add(&root->dirty_list,
                         &root->fs_info->dirty_cowonly_roots);
        }
+       spin_unlock(&root->fs_info->trans_lock);
 }
 
 /*
@@ -723,7 +725,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 
                cur = btrfs_find_tree_block(root, blocknr, blocksize);
                if (cur)
-                       uptodate = btrfs_buffer_uptodate(cur, gen);
+                       uptodate = btrfs_buffer_uptodate(cur, gen, 0);
                else
                        uptodate = 0;
                if (!cur || !uptodate) {
@@ -1358,7 +1360,12 @@ static noinline int reada_for_balance(struct btrfs_root *root,
                block1 = btrfs_node_blockptr(parent, slot - 1);
                gen = btrfs_node_ptr_generation(parent, slot - 1);
                eb = btrfs_find_tree_block(root, block1, blocksize);
-               if (eb && btrfs_buffer_uptodate(eb, gen))
+               /*
+                * if we get -eagain from btrfs_buffer_uptodate, we
+                * don't want to return eagain here.  That will loop
+                * forever
+                */
+               if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
                        block1 = 0;
                free_extent_buffer(eb);
        }
@@ -1366,7 +1373,7 @@ static noinline int reada_for_balance(struct btrfs_root *root,
                block2 = btrfs_node_blockptr(parent, slot + 1);
                gen = btrfs_node_ptr_generation(parent, slot + 1);
                eb = btrfs_find_tree_block(root, block2, blocksize);
-               if (eb && btrfs_buffer_uptodate(eb, gen))
+               if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0)
                        block2 = 0;
                free_extent_buffer(eb);
        }
@@ -1504,8 +1511,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
 
        tmp = btrfs_find_tree_block(root, blocknr, blocksize);
        if (tmp) {
-               if (btrfs_buffer_uptodate(tmp, 0)) {
-                       if (btrfs_buffer_uptodate(tmp, gen)) {
+               /* first we do an atomic uptodate check */
+               if (btrfs_buffer_uptodate(tmp, 0, 1) > 0) {
+                       if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
                                /*
                                 * we found an up to date block without
                                 * sleeping, return
@@ -1523,8 +1531,9 @@ read_block_for_search(struct btrfs_trans_handle *trans,
                        free_extent_buffer(tmp);
                        btrfs_set_path_blocking(p);
 
+                       /* now we're allowed to do a blocking uptodate check */
                        tmp = read_tree_block(root, blocknr, blocksize, gen);
-                       if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
+                       if (tmp && btrfs_buffer_uptodate(tmp, gen, 0) > 0) {
                                *eb_ret = tmp;
                                return 0;
                        }
@@ -1559,7 +1568,7 @@ read_block_for_search(struct btrfs_trans_handle *trans,
                 * and give up so that our caller doesn't loop forever
                 * on our EAGAINs.
                 */
-               if (!btrfs_buffer_uptodate(tmp, 0))
+               if (!btrfs_buffer_uptodate(tmp, 0, 0))
                        ret = -EIO;
                free_extent_buffer(tmp);
        }
@@ -4043,7 +4052,7 @@ again:
                        tmp = btrfs_find_tree_block(root, blockptr,
                                            btrfs_level_size(root, level - 1));
 
-                       if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
+                       if (tmp && btrfs_buffer_uptodate(tmp, gen, 1) > 0) {
                                free_extent_buffer(tmp);
                                break;
                        }
@@ -4166,7 +4175,8 @@ next:
                                struct extent_buffer *cur;
                                cur = btrfs_find_tree_block(root, blockptr,
                                            btrfs_level_size(root, level - 1));
-                               if (!cur || !btrfs_buffer_uptodate(cur, gen)) {
+                               if (!cur ||
+                                   btrfs_buffer_uptodate(cur, gen, 1) <= 0) {
                                        slot++;
                                        if (cur)
                                                free_extent_buffer(cur);
index d0c969beaad4d30a52e13ebb74d3f4fcefa9fece..a7ffc88a7dbe4bcc028d3397970275dffcf0492e 100644 (file)
@@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
  * in the wrong place.
  */
 static int verify_parent_transid(struct extent_io_tree *io_tree,
-                                struct extent_buffer *eb, u64 parent_transid)
+                                struct extent_buffer *eb, u64 parent_transid,
+                                int atomic)
 {
        struct extent_state *cached_state = NULL;
        int ret;
@@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
        if (!parent_transid || btrfs_header_generation(eb) == parent_transid)
                return 0;
 
+       if (atomic)
+               return -EAGAIN;
+
        lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,
                         0, &cached_state);
        if (extent_buffer_uptodate(eb) &&
@@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
                ret = read_extent_buffer_pages(io_tree, eb, start,
                                               WAIT_COMPLETE,
                                               btree_get_extent, mirror_num);
-               if (!ret && !verify_parent_transid(io_tree, eb, parent_transid))
+               if (!ret && !verify_parent_transid(io_tree, eb,
+                                                  parent_transid, 0))
                        break;
 
                /*
@@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
        root->commit_root = NULL;
        root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
                                     blocksize, generation);
-       if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) {
+       if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) {
                free_extent_buffer(root->node);
                root->node = NULL;
                return -EIO;
@@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root)
        return 0;
 }
 
-int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
+int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
+                         int atomic)
 {
        int ret;
        struct inode *btree_inode = buf->pages[0]->mapping->host;
@@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)
                return ret;
 
        ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf,
-                                   parent_transid);
+                                   parent_transid, atomic);
+       if (ret == -EAGAIN)
+               return ret;
        return !ret;
 }
 
index a7ace1a2dd12516a57102e44591f881e922ed89d..ab1830aaf0edbffba6a0cef86d13e9b3f2742cda 100644 (file)
@@ -66,7 +66,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
-int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);
+int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
+                         int atomic);
 int btrfs_set_buffer_uptodate(struct extent_buffer *buf);
 int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid);
 u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
index 6fc2e6f5aab859f2c94ca7135c57cee2de8218ba..49fd7b66d57b272c7aeaea7db4b1bbd0985f8aa2 100644 (file)
@@ -6568,7 +6568,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
                        goto skip;
        }
 
-       if (!btrfs_buffer_uptodate(next, generation)) {
+       if (!btrfs_buffer_uptodate(next, generation, 0)) {
                btrfs_tree_unlock(next);
                free_extent_buffer(next);
                next = NULL;
index 198c2ba2fa405ee13ee9ce65ba45a6c4be3773ec..c9018a05036e943a52ad91d81019bb4b934b6b9a 100644 (file)
@@ -4120,6 +4120,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                        if (atomic_inc_not_zero(&exists->refs)) {
                                spin_unlock(&mapping->private_lock);
                                unlock_page(p);
+                               page_cache_release(p);
                                mark_extent_buffer_accessed(exists);
                                goto free_eb;
                        }
@@ -4199,8 +4200,7 @@ free_eb:
                        unlock_page(eb->pages[i]);
        }
 
-       if (!atomic_dec_and_test(&eb->refs))
-               return exists;
+       WARN_ON(!atomic_dec_and_test(&eb->refs));
        btrfs_release_extent_buffer(eb);
        return exists;
 }
index 4f69028a68c486268bf5bcfc097a5412dbdd2ad0..086e6bdae1c4482b93b6dda4d16b1c5af288f2eb 100644 (file)
@@ -252,7 +252,7 @@ struct btrfs_data_container {
 
 struct btrfs_ioctl_ino_path_args {
        __u64                           inum;           /* in */
-       __u32                           size;           /* in */
+       __u64                           size;           /* in */
        __u64                           reserved[4];
        /* struct btrfs_data_container  *fspath;           out */
        __u64                           fspath;         /* out */
@@ -260,7 +260,7 @@ struct btrfs_ioctl_ino_path_args {
 
 struct btrfs_ioctl_logical_ino_args {
        __u64                           logical;        /* in */
-       __u32                           size;           /* in */
+       __u64                           size;           /* in */
        __u64                           reserved[4];
        /* struct btrfs_data_container  *inodes;        out   */
        __u64                           inodes;
index 4f76fc3f8e896ed70b01bcb2f45bdbc68a583ba7..2f3d6f917fb3373c02335b6912fcba1006f5fabe 100644 (file)
@@ -998,6 +998,7 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev,
                        page = sblock->pagev + page_index;
                        page->logical = logical;
                        page->physical = bbio->stripes[mirror_index].physical;
+                       /* for missing devices, bdev is NULL */
                        page->bdev = bbio->stripes[mirror_index].dev->bdev;
                        page->mirror_num = mirror_index + 1;
                        page->page = alloc_page(GFP_NOFS);
@@ -1042,6 +1043,12 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
                struct scrub_page *page = sblock->pagev + page_num;
                DECLARE_COMPLETION_ONSTACK(complete);
 
+               if (page->bdev == NULL) {
+                       page->io_error = 1;
+                       sblock->no_io_error_seen = 0;
+                       continue;
+               }
+
                BUG_ON(!page->page);
                bio = bio_alloc(GFP_NOFS, 1);
                if (!bio)
index d017283ae6f56fa8ea0ba1eeaa04077d443eb0fb..eb1ae908582cc51162a61798c80f3ed38e7ab6e8 100644 (file)
@@ -279,7 +279,7 @@ static int process_one_buffer(struct btrfs_root *log,
                                                log->fs_info->extent_root,
                                                eb->start, eb->len);
 
-       if (btrfs_buffer_uptodate(eb, gen)) {
+       if (btrfs_buffer_uptodate(eb, gen, 0)) {
                if (wc->write)
                        btrfs_write_tree_block(eb);
                if (wc->wait)