Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs...
[pandora-kernel.git] / fs / ext4 / super.c
index fc827bb..cc5c157 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/ctype.h>
 #include <linux/log2.h>
 #include <linux/crc16.h>
+#include <linux/cleancache.h>
 #include <asm/uaccess.h>
 
 #include <linux/kthread.h>
@@ -822,6 +823,8 @@ static void ext4_put_super(struct super_block *sb)
                invalidate_bdev(sbi->journal_bdev);
                ext4_blkdev_remove(sbi);
        }
+       if (sbi->s_mmp_tsk)
+               kthread_stop(sbi->s_mmp_tsk);
        sb->s_fs_info = NULL;
        /*
         * Now that we are completely done shutting down the
@@ -1112,7 +1115,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
 
        if (!test_opt(sb, INIT_INODE_TABLE))
                seq_puts(seq, ",noinit_inode_table");
-       else if (sbi->s_li_wait_mult)
+       else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)
                seq_printf(seq, ",init_inode_table=%u",
                           (unsigned) sbi->s_li_wait_mult);
 
@@ -1914,7 +1917,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                ext4_msg(sb, KERN_WARNING,
                         "warning: mounting fs with errors, "
                         "running e2fsck is recommended");
-       else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+       else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 &&
                 le16_to_cpu(es->s_mnt_count) >=
                 (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
                ext4_msg(sb, KERN_WARNING,
@@ -1946,6 +1949,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                        EXT4_INODES_PER_GROUP(sb),
                        sbi->s_mount_opt, sbi->s_mount_opt2);
 
+       cleancache_init_fs(sb);
        return res;
 }
 
@@ -2439,6 +2443,18 @@ static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a,
                          EXT4_SB(sb)->s_sectors_written_start) >> 1)));
 }
 
+static ssize_t extent_cache_hits_show(struct ext4_attr *a,
+                                     struct ext4_sb_info *sbi, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%lu\n", sbi->extent_cache_hits);
+}
+
+static ssize_t extent_cache_misses_show(struct ext4_attr *a,
+                                       struct ext4_sb_info *sbi, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%lu\n", sbi->extent_cache_misses);
+}
+
 static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
                                          struct ext4_sb_info *sbi,
                                          const char *buf, size_t count)
@@ -2496,6 +2512,8 @@ static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
 EXT4_RO_ATTR(delayed_allocation_blocks);
 EXT4_RO_ATTR(session_write_kbytes);
 EXT4_RO_ATTR(lifetime_write_kbytes);
+EXT4_RO_ATTR(extent_cache_hits);
+EXT4_RO_ATTR(extent_cache_misses);
 EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
                 inode_readahead_blks_store, s_inode_readahead_blks);
 EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);
@@ -2511,6 +2529,8 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(delayed_allocation_blocks),
        ATTR_LIST(session_write_kbytes),
        ATTR_LIST(lifetime_write_kbytes),
+       ATTR_LIST(extent_cache_hits),
+       ATTR_LIST(extent_cache_misses),
        ATTR_LIST(inode_readahead_blks),
        ATTR_LIST(inode_goal),
        ATTR_LIST(mb_stats),
@@ -2673,12 +2693,6 @@ static void print_daily_error_info(unsigned long arg)
        mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ);  /* Once a day */
 }
 
-static void ext4_lazyinode_timeout(unsigned long data)
-{
-       struct task_struct *p = (struct task_struct *)data;
-       wake_up_process(p);
-}
-
 /* Find next suitable group and run ext4_init_inode_table */
 static int ext4_run_li_request(struct ext4_li_request *elr)
 {
@@ -2710,11 +2724,8 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
                ret = ext4_init_inode_table(sb, group,
                                            elr->lr_timeout ? 0 : 1);
                if (elr->lr_timeout == 0) {
-                       timeout = jiffies - timeout;
-                       if (elr->lr_sbi->s_li_wait_mult)
-                               timeout *= elr->lr_sbi->s_li_wait_mult;
-                       else
-                               timeout *= 20;
+                       timeout = (jiffies - timeout) *
+                                 elr->lr_sbi->s_li_wait_mult;
                        elr->lr_timeout = timeout;
                }
                elr->lr_next_sched = jiffies + elr->lr_timeout;
@@ -2726,7 +2737,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
 
 /*
  * Remove lr_request from the list_request and free the
- * request tructure. Should be called with li_list_mtx held
+ * request structure. Should be called with li_list_mtx held
  */
 static void ext4_remove_li_request(struct ext4_li_request *elr)
 {
@@ -2744,14 +2755,16 @@ static void ext4_remove_li_request(struct ext4_li_request *elr)
 
 static void ext4_unregister_li_request(struct super_block *sb)
 {
-       struct ext4_li_request *elr = EXT4_SB(sb)->s_li_request;
-
-       if (!ext4_li_info)
+       mutex_lock(&ext4_li_mtx);
+       if (!ext4_li_info) {
+               mutex_unlock(&ext4_li_mtx);
                return;
+       }
 
        mutex_lock(&ext4_li_info->li_list_mtx);
-       ext4_remove_li_request(elr);
+       ext4_remove_li_request(EXT4_SB(sb)->s_li_request);
        mutex_unlock(&ext4_li_info->li_list_mtx);
+       mutex_unlock(&ext4_li_mtx);
 }
 
 static struct task_struct *ext4_lazyinit_task;
@@ -2770,17 +2783,10 @@ static int ext4_lazyinit_thread(void *arg)
        struct ext4_lazy_init *eli = (struct ext4_lazy_init *)arg;
        struct list_head *pos, *n;
        struct ext4_li_request *elr;
-       unsigned long next_wakeup;
-       DEFINE_WAIT(wait);
+       unsigned long next_wakeup, cur;
 
        BUG_ON(NULL == eli);
 
-       eli->li_timer.data = (unsigned long)current;
-       eli->li_timer.function = ext4_lazyinode_timeout;
-
-       eli->li_task = current;
-       wake_up(&eli->li_wait_task);
-
 cont_thread:
        while (true) {
                next_wakeup = MAX_JIFFY_OFFSET;
@@ -2811,19 +2817,15 @@ cont_thread:
                if (freezing(current))
                        refrigerator();
 
-               if ((time_after_eq(jiffies, next_wakeup)) ||
+               cur = jiffies;
+               if ((time_after_eq(cur, next_wakeup)) ||
                    (MAX_JIFFY_OFFSET == next_wakeup)) {
                        cond_resched();
                        continue;
                }
 
-               eli->li_timer.expires = next_wakeup;
-               add_timer(&eli->li_timer);
-               prepare_to_wait(&eli->li_wait_daemon, &wait,
-                               TASK_INTERRUPTIBLE);
-               if (time_before(jiffies, next_wakeup))
-                       schedule();
-               finish_wait(&eli->li_wait_daemon, &wait);
+               schedule_timeout_interruptible(next_wakeup - cur);
+
                if (kthread_should_stop()) {
                        ext4_clear_request_list();
                        goto exit_thread;
@@ -2847,12 +2849,7 @@ exit_thread:
                goto cont_thread;
        }
        mutex_unlock(&eli->li_list_mtx);
-       del_timer_sync(&ext4_li_info->li_timer);
-       eli->li_task = NULL;
-       wake_up(&eli->li_wait_task);
-
        kfree(ext4_li_info);
-       ext4_lazyinit_task = NULL;
        ext4_li_info = NULL;
        mutex_unlock(&ext4_li_mtx);
 
@@ -2880,7 +2877,6 @@ static int ext4_run_lazyinit_thread(void)
        if (IS_ERR(ext4_lazyinit_task)) {
                int err = PTR_ERR(ext4_lazyinit_task);
                ext4_clear_request_list();
-               del_timer_sync(&ext4_li_info->li_timer);
                kfree(ext4_li_info);
                ext4_li_info = NULL;
                printk(KERN_CRIT "EXT4: error %d creating inode table "
@@ -2889,8 +2885,6 @@ static int ext4_run_lazyinit_thread(void)
                return err;
        }
        ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING;
-
-       wait_event(ext4_li_info->li_wait_task, ext4_li_info->li_task != NULL);
        return 0;
 }
 
@@ -2925,13 +2919,9 @@ static int ext4_li_info_new(void)
        if (!eli)
                return -ENOMEM;
 
-       eli->li_task = NULL;
        INIT_LIST_HEAD(&eli->li_request_list);
        mutex_init(&eli->li_list_mtx);
 
-       init_waitqueue_head(&eli->li_wait_daemon);
-       init_waitqueue_head(&eli->li_wait_task);
-       init_timer(&eli->li_timer);
        eli->li_state |= EXT4_LAZYINIT_QUIT;
 
        ext4_li_info = eli;
@@ -2974,8 +2964,14 @@ static int ext4_register_li_request(struct super_block *sb,
        ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
        int ret = 0;
 
-       if (sbi->s_li_request != NULL)
+       if (sbi->s_li_request != NULL) {
+               /*
+                * Reset timeout so it can be computed again, because
+                * s_li_wait_mult might have changed.
+                */
+               sbi->s_li_request->lr_timeout = 0;
                return 0;
+       }
 
        if (first_not_zeroed == ngroups ||
            (sb->s_flags & MS_RDONLY) ||
@@ -3173,6 +3169,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
            ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
                set_opt(sb, DELALLOC);
 
+       /*
+        * set default s_li_wait_mult for lazyinit, for the case there is
+        * no mount option specified.
+        */
+       sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
+
        if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
                           &journal_devnum, &journal_ioprio, NULL, 0)) {
                ext4_msg(sb, KERN_WARNING,
@@ -3488,6 +3490,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                          EXT4_HAS_INCOMPAT_FEATURE(sb,
                                    EXT4_FEATURE_INCOMPAT_RECOVER));
 
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
+           !(sb->s_flags & MS_RDONLY))
+               if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
+                       goto failed_mount3;
+
        /*
         * The first inode we look at is the journal inode.  Don't try
         * root first: it may be modified in the journal!
@@ -3503,7 +3510,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount_wq;
        } else {
                clear_opt(sb, DATA_FLAGS);
-               set_opt(sb, WRITEBACK_DATA);
                sbi->s_journal = NULL;
                needs_recovery = 0;
                goto no_journal;
@@ -3736,6 +3742,8 @@ failed_mount3:
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
        percpu_counter_destroy(&sbi->s_dirs_counter);
        percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
+       if (sbi->s_mmp_tsk)
+               kthread_stop(sbi->s_mmp_tsk);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -4271,7 +4279,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        int enable_quota = 0;
        ext4_group_t g;
        unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
-       int err;
+       int err = 0;
 #ifdef CONFIG_QUOTA
        int i;
 #endif
@@ -4397,6 +4405,13 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                goto restore_opts;
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
+                       if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+                                                    EXT4_FEATURE_INCOMPAT_MMP))
+                               if (ext4_multi_mount_protect(sb,
+                                               le64_to_cpu(es->s_mmp_block))) {
+                                       err = -EROFS;
+                                       goto restore_opts;
+                               }
                        enable_quota = 1;
                }
        }
@@ -4461,6 +4476,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_super_block *es = sbi->s_es;
        u64 fsid;
+       s64 bfree;
 
        if (test_opt(sb, MINIX_DF)) {
                sbi->s_overhead_last = 0;
@@ -4504,8 +4520,10 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_type = EXT4_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
-       buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) -
+       bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter) -
                       percpu_counter_sum_positive(&sbi->s_dirtyblocks_counter);
+       /* prevent underflow in case that few free space is available */
+       buf->f_bfree = max_t(s64, bfree, 0);
        buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
        if (buf->f_bfree < ext4_r_blocks_count(es))
                buf->f_bavail = 0;
@@ -4681,6 +4699,9 @@ static int ext4_quota_off(struct super_block *sb, int type)
        if (test_opt(sb, DELALLOC))
                sync_filesystem(sb);
 
+       if (!inode)
+               goto out;
+
        /* Update modification times of quota files when userspace can
         * start looking at them */
        handle = ext4_journal_start(inode, 1);