|
@@ -57,6 +57,7 @@ struct proc_dir_entry *ext4_proc_root;
|
|
|
static struct kset *ext4_kset;
|
|
|
struct ext4_lazy_init *ext4_li_info;
|
|
|
struct mutex ext4_li_mtx;
|
|
|
+struct ext4_features *ext4_feat;
|
|
|
|
|
|
static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
|
|
|
unsigned long journal_devnum);
|
|
@@ -709,6 +710,7 @@ static void ext4_put_super(struct super_block *sb)
|
|
|
struct ext4_super_block *es = sbi->s_es;
|
|
|
int i, err;
|
|
|
|
|
|
+ ext4_unregister_li_request(sb);
|
|
|
dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
|
|
|
|
|
|
flush_workqueue(sbi->dio_unwritten_wq);
|
|
@@ -727,7 +729,6 @@ static void ext4_put_super(struct super_block *sb)
|
|
|
}
|
|
|
|
|
|
del_timer(&sbi->s_err_report);
|
|
|
- ext4_unregister_li_request(sb);
|
|
|
ext4_release_system_zone(sb);
|
|
|
ext4_mb_release(sb);
|
|
|
ext4_ext_release(sb);
|
|
@@ -2416,6 +2417,7 @@ static struct ext4_attr ext4_attr_##_name = { \
|
|
|
#define EXT4_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_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store)
|
|
|
#define EXT4_RW_ATTR_SBI_UI(name, elname) \
|
|
@@ -2452,6 +2454,14 @@ static struct attribute *ext4_attrs[] = {
|
|
|
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,
|
|
|
struct attribute *attr, char *buf)
|
|
|
{
|
|
@@ -2480,7 +2490,6 @@ static void ext4_sb_release(struct kobject *kobj)
|
|
|
complete(&sbi->s_kobj_unregister);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static const struct sysfs_ops ext4_attr_ops = {
|
|
|
.show = ext4_attr_show,
|
|
|
.store = ext4_attr_store,
|
|
@@ -2492,6 +2501,17 @@ static struct kobj_type ext4_ktype = {
|
|
|
.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
|
|
|
* the features present and the RDONLY/RDWR mount requested.
|
|
@@ -4720,6 +4740,30 @@ static struct file_system_type ext4_fs_type = {
|
|
|
.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)
|
|
|
{
|
|
|
int err;
|
|
@@ -4732,6 +4776,9 @@ static int __init init_ext4_fs(void)
|
|
|
if (!ext4_kset)
|
|
|
goto out4;
|
|
|
ext4_proc_root = proc_mkdir("fs/ext4", NULL);
|
|
|
+
|
|
|
+ err = ext4_init_feat_adverts();
|
|
|
+
|
|
|
err = init_ext4_mballoc();
|
|
|
if (err)
|
|
|
goto out3;
|
|
@@ -4760,6 +4807,7 @@ out1:
|
|
|
out2:
|
|
|
exit_ext4_mballoc();
|
|
|
out3:
|
|
|
+ kfree(ext4_feat);
|
|
|
remove_proc_entry("fs/ext4", NULL);
|
|
|
kset_unregister(ext4_kset);
|
|
|
out4:
|