[Devel] [PATCH RHEL7 COMMIT] ext4: send abort uevent on ext4 journal abort

Konstantin Khorenko khorenko at virtuozzo.com
Tue Jul 25 15:18:41 MSK 2017


The commit is pushed to "branch-rh7-3.10.0-514.26.1.vz7.33.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-514.26.1.vz7.33.16
------>
commit d196748d788fc94fb261d170b999f168ee520a06
Author: Dmitry Monakhov <dmonakhov at openvz.org>
Date:   Tue Jul 25 16:18:41 2017 +0400

    ext4: send abort uevent on ext4 journal abort
    
    Currenlty error from device result in ext4_abort, but uevent not generated because
    ext4_abort() caller's context do not allow GFP_KERNEL memory allocation.
    Let's relax submission context requirement and deffer actual uevent submission
    to work_queue.  It can be any workqueue I've pick rsv_conversion_wq because it is
    already exists.
    
    New uevent "ABORT" is introduced.
    
    https://jira.sw.ru/browse/PSBM-68848
    
    Signed-off-by: Dmitry Monakhov <dmonakhov at openvz.org>
    
    khorenko@: "system_wq" does not fit here because at the moment of
    work execution sb can be already destroyed.
    "EXT4_SB(sb)->rsv_conversion_wq" is flushed before sb is destroyed.
---
 fs/ext4/ext4.h  |  2 ++
 fs/ext4/super.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 1f6eec5..d5a4386 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1358,6 +1358,7 @@ struct ext4_sb_info {
 	__u32 s_csum_seed;
 
 	bool s_err_event_sent;
+	bool s_abrt_event_sent;
 
 	/* Reclaim extents from extent status tree */
 	struct shrinker s_es_shrinker;
@@ -2766,6 +2767,7 @@ enum ext4_event_type {
      EXT4_UA_UMOUNT,
      EXT4_UA_REMOUNT,
      EXT4_UA_ERROR,
+     EXT4_UA_ABORT,
      EXT4_UA_FREEZE,
      EXT4_UA_UNFREEZE,
 };
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 00aa685..6b79b4e 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -312,6 +312,12 @@ static int ext4_uuid_valid(const u8 *uuid)
 	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
  *
@@ -319,17 +325,20 @@ static int ext4_uuid_valid(const u8 *uuid)
  * @action:		action type
  *
  */
-int ext4_send_uevent(struct super_block *sb, enum ext4_event_type action)
+static void ext4_send_uevent_work(struct work_struct *w)
 {
-	int ret;
+	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 = sb->s_uuid;
 	enum kobject_action kaction = KOBJ_CHANGE;
+	int ret;
 
 	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
-	if (!env)
-		return -ENOMEM;
-
+	if (!env){
+		kfree(e);
+		return;
+	}
 	ret = add_uevent_var(env, "FS_TYPE=%s", sb->s_type->name);
 	if (ret)
 		goto out;
@@ -343,7 +352,7 @@ int ext4_send_uevent(struct super_block *sb, enum ext4_event_type action)
 			goto out;
 	}
 
-	switch (action) {
+	switch (e->action) {
 	case EXT4_UA_MOUNT:
 		kaction = KOBJ_ONLINE;
 		ret = add_uevent_var(env, "FS_ACTION=%s", "MOUNT");
@@ -358,6 +367,9 @@ int ext4_send_uevent(struct super_block *sb, enum ext4_event_type action)
 	case EXT4_UA_ERROR:
 		ret = add_uevent_var(env, "FS_ACTION=%s", "ERROR");
 		break;
+	case EXT4_UA_ABORT:
+		ret = add_uevent_var(env, "FS_ACTION=%s", "ABORT");
+		break;
 	case EXT4_UA_FREEZE:
 		ret = add_uevent_var(env, "FS_ACTION=%s", "FREEZE");
 		break;
@@ -372,7 +384,33 @@ int ext4_send_uevent(struct super_block *sb, enum ext4_event_type action)
 	ret = kobject_uevent_env(&(EXT4_SB(sb)->s_kobj), kaction, env->envp);
 out:
 	kfree(env);
-	return ret;
+	kfree(e);
+}
+
+/**
+ * ext4_send_uevent - prepare and schedule event submission
+ *
+ * @sb:		super_block
+ * @action:		action type
+ *
+ */
+int ext4_send_uevent(struct super_block *sb, enum ext4_event_type action)
+{
+	struct ext4_uevent *e;
+
+	smp_rmb();
+	if (!EXT4_SB(sb)->rsv_conversion_wq)
+		return -EPROTO;
+
+	e = kzalloc(sizeof(*e), GFP_NOIO);
+	if (!e)
+		return -ENOMEM;
+
+	e->sb = sb;
+	e->action = action;
+	INIT_WORK(&e->work, ext4_send_uevent_work);
+	queue_work(EXT4_SB(sb)->rsv_conversion_wq, &e->work);
+	return 0;
 }
 
 static void __save_error_info(struct super_block *sb, const char *func,
@@ -471,6 +509,9 @@ static void ext4_handle_error(struct super_block *sb)
 	if (!test_opt(sb, ERRORS_CONT)) {
 		journal_t *journal = EXT4_SB(sb)->s_journal;
 
+		if (!xchg(&EXT4_SB(sb)->s_abrt_event_sent, 1))
+			ext4_send_uevent(sb, EXT4_UA_ABORT);
+
 		EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
 		if (journal)
 			jbd2_journal_abort(journal, -EIO);
@@ -664,6 +705,10 @@ void __ext4_abort(struct super_block *sb, const char *function,
 
 	if ((sb->s_flags & MS_RDONLY) == 0) {
 		ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
+
+		if (!xchg(&EXT4_SB(sb)->s_abrt_event_sent, 1))
+			ext4_send_uevent(sb, EXT4_UA_ABORT);
+
 		EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
 		/*
 		 * Make sure updated value of ->s_mount_flags will be visible
@@ -854,14 +899,17 @@ static void ext4_put_super(struct super_block *sb)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	struct ext4_super_block *es = sbi->s_es;
+	struct workqueue_struct * rsv_conversion_wq = sbi->rsv_conversion_wq;
 	int i, err;
 
 	ext4_send_uevent(sb, EXT4_UA_UMOUNT);
 	ext4_unregister_li_request(sb);
 	dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
 
-	flush_workqueue(sbi->rsv_conversion_wq);
-	destroy_workqueue(sbi->rsv_conversion_wq);
+	sbi->rsv_conversion_wq = NULL;
+	smp_wmb();
+	flush_workqueue(rsv_conversion_wq);
+	destroy_workqueue(rsv_conversion_wq);
 
 	if (sbi->s_journal) {
 		err = jbd2_journal_destroy(sbi->s_journal);


More information about the Devel mailing list