[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