[Devel] ext4: send abort uevent on ext4 journal abort.

Submitted by Dmitry Monakhov on July 25, 2017, 8:28 a.m.

Details

Message ID 1500971283-20159-1-git-send-email-dmonakhov@openvz.org
State New
Series "ext4: send abort uevent on ext4 journal abort."
Headers show

Commit Message

Dmitry Monakhov July 25, 2017, 8:28 a.m.
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"

https://jira.sw.ru/browse/PSBM-68848
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
---
 fs/ext4/ext4.h  |  2 ++
 fs/ext4/super.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 61 insertions(+), 10 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index ce60718..1633538 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1357,6 +1357,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;
@@ -2765,6 +2766,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 088313b..0016c94 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,
@@ -470,9 +508,13 @@  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)
+		
+		if (journal) 
 			jbd2_journal_abort(journal, -EIO);
 	}
 	if (test_opt(sb, ERRORS_RO)) {
@@ -664,6 +706,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 +900,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);

Comments

Andrey Ryabinin July 25, 2017, 8:57 a.m.
On 07/25/2017 11:28 AM, Dmitry Monakhov wrote:
> It can be any workqueue I've pick rsv_conversion_wq because it is
> already exists.
> 

Ugh, why not system_wq?