diff options
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 531 |
1 files changed, 510 insertions, 21 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8ecc1e590303..0348ce066592 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -40,6 +40,9 @@ | |||
40 | #include <linux/crc16.h> | 40 | #include <linux/crc16.h> |
41 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
42 | 42 | ||
43 | #include <linux/kthread.h> | ||
44 | #include <linux/freezer.h> | ||
45 | |||
43 | #include "ext4.h" | 46 | #include "ext4.h" |
44 | #include "ext4_jbd2.h" | 47 | #include "ext4_jbd2.h" |
45 | #include "xattr.h" | 48 | #include "xattr.h" |
@@ -49,8 +52,11 @@ | |||
49 | #define CREATE_TRACE_POINTS | 52 | #define CREATE_TRACE_POINTS |
50 | #include <trace/events/ext4.h> | 53 | #include <trace/events/ext4.h> |
51 | 54 | ||
52 | struct proc_dir_entry *ext4_proc_root; | 55 | static struct proc_dir_entry *ext4_proc_root; |
53 | static struct kset *ext4_kset; | 56 | static struct kset *ext4_kset; |
57 | struct ext4_lazy_init *ext4_li_info; | ||
58 | struct mutex ext4_li_mtx; | ||
59 | struct ext4_features *ext4_feat; | ||
54 | 60 | ||
55 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, | 61 | static int ext4_load_journal(struct super_block *, struct ext4_super_block *, |
56 | unsigned long journal_devnum); | 62 | unsigned long journal_devnum); |
@@ -69,6 +75,8 @@ static void ext4_write_super(struct super_block *sb); | |||
69 | static int ext4_freeze(struct super_block *sb); | 75 | static int ext4_freeze(struct super_block *sb); |
70 | static int ext4_get_sb(struct file_system_type *fs_type, int flags, | 76 | static int ext4_get_sb(struct file_system_type *fs_type, int flags, |
71 | const char *dev_name, void *data, struct vfsmount *mnt); | 77 | const char *dev_name, void *data, struct vfsmount *mnt); |
78 | static void ext4_destroy_lazyinit_thread(void); | ||
79 | static void ext4_unregister_li_request(struct super_block *sb); | ||
72 | 80 | ||
73 | #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) | 81 | #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) |
74 | static struct file_system_type ext3_fs_type = { | 82 | static struct file_system_type ext3_fs_type = { |
@@ -701,6 +709,7 @@ static void ext4_put_super(struct super_block *sb) | |||
701 | struct ext4_super_block *es = sbi->s_es; | 709 | struct ext4_super_block *es = sbi->s_es; |
702 | int i, err; | 710 | int i, err; |
703 | 711 | ||
712 | ext4_unregister_li_request(sb); | ||
704 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); | 713 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); |
705 | 714 | ||
706 | flush_workqueue(sbi->dio_unwritten_wq); | 715 | flush_workqueue(sbi->dio_unwritten_wq); |
@@ -717,6 +726,7 @@ static void ext4_put_super(struct super_block *sb) | |||
717 | ext4_abort(sb, "Couldn't clean up the journal"); | 726 | ext4_abort(sb, "Couldn't clean up the journal"); |
718 | } | 727 | } |
719 | 728 | ||
729 | del_timer(&sbi->s_err_report); | ||
720 | ext4_release_system_zone(sb); | 730 | ext4_release_system_zone(sb); |
721 | ext4_mb_release(sb); | 731 | ext4_mb_release(sb); |
722 | ext4_ext_release(sb); | 732 | ext4_ext_release(sb); |
@@ -1042,6 +1052,12 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
1042 | !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY)) | 1052 | !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY)) |
1043 | seq_puts(seq, ",block_validity"); | 1053 | seq_puts(seq, ",block_validity"); |
1044 | 1054 | ||
1055 | if (!test_opt(sb, INIT_INODE_TABLE)) | ||
1056 | seq_puts(seq, ",noinit_inode_table"); | ||
1057 | else if (sbi->s_li_wait_mult) | ||
1058 | seq_printf(seq, ",init_inode_table=%u", | ||
1059 | (unsigned) sbi->s_li_wait_mult); | ||
1060 | |||
1045 | ext4_show_quota_options(seq, sb); | 1061 | ext4_show_quota_options(seq, sb); |
1046 | 1062 | ||
1047 | return 0; | 1063 | return 0; |
@@ -1170,6 +1186,7 @@ static const struct super_operations ext4_sops = { | |||
1170 | .quota_write = ext4_quota_write, | 1186 | .quota_write = ext4_quota_write, |
1171 | #endif | 1187 | #endif |
1172 | .bdev_try_to_free_page = bdev_try_to_free_page, | 1188 | .bdev_try_to_free_page = bdev_try_to_free_page, |
1189 | .trim_fs = ext4_trim_fs | ||
1173 | }; | 1190 | }; |
1174 | 1191 | ||
1175 | static const struct super_operations ext4_nojournal_sops = { | 1192 | static const struct super_operations ext4_nojournal_sops = { |
@@ -1216,6 +1233,7 @@ enum { | |||
1216 | Opt_inode_readahead_blks, Opt_journal_ioprio, | 1233 | Opt_inode_readahead_blks, Opt_journal_ioprio, |
1217 | Opt_dioread_nolock, Opt_dioread_lock, | 1234 | Opt_dioread_nolock, Opt_dioread_lock, |
1218 | Opt_discard, Opt_nodiscard, | 1235 | Opt_discard, Opt_nodiscard, |
1236 | Opt_init_inode_table, Opt_noinit_inode_table, | ||
1219 | }; | 1237 | }; |
1220 | 1238 | ||
1221 | static const match_table_t tokens = { | 1239 | static const match_table_t tokens = { |
@@ -1286,6 +1304,9 @@ static const match_table_t tokens = { | |||
1286 | {Opt_dioread_lock, "dioread_lock"}, | 1304 | {Opt_dioread_lock, "dioread_lock"}, |
1287 | {Opt_discard, "discard"}, | 1305 | {Opt_discard, "discard"}, |
1288 | {Opt_nodiscard, "nodiscard"}, | 1306 | {Opt_nodiscard, "nodiscard"}, |
1307 | {Opt_init_inode_table, "init_itable=%u"}, | ||
1308 | {Opt_init_inode_table, "init_itable"}, | ||
1309 | {Opt_noinit_inode_table, "noinit_itable"}, | ||
1289 | {Opt_err, NULL}, | 1310 | {Opt_err, NULL}, |
1290 | }; | 1311 | }; |
1291 | 1312 | ||
@@ -1756,6 +1777,20 @@ set_qf_format: | |||
1756 | case Opt_dioread_lock: | 1777 | case Opt_dioread_lock: |
1757 | clear_opt(sbi->s_mount_opt, DIOREAD_NOLOCK); | 1778 | clear_opt(sbi->s_mount_opt, DIOREAD_NOLOCK); |
1758 | break; | 1779 | break; |
1780 | case Opt_init_inode_table: | ||
1781 | set_opt(sbi->s_mount_opt, INIT_INODE_TABLE); | ||
1782 | if (args[0].from) { | ||
1783 | if (match_int(&args[0], &option)) | ||
1784 | return 0; | ||
1785 | } else | ||
1786 | option = EXT4_DEF_LI_WAIT_MULT; | ||
1787 | if (option < 0) | ||
1788 | return 0; | ||
1789 | sbi->s_li_wait_mult = option; | ||
1790 | break; | ||
1791 | case Opt_noinit_inode_table: | ||
1792 | clear_opt(sbi->s_mount_opt, INIT_INODE_TABLE); | ||
1793 | break; | ||
1759 | default: | 1794 | default: |
1760 | ext4_msg(sb, KERN_ERR, | 1795 | ext4_msg(sb, KERN_ERR, |
1761 | "Unrecognized mount option \"%s\" " | 1796 | "Unrecognized mount option \"%s\" " |
@@ -1939,7 +1974,8 @@ int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, | |||
1939 | } | 1974 | } |
1940 | 1975 | ||
1941 | /* Called at mount-time, super-block is locked */ | 1976 | /* Called at mount-time, super-block is locked */ |
1942 | static int ext4_check_descriptors(struct super_block *sb) | 1977 | static int ext4_check_descriptors(struct super_block *sb, |
1978 | ext4_group_t *first_not_zeroed) | ||
1943 | { | 1979 | { |
1944 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1980 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
1945 | ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); | 1981 | ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); |
@@ -1948,7 +1984,7 @@ static int ext4_check_descriptors(struct super_block *sb) | |||
1948 | ext4_fsblk_t inode_bitmap; | 1984 | ext4_fsblk_t inode_bitmap; |
1949 | ext4_fsblk_t inode_table; | 1985 | ext4_fsblk_t inode_table; |
1950 | int flexbg_flag = 0; | 1986 | int flexbg_flag = 0; |
1951 | ext4_group_t i; | 1987 | ext4_group_t i, grp = sbi->s_groups_count; |
1952 | 1988 | ||
1953 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) | 1989 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) |
1954 | flexbg_flag = 1; | 1990 | flexbg_flag = 1; |
@@ -1964,6 +2000,10 @@ static int ext4_check_descriptors(struct super_block *sb) | |||
1964 | last_block = first_block + | 2000 | last_block = first_block + |
1965 | (EXT4_BLOCKS_PER_GROUP(sb) - 1); | 2001 | (EXT4_BLOCKS_PER_GROUP(sb) - 1); |
1966 | 2002 | ||
2003 | if ((grp == sbi->s_groups_count) && | ||
2004 | !(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) | ||
2005 | grp = i; | ||
2006 | |||
1967 | block_bitmap = ext4_block_bitmap(sb, gdp); | 2007 | block_bitmap = ext4_block_bitmap(sb, gdp); |
1968 | if (block_bitmap < first_block || block_bitmap > last_block) { | 2008 | if (block_bitmap < first_block || block_bitmap > last_block) { |
1969 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " | 2009 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " |
@@ -2001,6 +2041,8 @@ static int ext4_check_descriptors(struct super_block *sb) | |||
2001 | if (!flexbg_flag) | 2041 | if (!flexbg_flag) |
2002 | first_block += EXT4_BLOCKS_PER_GROUP(sb); | 2042 | first_block += EXT4_BLOCKS_PER_GROUP(sb); |
2003 | } | 2043 | } |
2044 | if (NULL != first_not_zeroed) | ||
2045 | *first_not_zeroed = grp; | ||
2004 | 2046 | ||
2005 | ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); | 2047 | ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); |
2006 | sbi->s_es->s_free_inodes_count =cpu_to_le32(ext4_count_free_inodes(sb)); | 2048 | sbi->s_es->s_free_inodes_count =cpu_to_le32(ext4_count_free_inodes(sb)); |
@@ -2373,6 +2415,7 @@ static struct ext4_attr ext4_attr_##_name = { \ | |||
2373 | #define EXT4_ATTR(name, mode, show, store) \ | 2415 | #define EXT4_ATTR(name, mode, show, store) \ |
2374 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) | 2416 | static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) |
2375 | 2417 | ||
2418 | #define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL) | ||
2376 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) | 2419 | #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) |
2377 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) | 2420 | #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) |
2378 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ | 2421 | #define EXT4_RW_ATTR_SBI_UI(name, elname) \ |
@@ -2409,6 +2452,16 @@ static struct attribute *ext4_attrs[] = { | |||
2409 | NULL, | 2452 | NULL, |
2410 | }; | 2453 | }; |
2411 | 2454 | ||
2455 | /* Features this copy of ext4 supports */ | ||
2456 | EXT4_INFO_ATTR(lazy_itable_init); | ||
2457 | EXT4_INFO_ATTR(batched_discard); | ||
2458 | |||
2459 | static struct attribute *ext4_feat_attrs[] = { | ||
2460 | ATTR_LIST(lazy_itable_init), | ||
2461 | ATTR_LIST(batched_discard), | ||
2462 | NULL, | ||
2463 | }; | ||
2464 | |||
2412 | static ssize_t ext4_attr_show(struct kobject *kobj, | 2465 | static ssize_t ext4_attr_show(struct kobject *kobj, |
2413 | struct attribute *attr, char *buf) | 2466 | struct attribute *attr, char *buf) |
2414 | { | 2467 | { |
@@ -2437,7 +2490,6 @@ static void ext4_sb_release(struct kobject *kobj) | |||
2437 | complete(&sbi->s_kobj_unregister); | 2490 | complete(&sbi->s_kobj_unregister); |
2438 | } | 2491 | } |
2439 | 2492 | ||
2440 | |||
2441 | static const struct sysfs_ops ext4_attr_ops = { | 2493 | static const struct sysfs_ops ext4_attr_ops = { |
2442 | .show = ext4_attr_show, | 2494 | .show = ext4_attr_show, |
2443 | .store = ext4_attr_store, | 2495 | .store = ext4_attr_store, |
@@ -2449,6 +2501,17 @@ static struct kobj_type ext4_ktype = { | |||
2449 | .release = ext4_sb_release, | 2501 | .release = ext4_sb_release, |
2450 | }; | 2502 | }; |
2451 | 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 | |||
2452 | /* | 2515 | /* |
2453 | * Check whether this filesystem can be mounted based on | 2516 | * Check whether this filesystem can be mounted based on |
2454 | * the features present and the RDONLY/RDWR mount requested. | 2517 | * the features present and the RDONLY/RDWR mount requested. |
@@ -2539,6 +2602,372 @@ static void print_daily_error_info(unsigned long arg) | |||
2539 | mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */ | 2602 | mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */ |
2540 | } | 2603 | } |
2541 | 2604 | ||
2605 | static void ext4_lazyinode_timeout(unsigned long data) | ||
2606 | { | ||
2607 | struct task_struct *p = (struct task_struct *)data; | ||
2608 | wake_up_process(p); | ||
2609 | } | ||
2610 | |||
2611 | /* Find next suitable group and run ext4_init_inode_table */ | ||
2612 | static int ext4_run_li_request(struct ext4_li_request *elr) | ||
2613 | { | ||
2614 | struct ext4_group_desc *gdp = NULL; | ||
2615 | ext4_group_t group, ngroups; | ||
2616 | struct super_block *sb; | ||
2617 | unsigned long timeout = 0; | ||
2618 | int ret = 0; | ||
2619 | |||
2620 | sb = elr->lr_super; | ||
2621 | ngroups = EXT4_SB(sb)->s_groups_count; | ||
2622 | |||
2623 | for (group = elr->lr_next_group; group < ngroups; group++) { | ||
2624 | gdp = ext4_get_group_desc(sb, group, NULL); | ||
2625 | if (!gdp) { | ||
2626 | ret = 1; | ||
2627 | break; | ||
2628 | } | ||
2629 | |||
2630 | if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) | ||
2631 | break; | ||
2632 | } | ||
2633 | |||
2634 | if (group == ngroups) | ||
2635 | ret = 1; | ||
2636 | |||
2637 | if (!ret) { | ||
2638 | timeout = jiffies; | ||
2639 | ret = ext4_init_inode_table(sb, group, | ||
2640 | elr->lr_timeout ? 0 : 1); | ||
2641 | if (elr->lr_timeout == 0) { | ||
2642 | timeout = jiffies - timeout; | ||
2643 | if (elr->lr_sbi->s_li_wait_mult) | ||
2644 | timeout *= elr->lr_sbi->s_li_wait_mult; | ||
2645 | else | ||
2646 | timeout *= 20; | ||
2647 | elr->lr_timeout = timeout; | ||
2648 | } | ||
2649 | elr->lr_next_sched = jiffies + elr->lr_timeout; | ||
2650 | elr->lr_next_group = group + 1; | ||
2651 | } | ||
2652 | |||
2653 | return ret; | ||
2654 | } | ||
2655 | |||
2656 | /* | ||
2657 | * Remove lr_request from the list_request and free the | ||
2658 | * request tructure. Should be called with li_list_mtx held | ||
2659 | */ | ||
2660 | static void ext4_remove_li_request(struct ext4_li_request *elr) | ||
2661 | { | ||
2662 | struct ext4_sb_info *sbi; | ||
2663 | |||
2664 | if (!elr) | ||
2665 | return; | ||
2666 | |||
2667 | sbi = elr->lr_sbi; | ||
2668 | |||
2669 | list_del(&elr->lr_request); | ||
2670 | sbi->s_li_request = NULL; | ||
2671 | kfree(elr); | ||
2672 | } | ||
2673 | |||
2674 | static void ext4_unregister_li_request(struct super_block *sb) | ||
2675 | { | ||
2676 | struct ext4_li_request *elr = EXT4_SB(sb)->s_li_request; | ||
2677 | |||
2678 | if (!ext4_li_info) | ||
2679 | return; | ||
2680 | |||
2681 | mutex_lock(&ext4_li_info->li_list_mtx); | ||
2682 | ext4_remove_li_request(elr); | ||
2683 | mutex_unlock(&ext4_li_info->li_list_mtx); | ||
2684 | } | ||
2685 | |||
2686 | /* | ||
2687 | * This is the function where ext4lazyinit thread lives. It walks | ||
2688 | * through the request list searching for next scheduled filesystem. | ||
2689 | * When such a fs is found, run the lazy initialization request | ||
2690 | * (ext4_rn_li_request) and keep track of the time spend in this | ||
2691 | * function. Based on that time we compute next schedule time of | ||
2692 | * the request. When walking through the list is complete, compute | ||
2693 | * next waking time and put itself into sleep. | ||
2694 | */ | ||
2695 | static int ext4_lazyinit_thread(void *arg) | ||
2696 | { | ||
2697 | struct ext4_lazy_init *eli = (struct ext4_lazy_init *)arg; | ||
2698 | struct list_head *pos, *n; | ||
2699 | struct ext4_li_request *elr; | ||
2700 | unsigned long next_wakeup; | ||
2701 | DEFINE_WAIT(wait); | ||
2702 | int ret; | ||
2703 | |||
2704 | BUG_ON(NULL == eli); | ||
2705 | |||
2706 | eli->li_timer.data = (unsigned long)current; | ||
2707 | eli->li_timer.function = ext4_lazyinode_timeout; | ||
2708 | |||
2709 | eli->li_task = current; | ||
2710 | wake_up(&eli->li_wait_task); | ||
2711 | |||
2712 | cont_thread: | ||
2713 | while (true) { | ||
2714 | next_wakeup = MAX_JIFFY_OFFSET; | ||
2715 | |||
2716 | mutex_lock(&eli->li_list_mtx); | ||
2717 | if (list_empty(&eli->li_request_list)) { | ||
2718 | mutex_unlock(&eli->li_list_mtx); | ||
2719 | goto exit_thread; | ||
2720 | } | ||
2721 | |||
2722 | list_for_each_safe(pos, n, &eli->li_request_list) { | ||
2723 | elr = list_entry(pos, struct ext4_li_request, | ||
2724 | lr_request); | ||
2725 | |||
2726 | if (time_after_eq(jiffies, elr->lr_next_sched)) | ||
2727 | ret = ext4_run_li_request(elr); | ||
2728 | |||
2729 | if (ret) { | ||
2730 | ret = 0; | ||
2731 | ext4_remove_li_request(elr); | ||
2732 | continue; | ||
2733 | } | ||
2734 | |||
2735 | if (time_before(elr->lr_next_sched, next_wakeup)) | ||
2736 | next_wakeup = elr->lr_next_sched; | ||
2737 | } | ||
2738 | mutex_unlock(&eli->li_list_mtx); | ||
2739 | |||
2740 | if (freezing(current)) | ||
2741 | refrigerator(); | ||
2742 | |||
2743 | if (time_after_eq(jiffies, next_wakeup)) { | ||
2744 | cond_resched(); | ||
2745 | continue; | ||
2746 | } | ||
2747 | |||
2748 | eli->li_timer.expires = next_wakeup; | ||
2749 | add_timer(&eli->li_timer); | ||
2750 | prepare_to_wait(&eli->li_wait_daemon, &wait, | ||
2751 | TASK_INTERRUPTIBLE); | ||
2752 | if (time_before(jiffies, next_wakeup)) | ||
2753 | schedule(); | ||
2754 | finish_wait(&eli->li_wait_daemon, &wait); | ||
2755 | } | ||
2756 | |||
2757 | exit_thread: | ||
2758 | /* | ||
2759 | * It looks like the request list is empty, but we need | ||
2760 | * to check it under the li_list_mtx lock, to prevent any | ||
2761 | * additions into it, and of course we should lock ext4_li_mtx | ||
2762 | * to atomically free the list and ext4_li_info, because at | ||
2763 | * this point another ext4 filesystem could be registering | ||
2764 | * new one. | ||
2765 | */ | ||
2766 | mutex_lock(&ext4_li_mtx); | ||
2767 | mutex_lock(&eli->li_list_mtx); | ||
2768 | if (!list_empty(&eli->li_request_list)) { | ||
2769 | mutex_unlock(&eli->li_list_mtx); | ||
2770 | mutex_unlock(&ext4_li_mtx); | ||
2771 | goto cont_thread; | ||
2772 | } | ||
2773 | mutex_unlock(&eli->li_list_mtx); | ||
2774 | del_timer_sync(&ext4_li_info->li_timer); | ||
2775 | eli->li_task = NULL; | ||
2776 | wake_up(&eli->li_wait_task); | ||
2777 | |||
2778 | kfree(ext4_li_info); | ||
2779 | ext4_li_info = NULL; | ||
2780 | mutex_unlock(&ext4_li_mtx); | ||
2781 | |||
2782 | return 0; | ||
2783 | } | ||
2784 | |||
2785 | static void ext4_clear_request_list(void) | ||
2786 | { | ||
2787 | struct list_head *pos, *n; | ||
2788 | struct ext4_li_request *elr; | ||
2789 | |||
2790 | mutex_lock(&ext4_li_info->li_list_mtx); | ||
2791 | if (list_empty(&ext4_li_info->li_request_list)) | ||
2792 | return; | ||
2793 | |||
2794 | list_for_each_safe(pos, n, &ext4_li_info->li_request_list) { | ||
2795 | elr = list_entry(pos, struct ext4_li_request, | ||
2796 | lr_request); | ||
2797 | ext4_remove_li_request(elr); | ||
2798 | } | ||
2799 | mutex_unlock(&ext4_li_info->li_list_mtx); | ||
2800 | } | ||
2801 | |||
2802 | static int ext4_run_lazyinit_thread(void) | ||
2803 | { | ||
2804 | struct task_struct *t; | ||
2805 | |||
2806 | t = kthread_run(ext4_lazyinit_thread, ext4_li_info, "ext4lazyinit"); | ||
2807 | if (IS_ERR(t)) { | ||
2808 | int err = PTR_ERR(t); | ||
2809 | ext4_clear_request_list(); | ||
2810 | del_timer_sync(&ext4_li_info->li_timer); | ||
2811 | kfree(ext4_li_info); | ||
2812 | ext4_li_info = NULL; | ||
2813 | printk(KERN_CRIT "EXT4: error %d creating inode table " | ||
2814 | "initialization thread\n", | ||
2815 | err); | ||
2816 | return err; | ||
2817 | } | ||
2818 | ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING; | ||
2819 | |||
2820 | wait_event(ext4_li_info->li_wait_task, ext4_li_info->li_task != NULL); | ||
2821 | return 0; | ||
2822 | } | ||
2823 | |||
2824 | /* | ||
2825 | * Check whether it make sense to run itable init. thread or not. | ||
2826 | * If there is at least one uninitialized inode table, return | ||
2827 | * corresponding group number, else the loop goes through all | ||
2828 | * groups and return total number of groups. | ||
2829 | */ | ||
2830 | static ext4_group_t ext4_has_uninit_itable(struct super_block *sb) | ||
2831 | { | ||
2832 | ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count; | ||
2833 | struct ext4_group_desc *gdp = NULL; | ||
2834 | |||
2835 | for (group = 0; group < ngroups; group++) { | ||
2836 | gdp = ext4_get_group_desc(sb, group, NULL); | ||
2837 | if (!gdp) | ||
2838 | continue; | ||
2839 | |||
2840 | if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) | ||
2841 | break; | ||
2842 | } | ||
2843 | |||
2844 | return group; | ||
2845 | } | ||
2846 | |||
2847 | static int ext4_li_info_new(void) | ||
2848 | { | ||
2849 | struct ext4_lazy_init *eli = NULL; | ||
2850 | |||
2851 | eli = kzalloc(sizeof(*eli), GFP_KERNEL); | ||
2852 | if (!eli) | ||
2853 | return -ENOMEM; | ||
2854 | |||
2855 | eli->li_task = NULL; | ||
2856 | INIT_LIST_HEAD(&eli->li_request_list); | ||
2857 | mutex_init(&eli->li_list_mtx); | ||
2858 | |||
2859 | init_waitqueue_head(&eli->li_wait_daemon); | ||
2860 | init_waitqueue_head(&eli->li_wait_task); | ||
2861 | init_timer(&eli->li_timer); | ||
2862 | eli->li_state |= EXT4_LAZYINIT_QUIT; | ||
2863 | |||
2864 | ext4_li_info = eli; | ||
2865 | |||
2866 | return 0; | ||
2867 | } | ||
2868 | |||
2869 | static struct ext4_li_request *ext4_li_request_new(struct super_block *sb, | ||
2870 | ext4_group_t start) | ||
2871 | { | ||
2872 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
2873 | struct ext4_li_request *elr; | ||
2874 | unsigned long rnd; | ||
2875 | |||
2876 | elr = kzalloc(sizeof(*elr), GFP_KERNEL); | ||
2877 | if (!elr) | ||
2878 | return NULL; | ||
2879 | |||
2880 | elr->lr_super = sb; | ||
2881 | elr->lr_sbi = sbi; | ||
2882 | elr->lr_next_group = start; | ||
2883 | |||
2884 | /* | ||
2885 | * Randomize first schedule time of the request to | ||
2886 | * spread the inode table initialization requests | ||
2887 | * better. | ||
2888 | */ | ||
2889 | get_random_bytes(&rnd, sizeof(rnd)); | ||
2890 | elr->lr_next_sched = jiffies + (unsigned long)rnd % | ||
2891 | (EXT4_DEF_LI_MAX_START_DELAY * HZ); | ||
2892 | |||
2893 | return elr; | ||
2894 | } | ||
2895 | |||
2896 | static int ext4_register_li_request(struct super_block *sb, | ||
2897 | ext4_group_t first_not_zeroed) | ||
2898 | { | ||
2899 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
2900 | struct ext4_li_request *elr; | ||
2901 | ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; | ||
2902 | int ret; | ||
2903 | |||
2904 | if (sbi->s_li_request != NULL) | ||
2905 | return 0; | ||
2906 | |||
2907 | if (first_not_zeroed == ngroups || | ||
2908 | (sb->s_flags & MS_RDONLY) || | ||
2909 | !test_opt(sb, INIT_INODE_TABLE)) { | ||
2910 | sbi->s_li_request = NULL; | ||
2911 | return 0; | ||
2912 | } | ||
2913 | |||
2914 | if (first_not_zeroed == ngroups) { | ||
2915 | sbi->s_li_request = NULL; | ||
2916 | return 0; | ||
2917 | } | ||
2918 | |||
2919 | elr = ext4_li_request_new(sb, first_not_zeroed); | ||
2920 | if (!elr) | ||
2921 | return -ENOMEM; | ||
2922 | |||
2923 | mutex_lock(&ext4_li_mtx); | ||
2924 | |||
2925 | if (NULL == ext4_li_info) { | ||
2926 | ret = ext4_li_info_new(); | ||
2927 | if (ret) | ||
2928 | goto out; | ||
2929 | } | ||
2930 | |||
2931 | mutex_lock(&ext4_li_info->li_list_mtx); | ||
2932 | list_add(&elr->lr_request, &ext4_li_info->li_request_list); | ||
2933 | mutex_unlock(&ext4_li_info->li_list_mtx); | ||
2934 | |||
2935 | sbi->s_li_request = elr; | ||
2936 | |||
2937 | if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) { | ||
2938 | ret = ext4_run_lazyinit_thread(); | ||
2939 | if (ret) | ||
2940 | goto out; | ||
2941 | } | ||
2942 | out: | ||
2943 | mutex_unlock(&ext4_li_mtx); | ||
2944 | if (ret) | ||
2945 | kfree(elr); | ||
2946 | return ret; | ||
2947 | } | ||
2948 | |||
2949 | /* | ||
2950 | * We do not need to lock anything since this is called on | ||
2951 | * module unload. | ||
2952 | */ | ||
2953 | static void ext4_destroy_lazyinit_thread(void) | ||
2954 | { | ||
2955 | /* | ||
2956 | * If thread exited earlier | ||
2957 | * there's nothing to be done. | ||
2958 | */ | ||
2959 | if (!ext4_li_info) | ||
2960 | return; | ||
2961 | |||
2962 | ext4_clear_request_list(); | ||
2963 | |||
2964 | while (ext4_li_info->li_task) { | ||
2965 | wake_up(&ext4_li_info->li_wait_daemon); | ||
2966 | wait_event(ext4_li_info->li_wait_task, | ||
2967 | ext4_li_info->li_task == NULL); | ||
2968 | } | ||
2969 | } | ||
2970 | |||
2542 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 2971 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
2543 | __releases(kernel_lock) | 2972 | __releases(kernel_lock) |
2544 | __acquires(kernel_lock) | 2973 | __acquires(kernel_lock) |
@@ -2564,6 +2993,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2564 | __u64 blocks_count; | 2993 | __u64 blocks_count; |
2565 | int err; | 2994 | int err; |
2566 | unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; | 2995 | unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; |
2996 | ext4_group_t first_not_zeroed; | ||
2567 | 2997 | ||
2568 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | 2998 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); |
2569 | if (!sbi) | 2999 | if (!sbi) |
@@ -2624,6 +3054,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2624 | 3054 | ||
2625 | /* Set defaults before we parse the mount options */ | 3055 | /* Set defaults before we parse the mount options */ |
2626 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); | 3056 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); |
3057 | set_opt(sbi->s_mount_opt, INIT_INODE_TABLE); | ||
2627 | if (def_mount_opts & EXT4_DEFM_DEBUG) | 3058 | if (def_mount_opts & EXT4_DEFM_DEBUG) |
2628 | set_opt(sbi->s_mount_opt, DEBUG); | 3059 | set_opt(sbi->s_mount_opt, DEBUG); |
2629 | if (def_mount_opts & EXT4_DEFM_BSDGROUPS) { | 3060 | if (def_mount_opts & EXT4_DEFM_BSDGROUPS) { |
@@ -2901,7 +3332,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2901 | goto failed_mount2; | 3332 | goto failed_mount2; |
2902 | } | 3333 | } |
2903 | } | 3334 | } |
2904 | if (!ext4_check_descriptors(sb)) { | 3335 | if (!ext4_check_descriptors(sb, &first_not_zeroed)) { |
2905 | ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); | 3336 | ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); |
2906 | goto failed_mount2; | 3337 | goto failed_mount2; |
2907 | } | 3338 | } |
@@ -3122,6 +3553,10 @@ no_journal: | |||
3122 | goto failed_mount4; | 3553 | goto failed_mount4; |
3123 | } | 3554 | } |
3124 | 3555 | ||
3556 | err = ext4_register_li_request(sb, first_not_zeroed); | ||
3557 | if (err) | ||
3558 | goto failed_mount4; | ||
3559 | |||
3125 | sbi->s_kobj.kset = ext4_kset; | 3560 | sbi->s_kobj.kset = ext4_kset; |
3126 | init_completion(&sbi->s_kobj_unregister); | 3561 | init_completion(&sbi->s_kobj_unregister); |
3127 | err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL, | 3562 | err = kobject_init_and_add(&sbi->s_kobj, &ext4_ktype, NULL, |
@@ -3461,7 +3896,7 @@ static int ext4_load_journal(struct super_block *sb, | |||
3461 | EXT4_SB(sb)->s_journal = journal; | 3896 | EXT4_SB(sb)->s_journal = journal; |
3462 | ext4_clear_journal_err(sb, es); | 3897 | ext4_clear_journal_err(sb, es); |
3463 | 3898 | ||
3464 | if (journal_devnum && | 3899 | if (!really_read_only && journal_devnum && |
3465 | journal_devnum != le32_to_cpu(es->s_journal_dev)) { | 3900 | journal_devnum != le32_to_cpu(es->s_journal_dev)) { |
3466 | es->s_journal_dev = cpu_to_le32(journal_devnum); | 3901 | es->s_journal_dev = cpu_to_le32(journal_devnum); |
3467 | 3902 | ||
@@ -3514,9 +3949,12 @@ static int ext4_commit_super(struct super_block *sb, int sync) | |||
3514 | else | 3949 | else |
3515 | es->s_kbytes_written = | 3950 | es->s_kbytes_written = |
3516 | cpu_to_le64(EXT4_SB(sb)->s_kbytes_written); | 3951 | cpu_to_le64(EXT4_SB(sb)->s_kbytes_written); |
3517 | ext4_free_blocks_count_set(es, percpu_counter_sum_positive( | 3952 | if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter)) |
3953 | ext4_free_blocks_count_set(es, percpu_counter_sum_positive( | ||
3518 | &EXT4_SB(sb)->s_freeblocks_counter)); | 3954 | &EXT4_SB(sb)->s_freeblocks_counter)); |
3519 | es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive( | 3955 | if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter)) |
3956 | es->s_free_inodes_count = | ||
3957 | cpu_to_le32(percpu_counter_sum_positive( | ||
3520 | &EXT4_SB(sb)->s_freeinodes_counter)); | 3958 | &EXT4_SB(sb)->s_freeinodes_counter)); |
3521 | sb->s_dirt = 0; | 3959 | sb->s_dirt = 0; |
3522 | BUFFER_TRACE(sbh, "marking dirty"); | 3960 | BUFFER_TRACE(sbh, "marking dirty"); |
@@ -3835,6 +4273,19 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
3835 | enable_quota = 1; | 4273 | enable_quota = 1; |
3836 | } | 4274 | } |
3837 | } | 4275 | } |
4276 | |||
4277 | /* | ||
4278 | * Reinitialize lazy itable initialization thread based on | ||
4279 | * current settings | ||
4280 | */ | ||
4281 | if ((sb->s_flags & MS_RDONLY) || !test_opt(sb, INIT_INODE_TABLE)) | ||
4282 | ext4_unregister_li_request(sb); | ||
4283 | else { | ||
4284 | ext4_group_t first_not_zeroed; | ||
4285 | first_not_zeroed = ext4_has_uninit_itable(sb); | ||
4286 | ext4_register_li_request(sb, first_not_zeroed); | ||
4287 | } | ||
4288 | |||
3838 | ext4_setup_system_zone(sb); | 4289 | ext4_setup_system_zone(sb); |
3839 | if (sbi->s_journal == NULL) | 4290 | if (sbi->s_journal == NULL) |
3840 | ext4_commit_super(sb, 1); | 4291 | ext4_commit_super(sb, 1); |
@@ -4276,23 +4727,53 @@ static struct file_system_type ext4_fs_type = { | |||
4276 | .fs_flags = FS_REQUIRES_DEV, | 4727 | .fs_flags = FS_REQUIRES_DEV, |
4277 | }; | 4728 | }; |
4278 | 4729 | ||
4279 | static int __init init_ext4_fs(void) | 4730 | int __init ext4_init_feat_adverts(void) |
4731 | { | ||
4732 | struct ext4_features *ef; | ||
4733 | int ret = -ENOMEM; | ||
4734 | |||
4735 | ef = kzalloc(sizeof(struct ext4_features), GFP_KERNEL); | ||
4736 | if (!ef) | ||
4737 | goto out; | ||
4738 | |||
4739 | ef->f_kobj.kset = ext4_kset; | ||
4740 | init_completion(&ef->f_kobj_unregister); | ||
4741 | ret = kobject_init_and_add(&ef->f_kobj, &ext4_feat_ktype, NULL, | ||
4742 | "features"); | ||
4743 | if (ret) { | ||
4744 | kfree(ef); | ||
4745 | goto out; | ||
4746 | } | ||
4747 | |||
4748 | ext4_feat = ef; | ||
4749 | ret = 0; | ||
4750 | out: | ||
4751 | return ret; | ||
4752 | } | ||
4753 | |||
4754 | static int __init ext4_init_fs(void) | ||
4280 | { | 4755 | { |
4281 | int err; | 4756 | int err; |
4282 | 4757 | ||
4283 | ext4_check_flag_values(); | 4758 | ext4_check_flag_values(); |
4284 | err = init_ext4_system_zone(); | 4759 | err = ext4_init_pageio(); |
4285 | if (err) | 4760 | if (err) |
4286 | return err; | 4761 | return err; |
4762 | err = ext4_init_system_zone(); | ||
4763 | if (err) | ||
4764 | goto out5; | ||
4287 | ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj); | 4765 | ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj); |
4288 | if (!ext4_kset) | 4766 | if (!ext4_kset) |
4289 | goto out4; | 4767 | goto out4; |
4290 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); | 4768 | ext4_proc_root = proc_mkdir("fs/ext4", NULL); |
4291 | err = init_ext4_mballoc(); | 4769 | |
4770 | err = ext4_init_feat_adverts(); | ||
4771 | |||
4772 | err = ext4_init_mballoc(); | ||
4292 | if (err) | 4773 | if (err) |
4293 | goto out3; | 4774 | goto out3; |
4294 | 4775 | ||
4295 | err = init_ext4_xattr(); | 4776 | err = ext4_init_xattr(); |
4296 | if (err) | 4777 | if (err) |
4297 | goto out2; | 4778 | goto out2; |
4298 | err = init_inodecache(); | 4779 | err = init_inodecache(); |
@@ -4303,38 +4784,46 @@ static int __init init_ext4_fs(void) | |||
4303 | err = register_filesystem(&ext4_fs_type); | 4784 | err = register_filesystem(&ext4_fs_type); |
4304 | if (err) | 4785 | if (err) |
4305 | goto out; | 4786 | goto out; |
4787 | |||
4788 | ext4_li_info = NULL; | ||
4789 | mutex_init(&ext4_li_mtx); | ||
4306 | return 0; | 4790 | return 0; |
4307 | out: | 4791 | out: |
4308 | unregister_as_ext2(); | 4792 | unregister_as_ext2(); |
4309 | unregister_as_ext3(); | 4793 | unregister_as_ext3(); |
4310 | destroy_inodecache(); | 4794 | destroy_inodecache(); |
4311 | out1: | 4795 | out1: |
4312 | exit_ext4_xattr(); | 4796 | ext4_exit_xattr(); |
4313 | out2: | 4797 | out2: |
4314 | exit_ext4_mballoc(); | 4798 | ext4_exit_mballoc(); |
4315 | out3: | 4799 | out3: |
4800 | kfree(ext4_feat); | ||
4316 | remove_proc_entry("fs/ext4", NULL); | 4801 | remove_proc_entry("fs/ext4", NULL); |
4317 | kset_unregister(ext4_kset); | 4802 | kset_unregister(ext4_kset); |
4318 | out4: | 4803 | out4: |
4319 | exit_ext4_system_zone(); | 4804 | ext4_exit_system_zone(); |
4805 | out5: | ||
4806 | ext4_exit_pageio(); | ||
4320 | return err; | 4807 | return err; |
4321 | } | 4808 | } |
4322 | 4809 | ||
4323 | static void __exit exit_ext4_fs(void) | 4810 | static void __exit ext4_exit_fs(void) |
4324 | { | 4811 | { |
4812 | ext4_destroy_lazyinit_thread(); | ||
4325 | unregister_as_ext2(); | 4813 | unregister_as_ext2(); |
4326 | unregister_as_ext3(); | 4814 | unregister_as_ext3(); |
4327 | unregister_filesystem(&ext4_fs_type); | 4815 | unregister_filesystem(&ext4_fs_type); |
4328 | destroy_inodecache(); | 4816 | destroy_inodecache(); |
4329 | exit_ext4_xattr(); | 4817 | ext4_exit_xattr(); |
4330 | exit_ext4_mballoc(); | 4818 | ext4_exit_mballoc(); |
4331 | remove_proc_entry("fs/ext4", NULL); | 4819 | remove_proc_entry("fs/ext4", NULL); |
4332 | kset_unregister(ext4_kset); | 4820 | kset_unregister(ext4_kset); |
4333 | exit_ext4_system_zone(); | 4821 | ext4_exit_system_zone(); |
4822 | ext4_exit_pageio(); | ||
4334 | } | 4823 | } |
4335 | 4824 | ||
4336 | MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); | 4825 | MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); |
4337 | MODULE_DESCRIPTION("Fourth Extended Filesystem"); | 4826 | MODULE_DESCRIPTION("Fourth Extended Filesystem"); |
4338 | MODULE_LICENSE("GPL"); | 4827 | MODULE_LICENSE("GPL"); |
4339 | module_init(init_ext4_fs) | 4828 | module_init(ext4_init_fs) |
4340 | module_exit(exit_ext4_fs) | 4829 | module_exit(ext4_exit_fs) |