WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
        rb_erase(&em->rb_node, &tree->map);
-       list_del_init(&em->list);
+       if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
+               list_del_init(&em->list);
        em->in_tree = 0;
        return ret;
 }
 
                list_del_init(&em->list);
                if (em->generation <= test_gen)
                        continue;
+               /* Need a ref to keep it from getting evicted from cache */
+               atomic_inc(&em->refs);
+               set_bit(EXTENT_FLAG_LOGGING, &em->flags);
                list_add_tail(&em->list, &extents);
        }
 
                em = list_entry(extents.next, struct extent_map, list);
 
                list_del_init(&em->list);
+               clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
 
                /*
                 * If we had an error we just need to delete everybody from our
                 * private list.
                 */
-               if (ret)
+               if (ret) {
+                       free_extent_map(em);
                        continue;
+               }
+
+               write_unlock(&tree->lock);
 
                /*
                 * If the previous EM and the last extent we left off on aren't
                        ret = copy_items(trans, inode, dst_path, args.src,
                                         args.start_slot, args.nr,
                                         LOG_INODE_ALL);
-                       if (ret)
+                       if (ret) {
+                               free_extent_map(em);
+                               write_lock(&tree->lock);
                                continue;
+                       }
                        btrfs_release_path(path);
                        args.nr = 0;
                }
 
                ret = log_one_extent(trans, inode, root, em, path, dst_path, &args);
+               free_extent_map(em);
+               write_lock(&tree->lock);
        }
+       WARN_ON(!list_empty(&extents));
+       write_unlock(&tree->lock);
 
        if (!ret && args.nr)
                ret = copy_items(trans, inode, dst_path, args.src,
                                 args.start_slot, args.nr, LOG_INODE_ALL);
        btrfs_release_path(path);
-       WARN_ON(!list_empty(&extents));
-       write_unlock(&tree->lock);
        return ret;
 }