From: Dmitry Monakhov <dmonak...@openvz.org> *Purpose: It is reasonable to announce fs related events via uevent infrastructure. This patch implement only ext4'th part, but IMHO this should be usefull for any generic filesystem.
Example: Runtime fs-error is pure async event. Currently there is no good way to handle this situation and inform user-space about this. *Implementation: Add uevent infrastructure similar to dm uevent FS_ACTION = {MOUNT|UMOUNT|REMOUNT|ERROR|FREEZE|UNFREEZE} FS_UUID FS_NAME FS_TYPE Signed-off-by: Dmitry Monakhov <dmonak...@openvz.org> [aryabinin: add error event, rh8 rebase] Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com> Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> --- fs/ext4/ext4.h | 11 +++++ fs/ext4/super.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 5f6fdd5514b2..70b3038fa0d1 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1625,6 +1625,8 @@ struct ext4_sb_info { /* Precomputed FS UUID checksum for seeding other checksums */ __u32 s_csum_seed; + bool s_err_event_sent; + /* Reclaim extents from extent status tree */ struct shrinker s_es_shrinker; struct list_head s_es_list; /* List of inodes with reclaimable extents */ @@ -3655,6 +3657,15 @@ extern int ext4_check_blockref(const char *, unsigned int, struct ext4_ext_path; struct ext4_extent; +enum ext4_event_type { + EXT4_UA_MOUNT, + EXT4_UA_UMOUNT, + EXT4_UA_REMOUNT, + EXT4_UA_ERROR, + EXT4_UA_FREEZE, + EXT4_UA_UNFREEZE, +}; + /* * Maximum number of logical blocks in a file; ext4_extent's ee_block is * __le32. diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 6cf2d3e0ed8f..597768497c42 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -424,6 +424,118 @@ static time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi) #define ext4_get_tstamp(es, tstamp) \ __ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) +static int ext4_uuid_valid(const u8 *uuid) +{ + int i; + + for (i = 0; i < 16; i++) { + if (uuid[i]) + return 1; + } + return 0; +} + +struct ext4_uevent { + struct super_block *sb; + enum ext4_event_type action; + struct work_struct work; +}; + +/** + * ext4_send_uevent - prepare and send uevent + * + * @sb: super_block + * @action: action type + * + */ +static void ext4_send_uevent_work(struct work_struct *w) +{ + struct ext4_uevent *e = container_of(w, struct ext4_uevent, work); + struct super_block *sb = e->sb; + struct kobj_uevent_env *env; + const u8 *uuid = EXT4_SB(sb)->s_es->s_uuid; + enum kobject_action kaction = KOBJ_CHANGE; + int ret; + + env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); + if (!env){ + kfree(e); + return; + } + ret = add_uevent_var(env, "FS_TYPE=%s", sb->s_type->name); + if (ret) + goto out; + ret = add_uevent_var(env, "FS_NAME=%s", sb->s_id); + if (ret) + goto out; + + if (ext4_uuid_valid(uuid)) { + ret = add_uevent_var(env, "UUID=%pUB", uuid); + if (ret) + goto out; + } + + switch (e->action) { + case EXT4_UA_MOUNT: + kaction = KOBJ_ONLINE; + ret = add_uevent_var(env, "FS_ACTION=%s", "MOUNT"); + break; + case EXT4_UA_UMOUNT: + kaction = KOBJ_OFFLINE; + ret = add_uevent_var(env, "FS_ACTION=%s", "UMOUNT"); + break; + case EXT4_UA_REMOUNT: + ret = add_uevent_var(env, "FS_ACTION=%s", "REMOUNT"); + break; + case EXT4_UA_ERROR: + ret = add_uevent_var(env, "FS_ACTION=%s", "ERROR"); + break; + case EXT4_UA_FREEZE: + ret = add_uevent_var(env, "FS_ACTION=%s", "FREEZE"); + break; + case EXT4_UA_UNFREEZE: + ret = add_uevent_var(env, "FS_ACTION=%s", "UNFREEZE"); + break; + default: + ret = -EINVAL; + } + if (ret) + goto out; + ret = kobject_uevent_env(&(EXT4_SB(sb)->s_kobj), kaction, env->envp); +out: + kfree(env); + kfree(e); +} + +/** + * ext4_send_uevent - prepare and schedule event submission + * + * @sb: super_block + * @action: action type + * + */ +void ext4_send_uevent(struct super_block *sb, enum ext4_event_type action) +{ + struct ext4_uevent *e; + + /* + * May happen if called from ext4_put_super() -> __ext4_abort() + * -> ext4_send_uevent() + */ + if (!EXT4_SB(sb)->rsv_conversion_wq) + return; + + e = kzalloc(sizeof(*e), GFP_NOIO); + if (!e) + return; + + e->sb = sb; + e->action = action; + INIT_WORK(&e->work, ext4_send_uevent_work); + queue_work(EXT4_SB(sb)->rsv_conversion_wq, &e->work); +} + + /* * The del_gendisk() function uninitializes the disk-specific data * structures, including the bdi structure, without telling anyone @@ -644,6 +756,9 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error, journal_t *journal = EXT4_SB(sb)->s_journal; bool continue_fs = !force_ro && test_opt(sb, ERRORS_CONT); + if (!xchg(&EXT4_SB(sb)->s_err_event_sent, 1)) + ext4_send_uevent(sb, EXT4_UA_ERROR); + EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; if (test_opt(sb, WARN_ON_ERROR)) WARN_ON_ONCE(1); @@ -1171,11 +1286,13 @@ static void ext4_put_super(struct super_block *sb) int aborted = 0; int i, err; + ext4_send_uevent(sb, EXT4_UA_UMOUNT); ext4_unregister_li_request(sb); ext4_quota_off_umount(sb); flush_work(&sbi->s_error_work); destroy_workqueue(sbi->rsv_conversion_wq); + sbi->rsv_conversion_wq = NULL; /* * Unregister sysfs before destroying jbd2 journal. @@ -5206,6 +5323,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) atomic_set(&sbi->s_warning_count, 0); atomic_set(&sbi->s_msg_count, 0); + ext4_send_uevent(sb, EXT4_UA_MOUNT); kfree(orig_data); return 0; @@ -5853,8 +5971,10 @@ static int ext4_freeze(struct super_block *sb) int error = 0; journal_t *journal; - if (sb_rdonly(sb)) + if (sb_rdonly(sb)) { + ext4_send_uevent(sb, EXT4_UA_FREEZE); return 0; + } journal = EXT4_SB(sb)->s_journal; @@ -5879,6 +5999,10 @@ static int ext4_freeze(struct super_block *sb) if (journal) /* we rely on upper layer to stop further updates */ jbd2_journal_unlock_updates(journal); + + if (!error) + ext4_send_uevent(sb, EXT4_UA_FREEZE); + return error; } @@ -5888,6 +6012,8 @@ static int ext4_freeze(struct super_block *sb) */ static int ext4_unfreeze(struct super_block *sb) { + ext4_send_uevent(sb, EXT4_UA_UNFREEZE); + if (sb_rdonly(sb) || ext4_forced_shutdown(EXT4_SB(sb))) return 0; @@ -6222,6 +6348,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) #endif if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb)) ext4_stop_mmpd(sbi); + ext4_send_uevent(sb, EXT4_UA_REMOUNT); kfree(orig_data); return err; } _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel