mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
![Qu Wenruo](/assets/img/avatar_default.png)
[BUG] Since the introduction of per-fs feature sysfs interface (/sys/fs/btrfs/<UUID>/features/), the content of that directory is never updated. Thus for the following case, that directory will not show the new features like RAID56: # mkfs.btrfs -f $dev1 $dev2 $dev3 # mount $dev1 $mnt # btrfs balance start -f -mconvert=raid5 $mnt # ls /sys/fs/btrfs/$uuid/features/ extended_iref free_space_tree no_holes skinny_metadata While after unmount and mount, we got the correct features: # umount $mnt # mount $dev1 $mnt # ls /sys/fs/btrfs/$uuid/features/ extended_iref free_space_tree no_holes raid56 skinny_metadata [CAUSE] Because we never really try to update the content of per-fs features/ directory. We had an attempt to update the features directory dynamically in commit14e46e0495
("btrfs: synchronize incompat feature bits with sysfs files"), but unfortunately it get reverted in commite410e34fad
("Revert "btrfs: synchronize incompat feature bits with sysfs files""). The problem in the original patch is, in the context of btrfs_create_chunk(), we can not afford to update the sysfs group. The exported but never utilized function, btrfs_sysfs_feature_update() is the leftover of such attempt. As even if we go sysfs_update_group(), new files will need extra memory allocation, and we have no way to specify the sysfs update to go GFP_NOFS. [FIX] This patch will address the old problem by doing asynchronous sysfs update in the cleaner thread. This involves the following changes: - Make __btrfs_(set|clear)_fs_(incompat|compat_ro) helpers to set BTRFS_FS_FEATURE_CHANGED flag when needed - Update btrfs_sysfs_feature_update() to use sysfs_update_group() And drop unnecessary arguments. - Call btrfs_sysfs_feature_update() in cleaner_kthread If we have the BTRFS_FS_FEATURE_CHANGED flag set. - Wake up cleaner_kthread in btrfs_commit_transaction if we have BTRFS_FS_FEATURE_CHANGED flag By this, all the previously dangerous call sites like btrfs_create_chunk() need no new changes, as above helpers would have already set the BTRFS_FS_FEATURE_CHANGED flag. The real work happens at cleaner_kthread, thus we pay the cost of delaying the update to sysfs directory, but the delayed time should be small enough that end user can not distinguish though it might get delayed if the cleaner thread is busy with removing subvolumes or defrag. CC: stable@vger.kernel.org # 4.14+ Reviewed-by: Anand Jain <anand.jain@oracle.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
42 lines
1.6 KiB
C
42 lines
1.6 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
#ifndef BTRFS_SYSFS_H
|
|
#define BTRFS_SYSFS_H
|
|
|
|
#include <linux/kobject.h>
|
|
|
|
enum btrfs_feature_set {
|
|
FEAT_COMPAT,
|
|
FEAT_COMPAT_RO,
|
|
FEAT_INCOMPAT,
|
|
FEAT_MAX
|
|
};
|
|
|
|
char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags);
|
|
const char *btrfs_feature_set_name(enum btrfs_feature_set set);
|
|
int btrfs_sysfs_add_device(struct btrfs_device *device);
|
|
void btrfs_sysfs_remove_device(struct btrfs_device *device);
|
|
int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs);
|
|
void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs);
|
|
void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices);
|
|
void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info);
|
|
void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action);
|
|
|
|
int __init btrfs_init_sysfs(void);
|
|
void __cold btrfs_exit_sysfs(void);
|
|
int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info);
|
|
void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info);
|
|
void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache);
|
|
int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
|
|
struct btrfs_space_info *space_info);
|
|
void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info);
|
|
void btrfs_sysfs_update_devid(struct btrfs_device *device);
|
|
|
|
int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
|
|
struct btrfs_qgroup *qgroup);
|
|
void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info);
|
|
int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info);
|
|
void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
|
|
struct btrfs_qgroup *qgroup);
|
|
|
|
#endif
|