Merge branch 'for-linus-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull btrfs updates from Chris Mason:
 "This has our merge window series of cleanups and fixes.  These target
  a wide range of issues, but do include some important fixes for
  qgroups, O_DIRECT, and fsync handling.  Jeff Mahoney moved around a
  few definitions to make them easier for userland to consume.

  Also whiteout support is included now that issues with overlayfs have
  been cleared up.

  I have one more fix pending for page faults during btrfs_copy_from_user,
  but I wanted to get this bulk out the door first"

* 'for-linus-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (90 commits)
  btrfs: fix memory leak during RAID 5/6 device replacement
  Btrfs: add semaphore to synchronize direct IO writes with fsync
  Btrfs: fix race between block group relocation and nocow writes
  Btrfs: fix race between fsync and direct IO writes for prealloc extents
  Btrfs: fix number of transaction units for renames with whiteout
  Btrfs: pin logs earlier when doing a rename exchange operation
  Btrfs: unpin logs if rename exchange operation fails
  Btrfs: fix inode leak on failure to setup whiteout inode in rename
  btrfs: add support for RENAME_EXCHANGE and RENAME_WHITEOUT
  Btrfs: pin log earlier when renaming
  Btrfs: unpin log if rename operation fails
  Btrfs: don't do unnecessary delalloc flushes when relocating
  Btrfs: don't wait for unrelated IO to finish before relocation
  Btrfs: fix empty symlink after creating symlink and fsync parent dir
  Btrfs: fix for incorrect directory entries after fsync log replay
  btrfs: build fixup for qgroup_account_snapshot
  btrfs: qgroup: Fix qgroup accounting when creating snapshot
  Btrfs: fix fspath error deallocation
  btrfs: make find_workspace warn if there are no workspaces
  btrfs: make find_workspace always succeed
  ...
This commit is contained in:
Linus Torvalds
2016-05-21 10:49:22 -07:00
30 changed files with 2685 additions and 1801 deletions

View File

@@ -4141,6 +4141,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
INIT_LIST_HEAD(&extents);
down_write(&BTRFS_I(inode)->dio_sem);
write_lock(&tree->lock);
test_gen = root->fs_info->last_trans_committed;
@@ -4169,13 +4170,20 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
}
list_sort(NULL, &extents, extent_cmp);
/*
* Collect any new ordered extents within the range. This is to
* prevent logging file extent items without waiting for the disk
* location they point to being written. We do this only to deal
* with races against concurrent lockless direct IO writes.
*/
btrfs_get_logged_extents(inode, logged_list, start, end);
/*
* Some ordered extents started by fsync might have completed
* before we could collect them into the list logged_list, which
* means they're gone, not in our logged_list nor in the inode's
* ordered tree. We want the application/user space to know an
* error happened while attempting to persist file data so that
* it can take proper action. If such error happened, we leave
* without writing to the log tree and the fsync must report the
* file data write error and not commit the current transaction.
*/
ret = btrfs_inode_check_errors(inode);
if (ret)
ctx->io_err = ret;
process:
while (!list_empty(&extents)) {
em = list_entry(extents.next, struct extent_map, list);
@@ -4202,6 +4210,7 @@ process:
}
WARN_ON(!list_empty(&extents));
write_unlock(&tree->lock);
up_write(&BTRFS_I(inode)->dio_sem);
btrfs_release_path(path);
return ret;
@@ -4622,23 +4631,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
mutex_lock(&BTRFS_I(inode)->log_mutex);
/*
* Collect ordered extents only if we are logging data. This is to
* ensure a subsequent request to log this inode in LOG_INODE_ALL mode
* will process the ordered extents if they still exists at the time,
* because when we collect them we test and set for the flag
* BTRFS_ORDERED_LOGGED to prevent multiple log requests to process the
* same ordered extents. The consequence for the LOG_INODE_ALL log mode
* not processing the ordered extents is that we end up logging the
* corresponding file extent items, based on the extent maps in the
* inode's extent_map_tree's modified_list, without logging the
* respective checksums (since the may still be only attached to the
* ordered extents and have not been inserted in the csum tree by
* btrfs_finish_ordered_io() yet).
*/
if (inode_only == LOG_INODE_ALL)
btrfs_get_logged_extents(inode, &logged_list, start, end);
/*
* a brute force approach to making sure we get the most uptodate
* copies of everything.
@@ -4846,21 +4838,6 @@ log_extents:
goto out_unlock;
}
if (fast_search) {
/*
* Some ordered extents started by fsync might have completed
* before we collected the ordered extents in logged_list, which
* means they're gone, not in our logged_list nor in the inode's
* ordered tree. We want the application/user space to know an
* error happened while attempting to persist file data so that
* it can take proper action. If such error happened, we leave
* without writing to the log tree and the fsync must report the
* file data write error and not commit the current transaction.
*/
err = btrfs_inode_check_errors(inode);
if (err) {
ctx->io_err = err;
goto out_unlock;
}
ret = btrfs_log_changed_extents(trans, root, inode, dst_path,
&logged_list, ctx, start, end);
if (ret) {
@@ -5158,7 +5135,7 @@ process_leaf:
}
ctx->log_new_dentries = false;
if (type == BTRFS_FT_DIR)
if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK)
log_mode = LOG_INODE_ALL;
btrfs_release_path(path);
ret = btrfs_log_inode(trans, root, di_inode,
@@ -5278,11 +5255,16 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
if (IS_ERR(dir_inode))
continue;
if (ctx)
ctx->log_new_dentries = false;
ret = btrfs_log_inode(trans, root, dir_inode,
LOG_INODE_ALL, 0, LLONG_MAX, ctx);
if (!ret &&
btrfs_must_commit_transaction(trans, dir_inode))
ret = 1;
if (!ret && ctx && ctx->log_new_dentries)
ret = log_new_dir_dentries(trans, root,
dir_inode, ctx);
iput(dir_inode);
if (ret)
goto out;
@@ -5519,7 +5501,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
ret = walk_log_tree(trans, log_root_tree, &wc);
if (ret) {
btrfs_std_error(fs_info, ret, "Failed to pin buffers while "
btrfs_handle_fs_error(fs_info, ret, "Failed to pin buffers while "
"recovering log root tree.");
goto error;
}
@@ -5533,7 +5515,7 @@ again:
ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
if (ret < 0) {
btrfs_std_error(fs_info, ret,
btrfs_handle_fs_error(fs_info, ret,
"Couldn't find tree log root.");
goto error;
}
@@ -5551,7 +5533,7 @@ again:
log = btrfs_read_fs_root(log_root_tree, &found_key);
if (IS_ERR(log)) {
ret = PTR_ERR(log);
btrfs_std_error(fs_info, ret,
btrfs_handle_fs_error(fs_info, ret,
"Couldn't read tree log root.");
goto error;
}
@@ -5566,7 +5548,7 @@ again:
free_extent_buffer(log->node);
free_extent_buffer(log->commit_root);
kfree(log);
btrfs_std_error(fs_info, ret, "Couldn't read target root "
btrfs_handle_fs_error(fs_info, ret, "Couldn't read target root "
"for tree log recovery.");
goto error;
}
@@ -5652,11 +5634,9 @@ void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans,
* into the file. When the file is logged we check it and
* don't log the parents if the file is fully on disk.
*/
if (S_ISREG(inode->i_mode)) {
mutex_lock(&BTRFS_I(inode)->log_mutex);
BTRFS_I(inode)->last_unlink_trans = trans->transid;
mutex_unlock(&BTRFS_I(inode)->log_mutex);
}
mutex_lock(&BTRFS_I(inode)->log_mutex);
BTRFS_I(inode)->last_unlink_trans = trans->transid;
mutex_unlock(&BTRFS_I(inode)->log_mutex);
/*
* if this directory was already logged any new