From 36d8598e9355503844cc5cf876feeb754dc6ac6e Mon Sep 17 00:00:00 2001 From: Shiyong Li Date: Fri, 8 Dec 2017 17:36:20 -0800 Subject: [PATCH] fs/exfat: send uevnet from workqueue We can not send uevent directly because it might be called from atomic context. Change-Id: I384a7f197b22b1fcb8d068c98908e4fa5a1d3b82 Signed-off-by: Lianwei Wang Signed-off-by: Shiyong Li Reviewed-on: https://gerrit.mot.com/1102182 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Igor Kovalenko Submit-Approved: Jira Key Reviewed-on: https://gerrit.mot.com/1276883 Reviewed-by: Hua Tan --- fs/exfat/exfat_core.c | 4 +++- fs/exfat/exfat_super.c | 16 ++++++++++++++++ fs/exfat/exfat_super.h | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/exfat/exfat_core.c b/fs/exfat/exfat_core.c index 71c75e1c9367..248af20ea32f 100644 --- a/fs/exfat/exfat_core.c +++ b/fs/exfat/exfat_core.c @@ -1754,12 +1754,14 @@ void fs_sync(struct super_block *sb, s32 do_sync) void fs_error(struct super_block *sb) { struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; + struct exfat_sb_info *sbi = EXFAT_SB(sb); if (opts->errors == EXFAT_ERRORS_PANIC) panic("[EXFAT] Filesystem panic from previous error\n"); else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) { sb->s_flags |= MS_RDONLY; - kobject_uevent(&disk_to_dev(sb->s_bdev->bd_disk)->kobj, KOBJ_CHANGE); + if (sbi && !sbi->disable_uevent) + schedule_work(&sbi->uevent_work); printk(KERN_ERR "[EXFAT] Filesystem has been set read-only\n"); } } diff --git a/fs/exfat/exfat_super.c b/fs/exfat/exfat_super.c index 53e21a3db873..2e041cdede7e 100644 --- a/fs/exfat/exfat_super.c +++ b/fs/exfat/exfat_super.c @@ -72,6 +72,7 @@ #include #include #include +#include #include #include @@ -132,6 +133,14 @@ static time_t accum_days_in_year[] = { static void _exfat_truncate(struct inode *inode, loff_t old_size); +static void exfat_sbi_uevent_work(struct work_struct *work) +{ + struct exfat_sb_info *sbi = container_of(work, struct exfat_sb_info, + uevent_work); + + kobject_uevent(&disk_to_dev(sbi->sb->s_bdev->bd_disk)->kobj, KOBJ_CHANGE); +} + /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec *ts, DATE_TIME_T *tp) @@ -2057,6 +2066,10 @@ static void exfat_free_super(struct exfat_sb_info *sbi) static void exfat_put_super(struct super_block *sb) { struct exfat_sb_info *sbi = EXFAT_SB(sb); + + sbi->disable_uevent = 1; + cancel_work_sync(&sbi->uevent_work); + if (__is_sb_dirty(sb)) exfat_write_super(sb); @@ -2480,6 +2493,9 @@ static int exfat_fill_super(struct super_block *sb, void *data, int silent) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) mutex_init(&sbi->s_lock); #endif + sbi->sb = sb; + INIT_WORK(&sbi->uevent_work, exfat_sbi_uevent_work); + sb->s_fs_info = sbi; sb->s_flags |= MS_NODIRATIME; sb->s_magic = EXFAT_SUPER_MAGIC; diff --git a/fs/exfat/exfat_super.h b/fs/exfat/exfat_super.h index f647daa41b26..0e716074b75a 100644 --- a/fs/exfat/exfat_super.h +++ b/fs/exfat/exfat_super.h @@ -91,6 +91,9 @@ struct exfat_sb_info { #ifdef CONFIG_EXFAT_KERNEL_DEBUG long debug_flags; #endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + struct super_block *sb; + struct work_struct uevent_work; + int disable_uevent; }; /* -- 2.20.1