Commit d532dd10 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-6.2-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "Another batch of fixes, dealing with fallouts from 6.1 reported by
  users:

   - tree-log fixes:
       - fix directory logging due to race with concurrent index key
         deletion
       - fix missing error handling when logging directory items
       - handle case of conflicting inodes being added to the log
       - remove transaction aborts for not so serious errors

   - fix qgroup accounting warning when rescan can be started at time
     with temporarily disable accounting

   - print more specific errors to system log when device scan ioctl
     fails

   - disable space overcommit for ZNS devices, causing heavy performance
     drop"

* tag 'for-6.2-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: do not abort transaction on failure to update log root
  btrfs: do not abort transaction on failure to write log tree when syncing log
  btrfs: add missing setup of log for full commit at add_conflicting_inode()
  btrfs: fix directory logging due to race with concurrent index key deletion
  btrfs: fix missing error handling when logging directory items
  btrfs: zoned: enable metadata over-commit for non-ZNS setup
  btrfs: qgroup: do not warn on record without old_roots populated
  btrfs: add extra error messages to cover non-ENOMEM errors from device_add_list()
parents 5dc4c995 09e44868
......@@ -367,7 +367,14 @@ static int csum_one_extent_buffer(struct extent_buffer *eb)
btrfs_print_tree(eb, 0);
btrfs_err(fs_info, "block=%llu write time tree block corruption detected",
eb->start);
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
/*
* Be noisy if this is an extent buffer from a log tree. We don't abort
* a transaction in case there's a bad log tree extent buffer, we just
* fallback to a transaction commit. Still we want to know when there is
* a bad log tree extent buffer, as that may signal a bug somewhere.
*/
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG) ||
btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID);
return ret;
}
......
......@@ -119,6 +119,12 @@ enum {
/* Indicate that we want to commit the transaction. */
BTRFS_FS_NEED_TRANS_COMMIT,
/*
* Indicate metadata over-commit is disabled. This is set when active
* zone tracking is needed.
*/
BTRFS_FS_NO_OVERCOMMIT,
#if BITS_PER_LONG == 32
/* Indicate if we have error/warn message printed on 32bit systems */
BTRFS_FS_32BIT_ERROR,
......
......@@ -2765,9 +2765,19 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
/*
* Old roots should be searched when inserting qgroup
* extent record
* extent record.
*
* But for INCONSISTENT (NO_ACCOUNTING) -> rescan case,
* we may have some record inserted during
* NO_ACCOUNTING (thus no old_roots populated), but
* later we start rescan, which clears NO_ACCOUNTING,
* leaving some inserted records without old_roots
* populated.
*
* Those cases are rare and should not cause too much
* time spent during commit_transaction().
*/
if (WARN_ON(!record->old_roots)) {
if (!record->old_roots) {
/* Search commit root to find old_roots */
ret = btrfs_find_all_roots(&ctx, false);
if (ret < 0)
......
......@@ -407,7 +407,8 @@ int btrfs_can_overcommit(struct btrfs_fs_info *fs_info,
return 0;
used = btrfs_space_info_used(space_info, true);
if (btrfs_is_zoned(fs_info) && (space_info->flags & BTRFS_BLOCK_GROUP_METADATA))
if (test_bit(BTRFS_FS_NO_OVERCOMMIT, &fs_info->flags) &&
(space_info->flags & BTRFS_BLOCK_GROUP_METADATA))
avail = 0;
else
avail = calc_available_free_space(fs_info, space_info, flush);
......
......@@ -2980,7 +2980,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
ret = 0;
if (ret) {
blk_finish_plug(&plug);
btrfs_abort_transaction(trans, ret);
btrfs_set_log_full_commit(trans);
mutex_unlock(&root->log_mutex);
goto out;
......@@ -3045,15 +3044,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
blk_finish_plug(&plug);
btrfs_set_log_full_commit(trans);
if (ret != -ENOSPC) {
btrfs_abort_transaction(trans, ret);
mutex_unlock(&log_root_tree->log_mutex);
goto out;
}
if (ret != -ENOSPC)
btrfs_err(fs_info,
"failed to update log for root %llu ret %d",
root->root_key.objectid, ret);
btrfs_wait_tree_log_extents(log, mark);
mutex_unlock(&log_root_tree->log_mutex);
ret = BTRFS_LOG_FORCE_COMMIT;
goto out;
}
......@@ -3112,7 +3108,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
goto out_wake_log_root;
} else if (ret) {
btrfs_set_log_full_commit(trans);
btrfs_abort_transaction(trans, ret);
mutex_unlock(&log_root_tree->log_mutex);
goto out_wake_log_root;
}
......@@ -3826,7 +3821,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
path->slots[0]);
if (tmp.type == BTRFS_DIR_INDEX_KEY)
last_old_dentry_offset = tmp.offset;
} else if (ret < 0) {
err = ret;
}
goto done;
}
......@@ -3846,19 +3844,34 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
*/
if (tmp.type == BTRFS_DIR_INDEX_KEY)
last_old_dentry_offset = tmp.offset;
} else if (ret < 0) {
err = ret;
goto done;
}
btrfs_release_path(path);
/*
* Find the first key from this transaction again. See the note for
* log_new_dir_dentries, if we're logging a directory recursively we
* won't be holding its i_mutex, which means we can modify the directory
* while we're logging it. If we remove an entry between our first
* search and this search we'll not find the key again and can just
* bail.
* Find the first key from this transaction again or the one we were at
* in the loop below in case we had to reschedule. We may be logging the
* directory without holding its VFS lock, which happen when logging new
* dentries (through log_new_dir_dentries()) or in some cases when we
* need to log the parent directory of an inode. This means a dir index
* key might be deleted from the inode's root, and therefore we may not
* find it anymore. If we can't find it, just move to the next key. We
* can not bail out and ignore, because if we do that we will simply
* not log dir index keys that come after the one that was just deleted
* and we can end up logging a dir index range that ends at (u64)-1
* (@last_offset is initialized to that), resulting in removing dir
* entries we should not remove at log replay time.
*/
search:
ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
if (ret > 0)
ret = btrfs_next_item(root, path);
if (ret < 0)
err = ret;
/* If ret is 1, there are no more keys in the inode's root. */
if (ret != 0)
goto done;
......@@ -5580,8 +5593,10 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
* LOG_INODE_EXISTS mode) and slow down other fsyncs or transaction
* commits.
*/
if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES)
if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES) {
btrfs_set_log_full_commit(trans);
return BTRFS_LOG_FORCE_COMMIT;
}
inode = btrfs_iget(root->fs_info->sb, ino, root);
/*
......
......@@ -768,8 +768,11 @@ static noinline struct btrfs_device *device_list_add(const char *path,
BTRFS_SUPER_FLAG_CHANGING_FSID_V2);
error = lookup_bdev(path, &path_devt);
if (error)
if (error) {
btrfs_err(NULL, "failed to lookup block device for path %s: %d",
path, error);
return ERR_PTR(error);
}
if (fsid_change_in_progress) {
if (!has_metadata_uuid)
......@@ -836,6 +839,9 @@ static noinline struct btrfs_device *device_list_add(const char *path,
unsigned int nofs_flag;
if (fs_devices->opened) {
btrfs_err(NULL,
"device %s belongs to fsid %pU, and the fs is already mounted",
path, fs_devices->fsid);
mutex_unlock(&fs_devices->device_list_mutex);
return ERR_PTR(-EBUSY);
}
......@@ -905,6 +911,9 @@ static noinline struct btrfs_device *device_list_add(const char *path,
* generation are equal.
*/
mutex_unlock(&fs_devices->device_list_mutex);
btrfs_err(NULL,
"device %s already registered with a higher generation, found %llu expect %llu",
path, found_transid, device->generation);
return ERR_PTR(-EEXIST);
}
......
......@@ -539,6 +539,8 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
}
atomic_set(&zone_info->active_zones_left,
max_active_zones - nactive);
/* Overcommit does not work well with active zone tacking. */
set_bit(BTRFS_FS_NO_OVERCOMMIT, &fs_info->flags);
}
/* Validate superblock log */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment