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 da464a11474b..fe75247cf006 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; }; /*