diff options
author | Lukas Czerner <lczerner@redhat.com> | 2010-10-27 21:30:05 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-10-27 21:30:05 -0400 |
commit | 857ac889cce8a486d47874db4d2f9620e7e9e5de (patch) | |
tree | 12401895197d819fcbf2335244d91259f4640aa2 | |
parent | bfff68738f1cb5c93dab1114634cea02aae9e7ba (diff) |
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: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/ext4/ext4.h | 5 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 19 | ||||
-rw-r--r-- | fs/ext4/super.c | 52 |
3 files changed, 65 insertions, 11 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0fe078d368d0..4c5fe37b237d 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1574,6 +1574,11 @@ struct ext4_li_request { | |||
1574 | unsigned long lr_timeout; | 1574 | unsigned long lr_timeout; |
1575 | }; | 1575 | }; |
1576 | 1576 | ||
1577 | struct ext4_features { | ||
1578 | struct kobject f_kobj; | ||
1579 | struct completion f_kobj_unregister; | ||
1580 | }; | ||
1581 | |||
1577 | /* | 1582 | /* |
1578 | * Function prototypes | 1583 | * Function prototypes |
1579 | */ | 1584 | */ |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index e428f23215c0..87d228aae6b0 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -1274,6 +1274,16 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, | |||
1274 | ext4_itable_unused_count(sb, gdp)), | 1274 | ext4_itable_unused_count(sb, gdp)), |
1275 | sbi->s_inodes_per_block); | 1275 | sbi->s_inodes_per_block); |
1276 | 1276 | ||
1277 | if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) { | ||
1278 | ext4_error(sb, "Something is wrong with group %u\n" | ||
1279 | "Used itable blocks: %d" | ||
1280 | "itable unused count: %u\n", | ||
1281 | group, used_blks, | ||
1282 | ext4_itable_unused_count(sb, gdp)); | ||
1283 | ret = 1; | ||
1284 | goto out; | ||
1285 | } | ||
1286 | |||
1277 | blk = ext4_inode_table(sb, gdp) + used_blks; | 1287 | blk = ext4_inode_table(sb, gdp) + used_blks; |
1278 | num = sbi->s_itb_per_group - used_blks; | 1288 | num = sbi->s_itb_per_group - used_blks; |
1279 | 1289 | ||
@@ -1283,15 +1293,6 @@ extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, | |||
1283 | if (ret) | 1293 | if (ret) |
1284 | goto err_out; | 1294 | goto err_out; |
1285 | 1295 | ||
1286 | if (unlikely(num > EXT4_INODES_PER_GROUP(sb))) { | ||
1287 | ext4_error(sb, "Something is wrong with group %u\n" | ||
1288 | "Used itable blocks: %d" | ||
1289 | "Itable blocks per group: %lu\n", | ||
1290 | group, used_blks, sbi->s_itb_per_group); | ||
1291 | ret = 1; | ||
1292 | goto err_out; | ||
1293 | } | ||
1294 | |||
1295 | /* | 1296 | /* |
1296 | * Skip zeroout if the inode table is full. But we set the ZEROED | 1297 | * Skip zeroout if the inode table is full. But we set the ZEROED |
1297 | * flag anyway, because obviously, when it is full it does not need | 1298 | * flag anyway, because obviously, when it is full it does not need |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 5066537e5a38..c5b890140d01 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -57,6 +57,7 @@ struct proc_dir_entry *ext4_proc_root; | |||
57 | static struct kset *ext4_kset; | 57 | static struct kset *ext4_kset; |
58 | struct ext4_lazy_init *ext4_li_info; | 58 | struct ext4_lazy_init *ext4_li_info; |
59 | struct mutex ext4_li_mtx; | 59 | struct mutex ext4_li_mtx; |
60 | struct ext4_features *ext4_feat; | ||
60 | 61 | ||
61 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, | 62 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, |
62 | unsigned long journal_devnum); | 63 | unsigned long journal_devnum); |
@@ -709,6 +710,7 @@ static void ext4_put_super(struct super_block *sb) | |||
709 | struct ext4_super_block *es = sbi->s_es; | 710 | struct ext4_super_block *es = sbi->s_es; |
710 | int i, err; | 711 | int i, err; |
711 | 712 | ||
713 | ext4_unregister_li_request(sb); | ||
712 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); | 714 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); |
713 | 715 | ||
714 | flush_workqueue(sbi->dio_unwritten_wq); | 716 | flush_workqueue(sbi->dio_unwritten_wq); |
@@ -727,7 +729,6 @@ static void ext4_put_super(struct super_block *sb) | |||
727 | } | 729 | } |
728 | 730 | ||
729 | del_timer(&sbi->s_err_report); | 731 | del_timer(&sbi->s_err_report); |
730 | ext4_unregister_li_request(sb); | ||
731 | ext4_release_system_zone(sb); | 732 | ext4_release_system_zone(sb); |
732 | ext4_mb_release(sb); | 733 | ext4_mb_release(sb); |
733 | ext4_ext_release(sb); | 734 | ext4_ext_release(sb); |
@@ -2416,6 +2417,7 @@ static struct ext4_attr ext4_attr_##_name = { \ | |||
2416 | #define EXT4_ATTR(name, mode, show, store) \ | 2417 | #define EXT4_ATTR(name, mode, show, store) \ |
2417 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) | 2418 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) |
2418 | 2419 | ||
2420 | #define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL) | ||
2419 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) | 2421 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) |
2420 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) | 2422 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) |
2421 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ | 2423 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ |
@@ -2452,6 +2454,14 @@ static struct attribute *ext4_attrs[] = { | |||
2452 | NULL, | 2454 | NULL, |
2453 | }; | 2455 | }; |
2454 | 2456 | ||
2457 | /* Features this copy of ext4 supports */ | ||
2458 | EXT4_INFO_ATTR(lazy_itable_init); | ||
2459 | |||
2460 | static struct attribute *ext4_feat_attrs[] = { | ||
2461 | ATTR_LIST(lazy_itable_init), | ||
2462 | NULL, | ||
2463 | }; | ||
2464 | |||
2455 | static ssize_t ext4_attr_show(struct kobject *kobj, | 2465 | static ssize_t ext4_attr_show(struct kobject *kobj, |
2456 | struct attribute *attr, char *buf) | 2466 | struct attribute *attr, char *buf) |
2457 | { | 2467 | { |
@@ -2480,7 +2490,6 @@ static void ext4_sb_release(struct kobject *kobj) | |||
2480 | complete(&sbi->s_kobj_unregister); | 2490 | complete(&sbi->s_kobj_unregister); |
2481 | } | 2491 | } |
2482 | 2492 | ||
2483 | |||
2484 | static const struct sysfs_ops ext4_attr_ops = { | 2493 | static const struct sysfs_ops ext4_attr_ops = { |
2485 | .show = ext4_attr_show, | 2494 | .show = ext4_attr_show, |
2486 | .store = ext4_attr_store, | 2495 | .store = ext4_attr_store, |
@@ -2492,6 +2501,17 @@ static struct kobj_type ext4_ktype = { | |||
2492 | .release = ext4_sb_release, | 2501 | .release = ext4_sb_release, |
2493 | }; | 2502 | }; |
2494 | 2503 | ||
2504 | static void ext4_feat_release(struct kobject *kobj) | ||
2505 | { | ||
2506 | complete(&ext4_feat->f_kobj_unregister); | ||
2507 | } | ||
2508 | |||
2509 | static struct kobj_type ext4_feat_ktype = { | ||
2510 | .default_attrs = ext4_feat_attrs, | ||
2511 | .sysfs_ops = &ext4_attr_ops, | ||
2512 | .release = ext4_feat_release, | ||
2513 | }; | ||
2514 | |||
2495 | /* | 2515 | /* |
2496 | * Check whether this filesystem can be mounted based on | 2516 | * Check whether this filesystem can be mounted based on |
2497 | * the features present and the RDONLY/RDWR mount requested. | 2517 | * the features present and the RDONLY/RDWR mount requested. |
@@ -4720,6 +4740,30 @@ static struct file_system_type ext4_fs_type = { | |||
4720 | .fs_flags = FS_REQUIRES_DEV, | 4740 | .fs_flags = FS_REQUIRES_DEV, |
4721 | }; | 4741 | }; |
4722 | 4742 | ||
4743 | int __init ext4_init_feat_adverts(void) | ||
4744 | { | ||
4745 | struct ext4_features *ef; | ||
4746 | int ret = -ENOMEM; | ||
4747 | |||
4748 | ef = kzalloc(sizeof(struct ext4_features), GFP_KERNEL); | ||
4749 | if (!ef) | ||
4750 | goto out; | ||
4751 | |||
4752 | ef->f_kobj.kset = ext4_kset; | ||
4753 | init_completion(&ef->f_kobj_unregister); | ||
4754 | ret = kobject_init_and_add(&ef->f_kobj, &ext4_feat_ktype, NULL, | ||
4755 | "features"); | ||
4756 | if (ret) { | ||
4757 | kfree(ef); | ||
4758 | goto out; | ||
4759 | } | ||
4760 | |||
4761 | ext4_feat = ef; | ||
4762 | ret = 0; | ||
4763 | out: | ||
4764 | return ret; | ||
4765 | } | ||
4766 | |||
4723 | static int __init init_ext4_fs(void) | 4767 | static int __init init_ext4_fs(void) |
4724 | { | 4768 | { |
4725 | int err; | 4769 | int err; |
@@ -4732,6 +4776,9 @@ static int __init init_ext4_fs(void) | |||
4732 | if (!ext4_kset) | 4776 | if (!ext4_kset) |
4733 | goto out4; | 4777 | goto out4; |
4734 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); | 4778 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); |
4779 | |||
4780 | err = ext4_init_feat_adverts(); | ||
4781 | |||
4735 | err = init_ext4_mballoc(); | 4782 | err = init_ext4_mballoc(); |
4736 | if (err) | 4783 | if (err) |
4737 | goto out3; | 4784 | goto out3; |
@@ -4760,6 +4807,7 @@ out1: | |||
4760 | out2: | 4807 | out2: |
4761 | exit_ext4_mballoc(); | 4808 | exit_ext4_mballoc(); |
4762 | out3: | 4809 | out3: |
4810 | kfree(ext4_feat); | ||
4763 | remove_proc_entry("fs/ext4", NULL); | 4811 | remove_proc_entry("fs/ext4", NULL); |
4764 | kset_unregister(ext4_kset); | 4812 | kset_unregister(ext4_kset); |
4765 | out4: | 4813 | out4: |