From: Dmitry Monakhov <dmonak...@openvz.org> *Purpose: It is reasonable to annaunce 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> --- fs/ext4/ext4.h | 11 +++++ fs/ext4/super.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 028832d858fc..228492c9518f 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1498,6 +1498,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 */ @@ -3119,6 +3121,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 7fc5ad243953..3cc979825ec8 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -354,6 +354,117 @@ 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); +} + static void __save_error_info(struct super_block *sb, const char *func, unsigned int line) { @@ -453,6 +564,9 @@ static bool system_going_down(void) static void ext4_handle_error(struct super_block *sb) { + if (!xchg(&EXT4_SB(sb)->s_err_event_sent, 1)) + ext4_send_uevent(sb, EXT4_UA_ERROR); + if (test_opt(sb, WARN_ON_ERROR)) WARN_ON_ONCE(1); @@ -972,10 +1086,12 @@ 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); destroy_workqueue(sbi->rsv_conversion_wq); + sbi->rsv_conversion_wq = NULL; if (sbi->s_journal) { aborted = is_journal_aborted(sbi->s_journal); @@ -4523,6 +4639,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ratelimit_state_init(&sbi->s_warning_ratelimit_state, 5 * HZ, 10); ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10); + ext4_send_uevent(sb, EXT4_UA_MOUNT); kfree(orig_data); return 0; @@ -5081,8 +5198,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; @@ -5107,6 +5226,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; } @@ -5116,6 +5239,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; @@ -5394,6 +5519,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME); ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data); + ext4_send_uevent(sb, EXT4_UA_REMOUNT); kfree(orig_data); return 0; -- 2.26.2 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel