Commit 857ac889 authored by Lukas Czerner's avatar Lukas Czerner Committed by Theodore Ts'o

ext4: add interface to advertise ext4 features in sysfs

User-space should have the opportunity to check what features doest ext4
support in each particular copy. This adds easy interface by creating new
"features" directory in sys/fs/ext4/. In that directory files
advertising feature names can be created.

Add lazy_itable_init to the feature list.
Signed-off-by: default avatarLukas Czerner <lczerner@redhat.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent bfff6873
...@@ -1574,6 +1574,11 @@ struct ext4_li_request { ...@@ -1574,6 +1574,11 @@ struct ext4_li_request {
unsigned long lr_timeout; unsigned long lr_timeout;
}; };
struct ext4_features {
struct kobject f_kobj;
struct completion f_kobj_unregister;
};
/* /*
* Function prototypes * Function prototypes
*/ */
......
...@@ -1274,6 +1274,16 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, ...@@ -1274,6 +1274,16 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
ext4_itable_unused_count(sb, gdp)), ext4_itable_unused_count(sb, gdp)),
sbi->s_inodes_per_block); sbi->s_inodes_per_block);
if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
ext4_error(sb, "Something is wrong with group %u\n"
"Used itable blocks: %d"
"itable unused count: %u\n",
group, used_blks,
ext4_itable_unused_count(sb, gdp));
ret = 1;
goto out;
}
blk = ext4_inode_table(sb, gdp) + used_blks; blk = ext4_inode_table(sb, gdp) + used_blks;
num = sbi->s_itb_per_group - used_blks; num = sbi->s_itb_per_group - used_blks;
...@@ -1283,15 +1293,6 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, ...@@ -1283,15 +1293,6 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group,
if (ret) if (ret)
goto err_out; goto err_out;
if (unlikely(num > EXT4_INODES_PER_GROUP(sb))) {
ext4_error(sb, "Something is wrong with group %u\n"
"Used itable blocks: %d"
"Itable blocks per group: %lu\n",
group, used_blks, sbi->s_itb_per_group);
ret = 1;
goto err_out;
}
/* /*
* Skip zeroout if the inode table is full. But we set the ZEROED * Skip zeroout if the inode table is full. But we set the ZEROED
* flag anyway, because obviously, when it is full it does not need * flag anyway, because obviously, when it is full it does not need
......
...@@ -57,6 +57,7 @@ struct proc_dir_entry *ext4_proc_root; ...@@ -57,6 +57,7 @@ struct proc_dir_entry *ext4_proc_root;
static struct kset *ext4_kset; static struct kset *ext4_kset;
struct ext4_lazy_init *ext4_li_info; struct ext4_lazy_init *ext4_li_info;
struct mutex ext4_li_mtx; struct mutex ext4_li_mtx;
struct ext4_features *ext4_feat;
static int ext4_load_journal(struct super_block *, struct ext4_super_block *, static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
unsigned long journal_devnum); unsigned long journal_devnum);
...@@ -709,6 +710,7 @@ static void ext4_put_super(struct super_block *sb) ...@@ -709,6 +710,7 @@ static void ext4_put_super(struct super_block *sb)
struct ext4_super_block *es = sbi->s_es; struct ext4_super_block *es = sbi->s_es;
int i, err; int i, err;
ext4_unregister_li_request(sb);
dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
flush_workqueue(sbi->dio_unwritten_wq); flush_workqueue(sbi->dio_unwritten_wq);
...@@ -727,7 +729,6 @@ static void ext4_put_super(struct super_block *sb) ...@@ -727,7 +729,6 @@ static void ext4_put_super(struct super_block *sb)
} }
del_timer(&sbi->s_err_report); del_timer(&sbi->s_err_report);
ext4_unregister_li_request(sb);
ext4_release_system_zone(sb); ext4_release_system_zone(sb);
ext4_mb_release(sb); ext4_mb_release(sb);
ext4_ext_release(sb); ext4_ext_release(sb);
...@@ -2416,6 +2417,7 @@ static struct ext4_attr ext4_attr_##_name = { \ ...@@ -2416,6 +2417,7 @@ static struct ext4_attr ext4_attr_##_name = { \
#define EXT4_ATTR(name, mode, show, store) \ #define EXT4_ATTR(name, mode, show, store) \
static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
#define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL)
#define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL)
#define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
#define EXT4_RW_ATTR_SBI_UI(name, elname) \ #define EXT4_RW_ATTR_SBI_UI(name, elname) \
...@@ -2452,6 +2454,14 @@ static struct attribute *ext4_attrs[] = { ...@@ -2452,6 +2454,14 @@ static struct attribute *ext4_attrs[] = {
NULL, NULL,
}; };
/* Features this copy of ext4 supports */
EXT4_INFO_ATTR(lazy_itable_init);
static struct attribute *ext4_feat_attrs[] = {
ATTR_LIST(lazy_itable_init),
NULL,
};
static ssize_t ext4_attr_show(struct kobject *kobj, static ssize_t ext4_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf) struct attribute *attr, char *buf)
{ {
...@@ -2480,7 +2490,6 @@ static void ext4_sb_release(struct kobject *kobj) ...@@ -2480,7 +2490,6 @@ static void ext4_sb_release(struct kobject *kobj)
complete(&sbi->s_kobj_unregister); complete(&sbi->s_kobj_unregister);
} }
static const struct sysfs_ops ext4_attr_ops = { static const struct sysfs_ops ext4_attr_ops = {
.show = ext4_attr_show, .show = ext4_attr_show,
.store = ext4_attr_store, .store = ext4_attr_store,
...@@ -2492,6 +2501,17 @@ static struct kobj_type ext4_ktype = { ...@@ -2492,6 +2501,17 @@ static struct kobj_type ext4_ktype = {
.release = ext4_sb_release, .release = ext4_sb_release,
}; };
static void ext4_feat_release(struct kobject *kobj)
{
complete(&ext4_feat->f_kobj_unregister);
}
static struct kobj_type ext4_feat_ktype = {
.default_attrs = ext4_feat_attrs,
.sysfs_ops = &ext4_attr_ops,
.release = ext4_feat_release,
};
/* /*
* Check whether this filesystem can be mounted based on * Check whether this filesystem can be mounted based on
* the features present and the RDONLY/RDWR mount requested. * the features present and the RDONLY/RDWR mount requested.
...@@ -4720,6 +4740,30 @@ static struct file_system_type ext4_fs_type = { ...@@ -4720,6 +4740,30 @@ static struct file_system_type ext4_fs_type = {
.fs_flags = FS_REQUIRES_DEV, .fs_flags = FS_REQUIRES_DEV,
}; };
int __init ext4_init_feat_adverts(void)
{
struct ext4_features *ef;
int ret = -ENOMEM;
ef = kzalloc(sizeof(struct ext4_features), GFP_KERNEL);
if (!ef)
goto out;
ef->f_kobj.kset = ext4_kset;
init_completion(&ef->f_kobj_unregister);
ret = kobject_init_and_add(&ef->f_kobj, &ext4_feat_ktype, NULL,
"features");
if (ret) {
kfree(ef);
goto out;
}
ext4_feat = ef;
ret = 0;
out:
return ret;
}
static int __init init_ext4_fs(void) static int __init init_ext4_fs(void)
{ {
int err; int err;
...@@ -4732,6 +4776,9 @@ static int __init init_ext4_fs(void) ...@@ -4732,6 +4776,9 @@ static int __init init_ext4_fs(void)
if (!ext4_kset) if (!ext4_kset)
goto out4; goto out4;
ext4_proc_root = proc_mkdir("fs/ext4", NULL); ext4_proc_root = proc_mkdir("fs/ext4", NULL);
err = ext4_init_feat_adverts();
err = init_ext4_mballoc(); err = init_ext4_mballoc();
if (err) if (err)
goto out3; goto out3;
...@@ -4760,6 +4807,7 @@ static int __init init_ext4_fs(void) ...@@ -4760,6 +4807,7 @@ static int __init init_ext4_fs(void)
out2: out2:
exit_ext4_mballoc(); exit_ext4_mballoc();
out3: out3:
kfree(ext4_feat);
remove_proc_entry("fs/ext4", NULL); remove_proc_entry("fs/ext4", NULL);
kset_unregister(ext4_kset); kset_unregister(ext4_kset);
out4: out4:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment