Add mechnism to optionally notify userspace about fs errors with uevents associated with fs kobject's attribute: /sys/fs/fat/<part_bdev>/fs_fault uevent's type is KOBJ_CHANGE, uevent's environment variable FS_FAULT=1. Signed-off-by: Denis Karpov <ext-denis.2.karpov@xxxxxxxxx> --- fs/fat/fat.h | 6 +++--- fs/fat/inode.c | 37 +++++++++++++++++++++++++++++++------ fs/fat/misc.c | 4 ++-- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 480be11..ebf4c62 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -87,9 +87,9 @@ struct msdos_sb_info { #define FAT_CACHE_VALID 0 /* special case for valid cache */ /* Mark FAT run-time errors */ -#define FAT_FS_FAULT_SET(sbi, val) \ +#define FAT_FS_FAULT_SET(sbi, val, notify) \ fat_sbi_attr_set_notify(sbi, offsetof(struct msdos_sb_info, fs_fault), \ - val) + val, notify) /* * MS-DOS file system inode data in memory @@ -320,7 +320,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); extern int fat_sbi_attr_set_notify(struct msdos_sb_info *sbi, - unsigned long offset, unsigned long val); + unsigned long offset, unsigned long val, int notify); /* fat/misc.c */ extern void fat_fs_error(struct super_block *s, const char *function, diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 4613343..b1a0c8d 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -527,7 +527,7 @@ static int fat_remount(struct super_block *sb, int *flags, char *data) { struct msdos_sb_info *sbi = MSDOS_SB(sb); *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); - FAT_FS_FAULT_SET(sbi, 0); + FAT_FS_FAULT_SET(sbi, 0, 0); return 0; } @@ -1185,6 +1185,7 @@ struct fat_attr { ssize_t (*store)(struct fat_attr *, struct msdos_sb_info *, const char *, size_t); unsigned short offset; + unsigned short uevent; }; static ssize_t fat_sbi_attr_show(struct fat_attr *a, struct msdos_sb_info *sbi, @@ -1206,17 +1207,22 @@ static ssize_t fat_sbi_attr_store(struct fat_attr *a, return count; } -#define FAT_SBI_ATTR(_name, _mode, _show, _store) \ +#define FAT_SBI_ATTR(_name, _mode, _show, _store, _uevent) \ static struct fat_attr fat_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ .offset = offsetof(struct msdos_sb_info, _name), \ + .uevent = _uevent, \ } #define FAT_SBI_RO_ATTR(name) FAT_SBI_ATTR(name, 0444, \ - fat_sbi_attr_show, NULL) + fat_sbi_attr_show, NULL, 0) #define FAT_SBI_RW_ATTR(name) FAT_SBI_ATTR(name, 0644 \ - fat_sbi_attr_show, fat_sbi_attr_store) + fat_sbi_attr_show, fat_sbi_attr_store, 0) +#define FAT_SBI_RO_ATTR_NOTIFY(name) FAT_SBI_ATTR(name, 0444, \ + fat_sbi_attr_show, NULL, 1) +#define FAT_SBI_RW_ATTR_NOTIFY(name) FAT_SBI_ATTR(name, 0644, \ + fat_sbi_attr_show, fat_sbi_attr_store, 1) #define ATTR_LIST(name) (&fat_attr_ ##name.attr) @@ -1240,11 +1246,15 @@ static struct attribute *find_attr_by_offset(struct kobject *kobj, int fat_sbi_attr_set_notify(struct msdos_sb_info *sbi, unsigned long offset, - unsigned long val) + unsigned long val, + int notify) { struct fat_attr *a = (struct fat_attr *) find_attr_by_offset(&sbi->s_kobj, offset); unsigned long *attr_val; + int ev_len; + char *t_str; + char *envp[] = { NULL, NULL }; if (!a) return -EINVAL; @@ -1257,6 +1267,21 @@ int fat_sbi_attr_set_notify(struct msdos_sb_info *sbi, sysfs_notify(&sbi->s_kobj, NULL, a->attr.name); + if (!notify || !a->uevent) + return 0; + + /* dec MAX_UINT == 10 char string */ + ev_len = strlen(a->attr.name) + 1 + 10 + 1; + envp[0] = t_str = kzalloc(ev_len, GFP_KERNEL); + if (!t_str) + return -ENOMEM; + + snprintf(t_str, ev_len, "%s=%lu", a->attr.name, val); + while ((*t_str++ = toupper(*t_str))) + ; + kobject_uevent_env(&sbi->s_kobj, KOBJ_CHANGE, envp); + kfree(envp[0]); + return 0; } EXPORT_SYMBOL(fat_sbi_attr_set_notify); @@ -1573,7 +1598,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, printk(KERN_ERR "FAT: create fs kobject failed\n"); goto out_fail; } - FAT_FS_FAULT_SET(sbi, 0); + FAT_FS_FAULT_SET(sbi, 0, 0); return 0; diff --git a/fs/fat/misc.c b/fs/fat/misc.c index ce478be..8cdefd8 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -35,7 +35,7 @@ void fat_fs_error(struct super_block *s, const char *function, printk(KERN_ERR " File system has been set read-only\n"); } - FAT_FS_FAULT_SET(sbi, 1); + FAT_FS_FAULT_SET(sbi, 1, 0); } EXPORT_SYMBOL_GPL(fat_fs_error); @@ -58,7 +58,7 @@ void fat_fs_warning(struct super_block *s, const char * function, printk("\n"); va_end(args); - FAT_FS_FAULT_SET(sbi, 1); + FAT_FS_FAULT_SET(sbi, 1, 0); } EXPORT_SYMBOL_GPL(fat_fs_warning); -- 1.6.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html