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) {
                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);
        }
                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);
        }
 
        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
                        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;
                        }
                 * 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);
        }
                        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;
                        }
                                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);
 
  * 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;
        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) &&
                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;
 
                /*
        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;
        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;
                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;
 }
 
 
 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);