Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Mar 2015 21:52:54 +0000 (13:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Mar 2015 21:52:54 +0000 (13:52 -0800)
Pull btrfs fixes from Chris Mason:
 "Outside of misc fixes, Filipe has a few fsync corners and we're
  pulling in one more of Josef's fixes from production use here"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs:__add_inode_ref: out of bounds memory read when looking for extended ref.
  Btrfs: fix data loss in the fast fsync path
  Btrfs: remove extra run_delayed_refs in update_cowonly_root
  Btrfs: incremental send, don't rename a directory too soon
  btrfs: fix lost return value due to variable shadowing
  Btrfs: do not ignore errors from btrfs_lookup_xattr in do_setxattr
  Btrfs: fix off-by-one logic error in btrfs_realloc_node
  Btrfs: add missing inode update when punching hole
  Btrfs: abort the transaction if we fail to update the free space cache inode
  Btrfs: fix fsync race leading to ordered extent memory leaks

1  2 
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c

diff --combined fs/btrfs/extent-tree.c
@@@ -3208,6 -3208,8 +3208,8 @@@ static int cache_save_setup(struct btrf
                return 0;
        }
  
+       if (trans->aborted)
+               return 0;
  again:
        inode = lookup_free_space_inode(root, block_group, path);
        if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
         */
        BTRFS_I(inode)->generation = 0;
        ret = btrfs_update_inode(trans, root, inode);
+       if (ret) {
+               /*
+                * So theoretically we could recover from this, simply set the
+                * super cache generation to 0 so we know to invalidate the
+                * cache, but then we'd have to keep track of the block groups
+                * that fail this way so we know we _have_ to reset this cache
+                * before the next commit or risk reading stale cache.  So to
+                * limit our exposure to horrible edge cases lets just abort the
+                * transaction, this only happens in really bad situations
+                * anyway.
+                */
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_put;
+       }
        WARN_ON(ret);
  
        if (i_size_read(inode) > 0) {
@@@ -9359,6 -9375,7 +9375,6 @@@ int btrfs_remove_block_group(struct btr
         * are still on the list after taking the semaphore
         */
        list_del_init(&block_group->list);
 -      list_del_init(&block_group->ro_list);
        if (list_empty(&block_group->space_info->block_groups[index])) {
                kobj = block_group->space_info->block_group_kobjs[index];
                block_group->space_info->block_group_kobjs[index] = NULL;
        btrfs_remove_free_space_cache(block_group);
  
        spin_lock(&block_group->space_info->lock);
 +      list_del_init(&block_group->ro_list);
        block_group->space_info->total_bytes -= block_group->key.offset;
        block_group->space_info->bytes_readonly -= block_group->key.offset;
        block_group->space_info->disk_total -= block_group->key.offset * factor;
diff --combined fs/btrfs/file.c
@@@ -1746,7 -1746,7 +1746,7 @@@ static ssize_t btrfs_file_write_iter(st
  
        mutex_lock(&inode->i_mutex);
  
 -      current->backing_dev_info = inode->i_mapping->backing_dev_info;
 +      current->backing_dev_info = inode_to_bdi(inode);
        err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
        if (err) {
                mutex_unlock(&inode->i_mutex);
        mutex_unlock(&inode->i_mutex);
  
        /*
-        * we want to make sure fsync finds this change
-        * but we haven't joined a transaction running right now.
-        *
-        * Later on, someone is sure to update the inode and get the
-        * real transid recorded.
-        *
-        * We set last_trans now to the fs_info generation + 1,
-        * this will either be one more than the running transaction
-        * or the generation used for the next transaction if there isn't
-        * one running right now.
-        *
         * We also have to set last_sub_trans to the current log transid,
         * otherwise subsequent syncs to a file that's been synced in this
         * transaction will appear to have already occured.
         */
-       BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
        BTRFS_I(inode)->last_sub_trans = root->log_transid;
        if (num_written > 0) {
                err = generic_write_sync(file, pos, num_written);
@@@ -1959,25 -1947,37 +1947,37 @@@ int btrfs_sync_file(struct file *file, 
        atomic_inc(&root->log_batch);
  
        /*
-        * check the transaction that last modified this inode
-        * and see if its already been committed
-        */
-       if (!BTRFS_I(inode)->last_trans) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
-       }
-       /*
-        * if the last transaction that changed this file was before
-        * the current transaction, we can bail out now without any
-        * syncing
+        * If the last transaction that changed this file was before the current
+        * transaction and we have the full sync flag set in our inode, we can
+        * bail out now without any syncing.
+        *
+        * Note that we can't bail out if the full sync flag isn't set. This is
+        * because when the full sync flag is set we start all ordered extents
+        * and wait for them to fully complete - when they complete they update
+        * the inode's last_trans field through:
+        *
+        *     btrfs_finish_ordered_io() ->
+        *         btrfs_update_inode_fallback() ->
+        *             btrfs_update_inode() ->
+        *                 btrfs_set_inode_last_trans()
+        *
+        * So we are sure that last_trans is up to date and can do this check to
+        * bail out safely. For the fast path, when the full sync flag is not
+        * set in our inode, we can not do it because we start only our ordered
+        * extents and don't wait for them to complete (that is when
+        * btrfs_finish_ordered_io runs), so here at this point their last_trans
+        * value might be less than or equals to fs_info->last_trans_committed,
+        * and setting a speculative last_trans for an inode when a buffered
+        * write is made (such as fs_info->generation + 1 for example) would not
+        * be reliable since after setting the value and before fsync is called
+        * any number of transactions can start and commit (transaction kthread
+        * commits the current transaction periodically), and a transaction
+        * commit does not start nor waits for ordered extents to complete.
         */
        smp_mb();
        if (btrfs_inode_in_log(inode, root->fs_info->generation) ||
-           BTRFS_I(inode)->last_trans <=
-           root->fs_info->last_trans_committed) {
-               BTRFS_I(inode)->last_trans = 0;
+           (full_sync && BTRFS_I(inode)->last_trans <=
+            root->fs_info->last_trans_committed)) {
                /*
                 * We'v had everything committed since the last time we were
                 * modified so clear this flag in case it was set for whatever
@@@ -2081,6 -2081,7 +2081,6 @@@ static const struct vm_operations_struc
        .fault          = filemap_fault,
        .map_pages      = filemap_map_pages,
        .page_mkwrite   = btrfs_page_mkwrite,
 -      .remap_pages    = generic_file_remap_pages,
  };
  
  static int btrfs_file_mmap(struct file        *filp, struct vm_area_struct *vma)
@@@ -2275,6 -2276,8 +2275,8 @@@ static int btrfs_punch_hole(struct inod
        bool same_page;
        bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
        u64 ino_size;
+       bool truncated_page = false;
+       bool updated_inode = false;
  
        ret = btrfs_wait_ordered_range(inode, offset, len);
        if (ret)
         * entire page.
         */
        if (same_page && len < PAGE_CACHE_SIZE) {
-               if (offset < ino_size)
+               if (offset < ino_size) {
+                       truncated_page = true;
                        ret = btrfs_truncate_page(inode, offset, len, 0);
+               } else {
+                       ret = 0;
+               }
                goto out_only_mutex;
        }
  
        /* zero back part of the first page */
        if (offset < ino_size) {
+               truncated_page = true;
                ret = btrfs_truncate_page(inode, offset, 0, 0);
                if (ret) {
                        mutex_unlock(&inode->i_mutex);
                if (!ret) {
                        /* zero the front end of the last page */
                        if (tail_start + tail_len < ino_size) {
+                               truncated_page = true;
                                ret = btrfs_truncate_page(inode,
                                                tail_start + tail_len, 0, 1);
                                if (ret)
        }
  
        if (lockend < lockstart) {
-               mutex_unlock(&inode->i_mutex);
-               return 0;
+               ret = 0;
+               goto out_only_mutex;
        }
  
        while (1) {
@@@ -2506,6 -2515,7 +2514,7 @@@ out_trans
  
        trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
+       updated_inode = true;
        btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty(root);
  out_free:
        unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                             &cached_state, GFP_NOFS);
  out_only_mutex:
+       if (!updated_inode && truncated_page && !ret && !err) {
+               /*
+                * If we only end up zeroing part of a page, we still need to
+                * update the inode item, so that all the time fields are
+                * updated as well as the necessary btrfs inode in memory fields
+                * for detecting, at fsync time, if the inode isn't yet in the
+                * log tree or it's there but not up to date.
+                */
+               trans = btrfs_start_transaction(root, 1);
+               if (IS_ERR(trans)) {
+                       err = PTR_ERR(trans);
+               } else {
+                       err = btrfs_update_inode(trans, root, inode);
+                       ret = btrfs_end_transaction(trans, root);
+               }
+       }
        mutex_unlock(&inode->i_mutex);
        if (ret && !err)
                err = ret;
diff --combined fs/btrfs/inode.c
@@@ -3670,6 -3670,7 +3670,6 @@@ cache_acl
        switch (inode->i_mode & S_IFMT) {
        case S_IFREG:
                inode->i_mapping->a_ops = &btrfs_aops;
 -              inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
                inode->i_fop = &btrfs_file_operations;
                inode->i_op = &btrfs_file_inode_operations;
        case S_IFLNK:
                inode->i_op = &btrfs_symlink_inode_operations;
                inode->i_mapping->a_ops = &btrfs_symlink_aops;
 -              inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
                break;
        default:
                inode->i_op = &btrfs_special_inode_operations;
@@@ -6165,6 -6167,7 +6165,6 @@@ static int btrfs_create(struct inode *d
        inode->i_fop = &btrfs_file_operations;
        inode->i_op = &btrfs_file_inode_operations;
        inode->i_mapping->a_ops = &btrfs_aops;
 -      inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
        if (err)
@@@ -7285,7 -7288,6 +7285,6 @@@ static int btrfs_get_blocks_direct(stru
            ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) &&
             em->block_start != EXTENT_MAP_HOLE)) {
                int type;
-               int ret;
                u64 block_start, orig_start, orig_block_len, ram_bytes;
  
                if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@@ -9278,6 -9280,7 +9277,6 @@@ static int btrfs_symlink(struct inode *
        inode->i_fop = &btrfs_file_operations;
        inode->i_op = &btrfs_file_inode_operations;
        inode->i_mapping->a_ops = &btrfs_aops;
 -      inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
        BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
  
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
  
        inode->i_op = &btrfs_symlink_inode_operations;
        inode->i_mapping->a_ops = &btrfs_symlink_aops;
 -      inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
        inode_set_bytes(inode, name_len);
        btrfs_i_size_write(inode, name_len);
        err = btrfs_update_inode(trans, root, inode);
@@@ -9532,6 -9536,7 +9531,6 @@@ static int btrfs_tmpfile(struct inode *
        inode->i_op = &btrfs_file_inode_operations;
  
        inode->i_mapping->a_ops = &btrfs_aops;
 -      inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
        BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
  
        ret = btrfs_init_inode_security(trans, inode, dir, NULL);
diff --combined fs/btrfs/transaction.c
@@@ -1052,9 -1052,6 +1052,6 @@@ static int update_cowonly_root(struct b
                ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
                if (ret)
                        return ret;
-               ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
-               if (ret)
-                       return ret;
        }
  
        return 0;
@@@ -2133,7 -2130,7 +2130,7 @@@ void btrfs_apply_pending_changes(struc
        unsigned long prev;
        unsigned long bit;
  
 -      prev = cmpxchg(&fs_info->pending_changes, 0, 0);
 +      prev = xchg(&fs_info->pending_changes, 0);
        if (!prev)
                return;
  
diff --combined fs/btrfs/tree-log.c
@@@ -1012,7 -1012,7 +1012,7 @@@ again
                base = btrfs_item_ptr_offset(leaf, path->slots[0]);
  
                while (cur_offset < item_size) {
-                       extref = (struct btrfs_inode_extref *)base + cur_offset;
+                       extref = (struct btrfs_inode_extref *)(base + cur_offset);
  
                        victim_name_len = btrfs_inode_extref_name_len(leaf, extref);
  
@@@ -2635,7 -2635,6 +2635,7 @@@ int btrfs_sync_log(struct btrfs_trans_h
        }
  
        if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) {
 +              blk_finish_plug(&plug);
                mutex_unlock(&log_root_tree->log_mutex);
                ret = root_log_ctx.log_ret;
                goto out;