Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Oct 2009 22:06:37 +0000 (15:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 15 Oct 2009 22:06:37 +0000 (15:06 -0700)
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable:
  Btrfs: always pin metadata in discard mode
  Btrfs: enable discard support
  Btrfs: add -o discard option
  Btrfs: properly wait log writers during log sync
  Btrfs: fix possible ENOSPC problems with truncate
  Btrfs: fix btrfs acl #ifdef checks
  Btrfs: streamline tree-log btree block writeout
  Btrfs: avoid tree log commit when there are no changes
  Btrfs: only write one super copy during fsync

1  2 
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/super.c
fs/btrfs/tree-log.c

diff --combined fs/btrfs/ctree.h
@@@ -1009,6 -1009,7 +1009,7 @@@ struct btrfs_root 
        atomic_t log_writers;
        atomic_t log_commit[2];
        unsigned long log_transid;
+       unsigned long last_log_commit;
        unsigned long log_batch;
        pid_t log_start_pid;
        bool log_multiple_pids;
  #define BTRFS_MOUNT_FLUSHONCOMMIT       (1 << 7)
  #define BTRFS_MOUNT_SSD_SPREAD                (1 << 8)
  #define BTRFS_MOUNT_NOSSD             (1 << 9)
+ #define BTRFS_MOUNT_DISCARD           (1 << 10)
  
  #define btrfs_clear_opt(o, opt)               ((o) &= ~BTRFS_MOUNT_##opt)
  #define btrfs_set_opt(o, opt)         ((o) |= BTRFS_MOUNT_##opt)
@@@ -2342,7 -2344,7 +2344,7 @@@ int btrfs_sync_file(struct file *file, 
  int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
  int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
 -extern struct file_operations btrfs_file_operations;
 +extern const struct file_operations btrfs_file_operations;
  int btrfs_drop_extents(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct inode *inode,
                       u64 start, u64 end, u64 locked_end,
@@@ -2373,7 -2375,7 +2375,7 @@@ int btrfs_parse_options(struct btrfs_ro
  int btrfs_sync_fs(struct super_block *sb, int wait);
  
  /* acl.c */
- #ifdef CONFIG_BTRFS_POSIX_ACL
+ #ifdef CONFIG_BTRFS_FS_POSIX_ACL
  int btrfs_check_acl(struct inode *inode, int mask);
  #else
  #define btrfs_check_acl NULL
diff --combined fs/btrfs/disk-io.c
@@@ -773,7 -773,7 +773,7 @@@ static void btree_invalidatepage(struc
        }
  }
  
 -static struct address_space_operations btree_aops = {
 +static const struct address_space_operations btree_aops = {
        .readpage       = btree_readpage,
        .writepage      = btree_writepage,
        .writepages     = btree_writepages,
@@@ -822,14 -822,16 +822,14 @@@ struct extent_buffer *btrfs_find_create
  
  int btrfs_write_tree_block(struct extent_buffer *buf)
  {
 -      return btrfs_fdatawrite_range(buf->first_page->mapping, buf->start,
 -                                    buf->start + buf->len - 1, WB_SYNC_ALL);
 +      return filemap_fdatawrite_range(buf->first_page->mapping, buf->start,
 +                                      buf->start + buf->len - 1);
  }
  
  int btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
  {
 -      return btrfs_wait_on_page_writeback_range(buf->first_page->mapping,
 -                                buf->start >> PAGE_CACHE_SHIFT,
 -                                (buf->start + buf->len - 1) >>
 -                                 PAGE_CACHE_SHIFT);
 +      return filemap_fdatawait_range(buf->first_page->mapping,
 +                                     buf->start, buf->start + buf->len - 1);
  }
  
  struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
@@@ -917,6 -919,7 +917,7 @@@ static int __setup_root(u32 nodesize, u
        atomic_set(&root->log_writers, 0);
        root->log_batch = 0;
        root->log_transid = 0;
+       root->last_log_commit = 0;
        extent_io_tree_init(&root->dirty_log_pages,
                             fs_info->btree_inode->i_mapping, GFP_NOFS);
  
@@@ -1087,6 -1090,7 +1088,7 @@@ int btrfs_add_log_tree(struct btrfs_tra
        WARN_ON(root->log_root);
        root->log_root = log_root;
        root->log_transid = 0;
+       root->last_log_commit = 0;
        return 0;
  }
  
@@@ -1371,7 -1375,6 +1373,7 @@@ static int setup_bdi(struct btrfs_fs_in
  {
        int err;
  
 +      bdi->name = "btrfs";
        bdi->capabilities = BDI_CAP_MAP_COPY;
        err = bdi_init(bdi);
        if (err)
@@@ -1640,7 -1643,6 +1642,7 @@@ struct btrfs_root *open_ctree(struct su
  
        sb->s_blocksize = 4096;
        sb->s_blocksize_bits = blksize_bits(4096);
 +      sb->s_bdi = &fs_info->bdi;
  
        fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID;
        fs_info->btree_inode->i_nlink = 1;
diff --combined fs/btrfs/extent-tree.c
@@@ -1568,23 -1568,22 +1568,23 @@@ static int remove_extent_backref(struc
        return ret;
  }
  
- #ifdef BIO_RW_DISCARD
  static void btrfs_issue_discard(struct block_device *bdev,
                                u64 start, u64 len)
  {
 -      blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL);
 +      blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL,
 +                           DISCARD_FL_BARRIER);
  }
- #endif
  
  static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
                                u64 num_bytes)
  {
- #ifdef BIO_RW_DISCARD
        int ret;
        u64 map_length = num_bytes;
        struct btrfs_multi_bio *multi = NULL;
  
+       if (!btrfs_test_opt(root, DISCARD))
+               return 0;
        /* Tell the block device(s) that the sectors can be discarded */
        ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
                              bytenr, &map_length, &multi, 0);
        }
  
        return ret;
- #else
-       return 0;
- #endif
  }
  
  int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
@@@ -3690,6 -3686,14 +3687,14 @@@ static int pin_down_bytes(struct btrfs_
        if (is_data)
                goto pinit;
  
+       /*
+        * discard is sloooow, and so triggering discards on
+        * individual btree blocks isn't a good plan.  Just
+        * pin everything in discard mode.
+        */
+       if (btrfs_test_opt(root, DISCARD))
+               goto pinit;
        buf = btrfs_find_tree_block(root, bytenr, num_bytes);
        if (!buf)
                goto pinit;
diff --combined fs/btrfs/file.c
@@@ -1023,8 -1023,9 +1023,8 @@@ static ssize_t btrfs_file_write(struct 
                }
  
                if (will_write) {
 -                      btrfs_fdatawrite_range(inode->i_mapping, pos,
 -                                             pos + write_bytes - 1,
 -                                             WB_SYNC_ALL);
 +                      filemap_fdatawrite_range(inode->i_mapping, pos,
 +                                               pos + write_bytes - 1);
                } else {
                        balance_dirty_pages_ratelimited_nr(inode->i_mapping,
                                                           num_pages);
@@@ -1086,8 -1087,10 +1086,10 @@@ out_nolock
                                        btrfs_end_transaction(trans, root);
                                else
                                        btrfs_commit_transaction(trans, root);
-                       } else {
+                       } else if (ret != BTRFS_NO_LOG_SYNC) {
                                btrfs_commit_transaction(trans, root);
+                       } else {
+                               btrfs_end_transaction(trans, root);
                        }
                }
                if (file->f_flags & O_DIRECT) {
@@@ -1137,6 -1140,13 +1139,13 @@@ int btrfs_sync_file(struct file *file, 
        int ret = 0;
        struct btrfs_trans_handle *trans;
  
+       /* we wait first, since the writeback may change the inode */
+       root->log_batch++;
+       /* the VFS called filemap_fdatawrite for us */
+       btrfs_wait_ordered_range(inode, 0, (u64)-1);
+       root->log_batch++;
        /*
         * check the transaction that last modified this inode
         * and see if its already been committed
        if (!BTRFS_I(inode)->last_trans)
                goto out;
  
+       /*
+        * if the last transaction that changed this file was before
+        * the current transaction, we can bail out now without any
+        * syncing
+        */
        mutex_lock(&root->fs_info->trans_mutex);
        if (BTRFS_I(inode)->last_trans <=
            root->fs_info->last_trans_committed) {
        }
        mutex_unlock(&root->fs_info->trans_mutex);
  
-       root->log_batch++;
-       filemap_fdatawrite(inode->i_mapping);
-       btrfs_wait_ordered_range(inode, 0, (u64)-1);
-       root->log_batch++;
-       if (datasync && !(inode->i_state & I_DIRTY_PAGES))
-               goto out;
        /*
         * ok we haven't committed the transaction yet, lets do a commit
         */
         */
        mutex_unlock(&dentry->d_inode->i_mutex);
  
-       if (ret > 0) {
-               ret = btrfs_commit_transaction(trans, root);
-       } else {
-               ret = btrfs_sync_log(trans, root);
-               if (ret == 0)
-                       ret = btrfs_end_transaction(trans, root);
-               else
+       if (ret != BTRFS_NO_LOG_SYNC) {
+               if (ret > 0) {
                        ret = btrfs_commit_transaction(trans, root);
+               } else {
+                       ret = btrfs_sync_log(trans, root);
+                       if (ret == 0)
+                               ret = btrfs_end_transaction(trans, root);
+                       else
+                               ret = btrfs_commit_transaction(trans, root);
+               }
+       } else {
+               ret = btrfs_end_transaction(trans, root);
        }
        mutex_lock(&dentry->d_inode->i_mutex);
  out:
        return ret > 0 ? EIO : ret;
  }
  
 -static struct vm_operations_struct btrfs_file_vm_ops = {
 +static const struct vm_operations_struct btrfs_file_vm_ops = {
        .fault          = filemap_fault,
        .page_mkwrite   = btrfs_page_mkwrite,
  };
@@@ -1214,7 -1226,7 +1225,7 @@@ static int btrfs_file_mmap(struct file  
        return 0;
  }
  
 -struct file_operations btrfs_file_operations = {
 +const struct file_operations btrfs_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
        .aio_read       = generic_file_aio_read,
diff --combined fs/btrfs/inode.c
@@@ -55,14 -55,14 +55,14 @@@ struct btrfs_iget_args 
        struct btrfs_root *root;
  };
  
 -static struct inode_operations btrfs_dir_inode_operations;
 -static struct inode_operations btrfs_symlink_inode_operations;
 -static struct inode_operations btrfs_dir_ro_inode_operations;
 -static struct inode_operations btrfs_special_inode_operations;
 -static struct inode_operations btrfs_file_inode_operations;
 -static struct address_space_operations btrfs_aops;
 -static struct address_space_operations btrfs_symlink_aops;
 -static struct file_operations btrfs_dir_file_operations;
 +static const struct inode_operations btrfs_dir_inode_operations;
 +static const struct inode_operations btrfs_symlink_inode_operations;
 +static const struct inode_operations btrfs_dir_ro_inode_operations;
 +static const struct inode_operations btrfs_special_inode_operations;
 +static const struct inode_operations btrfs_file_inode_operations;
 +static const struct address_space_operations btrfs_aops;
 +static const struct address_space_operations btrfs_symlink_aops;
 +static const struct file_operations btrfs_dir_file_operations;
  static struct extent_io_ops btrfs_extent_io_ops;
  
  static struct kmem_cache *btrfs_inode_cachep;
@@@ -3032,12 -3032,22 +3032,22 @@@ static int btrfs_truncate_page(struct a
  
        if ((offset & (blocksize - 1)) == 0)
                goto out;
+       ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
+       if (ret)
+               goto out;
+       ret = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
+       if (ret)
+               goto out;
  
        ret = -ENOMEM;
  again:
        page = grab_cache_page(mapping, index);
-       if (!page)
+       if (!page) {
+               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
+               btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
                goto out;
+       }
  
        page_start = page_offset(page);
        page_end = page_start + PAGE_CACHE_SIZE - 1;
                goto again;
        }
  
+       clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
+                         EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
+                         GFP_NOFS);
        ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
        if (ret) {
                unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
        unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
  
  out_unlock:
+       if (ret)
+               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
+       btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
        unlock_page(page);
        page_cache_release(page);
  out:
@@@ -3111,7 -3128,9 +3128,9 @@@ int btrfs_cont_expand(struct inode *ino
        if (size <= hole_start)
                return 0;
  
-       btrfs_truncate_page(inode->i_mapping, inode->i_size);
+       err = btrfs_truncate_page(inode->i_mapping, inode->i_size);
+       if (err)
+               return err;
  
        while (1) {
                struct btrfs_ordered_extent *ordered;
@@@ -3480,6 -3499,7 +3499,7 @@@ static noinline void init_btrfs_i(struc
        bi->generation = 0;
        bi->sequence = 0;
        bi->last_trans = 0;
+       bi->last_sub_trans = 0;
        bi->logged_trans = 0;
        bi->delalloc_bytes = 0;
        bi->reserved_bytes = 0;
@@@ -4980,7 -5000,9 +5000,9 @@@ again
        set_page_dirty(page);
        SetPageUptodate(page);
  
-       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
+       BTRFS_I(inode)->last_trans = root->fs_info->generation;
+       BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
        unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
  
  out_unlock:
@@@ -5005,7 -5027,9 +5027,9 @@@ static void btrfs_truncate(struct inod
        if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                return;
  
-       btrfs_truncate_page(inode->i_mapping, inode->i_size);
+       ret = btrfs_truncate_page(inode->i_mapping, inode->i_size);
+       if (ret)
+               return;
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
  
        trans = btrfs_start_transaction(root, 1);
@@@ -5100,6 -5124,7 +5124,7 @@@ struct inode *btrfs_alloc_inode(struct 
        if (!ei)
                return NULL;
        ei->last_trans = 0;
+       ei->last_sub_trans = 0;
        ei->logged_trans = 0;
        ei->outstanding_extents = 0;
        ei->reserved_extents = 0;
@@@ -5729,7 -5754,7 +5754,7 @@@ static int btrfs_permission(struct inod
        return generic_permission(inode, mask, btrfs_check_acl);
  }
  
 -static struct inode_operations btrfs_dir_inode_operations = {
 +static const struct inode_operations btrfs_dir_inode_operations = {
        .getattr        = btrfs_getattr,
        .lookup         = btrfs_lookup,
        .create         = btrfs_create,
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
  };
 -static struct inode_operations btrfs_dir_ro_inode_operations = {
 +static const struct inode_operations btrfs_dir_ro_inode_operations = {
        .lookup         = btrfs_lookup,
        .permission     = btrfs_permission,
  };
  
 -static struct file_operations btrfs_dir_file_operations = {
 +static const struct file_operations btrfs_dir_file_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = btrfs_real_readdir,
@@@ -5790,7 -5815,7 +5815,7 @@@ static struct extent_io_ops btrfs_exten
   *
   * For now we're avoiding this by dropping bmap.
   */
 -static struct address_space_operations btrfs_aops = {
 +static const struct address_space_operations btrfs_aops = {
        .readpage       = btrfs_readpage,
        .writepage      = btrfs_writepage,
        .writepages     = btrfs_writepages,
        .invalidatepage = btrfs_invalidatepage,
        .releasepage    = btrfs_releasepage,
        .set_page_dirty = btrfs_set_page_dirty,
 +      .error_remove_page = generic_error_remove_page,
  };
  
 -static struct address_space_operations btrfs_symlink_aops = {
 +static const struct address_space_operations btrfs_symlink_aops = {
        .readpage       = btrfs_readpage,
        .writepage      = btrfs_writepage,
        .invalidatepage = btrfs_invalidatepage,
        .releasepage    = btrfs_releasepage,
  };
  
 -static struct inode_operations btrfs_file_inode_operations = {
 +static const struct inode_operations btrfs_file_inode_operations = {
        .truncate       = btrfs_truncate,
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
        .fallocate      = btrfs_fallocate,
        .fiemap         = btrfs_fiemap,
  };
 -static struct inode_operations btrfs_special_inode_operations = {
 +static const struct inode_operations btrfs_special_inode_operations = {
        .getattr        = btrfs_getattr,
        .setattr        = btrfs_setattr,
        .permission     = btrfs_permission,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
  };
 -static struct inode_operations btrfs_symlink_inode_operations = {
 +static const struct inode_operations btrfs_symlink_inode_operations = {
        .readlink       = generic_readlink,
        .follow_link    = page_follow_link_light,
        .put_link       = page_put_link,
diff --combined fs/btrfs/super.c
@@@ -51,7 -51,7 +51,7 @@@
  #include "export.h"
  #include "compression.h"
  
 -static struct super_operations btrfs_super_ops;
 +static const struct super_operations btrfs_super_ops;
  
  static void btrfs_put_super(struct super_block *sb)
  {
@@@ -66,7 -66,8 +66,8 @@@ enum 
        Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
        Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
        Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl,
-       Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_err,
+       Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit,
+       Opt_discard, Opt_err,
  };
  
  static match_table_t tokens = {
@@@ -88,6 -89,7 +89,7 @@@
        {Opt_notreelog, "notreelog"},
        {Opt_flushoncommit, "flushoncommit"},
        {Opt_ratio, "metadata_ratio=%d"},
+       {Opt_discard, "discard"},
        {Opt_err, NULL},
  };
  
@@@ -257,6 -259,9 +259,9 @@@ int btrfs_parse_options(struct btrfs_ro
                                       info->metadata_ratio);
                        }
                        break;
+               case Opt_discard:
+                       btrfs_set_opt(info->mount_opt, DISCARD);
+                       break;
                default:
                        break;
                }
@@@ -344,7 -349,7 +349,7 @@@ static int btrfs_fill_super(struct supe
        sb->s_export_op = &btrfs_export_ops;
        sb->s_xattr = btrfs_xattr_handlers;
        sb->s_time_gran = 1;
- #ifdef CONFIG_BTRFS_POSIX_ACL
+ #ifdef CONFIG_BTRFS_FS_POSIX_ACL
        sb->s_flags |= MS_POSIXACL;
  #endif
  
@@@ -677,7 -682,7 +682,7 @@@ static int btrfs_unfreeze(struct super_
        return 0;
  }
  
 -static struct super_operations btrfs_super_ops = {
 +static const struct super_operations btrfs_super_ops = {
        .drop_inode     = btrfs_drop_inode,
        .delete_inode   = btrfs_delete_inode,
        .put_super      = btrfs_put_super,
diff --combined fs/btrfs/tree-log.c
@@@ -1980,6 -1980,7 +1980,7 @@@ int btrfs_sync_log(struct btrfs_trans_h
        int ret;
        struct btrfs_root *log = root->log_root;
        struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
+       u64 log_transid = 0;
  
        mutex_lock(&root->log_mutex);
        index1 = root->log_transid % 2;
        if (atomic_read(&root->log_commit[(index1 + 1) % 2]))
                wait_log_commit(trans, root, root->log_transid - 1);
  
-       while (root->log_multiple_pids) {
+       while (1) {
                unsigned long batch = root->log_batch;
-               mutex_unlock(&root->log_mutex);
-               schedule_timeout_uninterruptible(1);
-               mutex_lock(&root->log_mutex);
+               if (root->log_multiple_pids) {
+                       mutex_unlock(&root->log_mutex);
+                       schedule_timeout_uninterruptible(1);
+                       mutex_lock(&root->log_mutex);
+               }
                wait_for_writer(trans, root);
                if (batch == root->log_batch)
                        break;
                goto out;
        }
  
-       ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
+       /* we start IO on  all the marked extents here, but we don't actually
+        * wait for them until later.
+        */
+       ret = btrfs_write_marked_extents(log, &log->dirty_log_pages);
        BUG_ON(ret);
  
        btrfs_set_root_node(&log->root_item, log->node);
  
        root->log_batch = 0;
+       log_transid = root->log_transid;
        root->log_transid++;
        log->log_transid = root->log_transid;
        root->log_start_pid = 0;
  
        index2 = log_root_tree->log_transid % 2;
        if (atomic_read(&log_root_tree->log_commit[index2])) {
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages);
                wait_log_commit(trans, log_root_tree,
                                log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
         * check the full commit flag again
         */
        if (root->fs_info->last_trans_log_full_commit == trans->transid) {
+               btrfs_wait_marked_extents(log, &log->dirty_log_pages);
                mutex_unlock(&log_root_tree->log_mutex);
                ret = -EAGAIN;
                goto out_wake_log_root;
        ret = btrfs_write_and_wait_marked_extents(log_root_tree,
                                &log_root_tree->dirty_log_pages);
        BUG_ON(ret);
+       btrfs_wait_marked_extents(log, &log->dirty_log_pages);
  
        btrfs_set_super_log_root(&root->fs_info->super_for_commit,
                                log_root_tree->node->start);
         * the running transaction open, so a full commit can't hop
         * in and cause problems either.
         */
-       write_ctree_super(trans, root->fs_info->tree_root, 2);
+       write_ctree_super(trans, root->fs_info->tree_root, 1);
        ret = 0;
  
+       mutex_lock(&root->log_mutex);
+       if (root->last_log_commit < log_transid)
+               root->last_log_commit = log_transid;
+       mutex_unlock(&root->log_mutex);
  out_wake_log_root:
        atomic_set(&log_root_tree->log_commit[index2], 0);
        smp_mb();
@@@ -2615,7 -2629,7 +2629,7 @@@ static noinline int copy_items(struct b
                                                                extent);
                                cs = btrfs_file_extent_offset(src, extent);
                                cl = btrfs_file_extent_num_bytes(src,
 -                                                              extent);;
 +                                                              extent);
                                if (btrfs_file_extent_compression(src,
                                                                  extent)) {
                                        cs = 0;
        return ret;
  }
  
+ static int inode_in_log(struct btrfs_trans_handle *trans,
+                struct inode *inode)
+ {
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret = 0;
+       mutex_lock(&root->log_mutex);
+       if (BTRFS_I(inode)->logged_trans == trans->transid &&
+           BTRFS_I(inode)->last_sub_trans <= root->last_log_commit)
+               ret = 1;
+       mutex_unlock(&root->log_mutex);
+       return ret;
+ }
  /*
   * helper function around btrfs_log_inode to make sure newly created
   * parent directories also end up in the log.  A minimal inode and backref
@@@ -2901,6 -2930,11 +2930,11 @@@ int btrfs_log_inode_parent(struct btrfs
        if (ret)
                goto end_no_trans;
  
+       if (inode_in_log(trans, inode)) {
+               ret = BTRFS_NO_LOG_SYNC;
+               goto end_no_trans;
+       }
        start_log_trans(trans, root);
  
        ret = btrfs_log_inode(trans, root, inode, inode_only);