]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/f2fs/super.c
Merge tag 'for-linus-20190420' of git://git.kernel.dk/linux-block
[linux.git] / fs / f2fs / super.c
index d1ccc52afc939b0514f2796ec545a138a2abd068..f2aaa2cc6b3e01e88a7aeea026cfaa97f73ae1de 100644 (file)
@@ -269,7 +269,7 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
        if (!qname) {
                f2fs_msg(sb, KERN_ERR,
                        "Not enough memory for storing quotafile name");
-               return -EINVAL;
+               return -ENOMEM;
        }
        if (F2FS_OPTION(sbi).s_qf_names[qtype]) {
                if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0)
@@ -586,7 +586,7 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_io_size_bits:
                        if (args->from && match_int(args, &arg))
                                return -EINVAL;
-                       if (arg > __ilog2_u32(BIO_MAX_PAGES)) {
+                       if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_PAGES)) {
                                f2fs_msg(sb, KERN_WARNING,
                                        "Not support %d, larger than %d",
                                        1 << arg, BIO_MAX_PAGES);
@@ -821,6 +821,8 @@ static int parse_options(struct super_block *sb, char *options)
        }
 
        if (test_opt(sbi, INLINE_XATTR_SIZE)) {
+               int min_size, max_size;
+
                if (!f2fs_sb_has_extra_attr(sbi) ||
                        !f2fs_sb_has_flexible_inline_xattr(sbi)) {
                        f2fs_msg(sb, KERN_ERR,
@@ -834,14 +836,15 @@ static int parse_options(struct super_block *sb, char *options)
                                        "set with inline_xattr option");
                        return -EINVAL;
                }
-               if (!F2FS_OPTION(sbi).inline_xattr_size ||
-                       F2FS_OPTION(sbi).inline_xattr_size >=
-                                       DEF_ADDRS_PER_INODE -
-                                       F2FS_TOTAL_EXTRA_ATTR_SIZE -
-                                       DEF_INLINE_RESERVED_SIZE -
-                                       DEF_MIN_INLINE_SIZE) {
+
+               min_size = sizeof(struct f2fs_xattr_header) / sizeof(__le32);
+               max_size = MAX_INLINE_XATTR_SIZE;
+
+               if (F2FS_OPTION(sbi).inline_xattr_size < min_size ||
+                               F2FS_OPTION(sbi).inline_xattr_size > max_size) {
                        f2fs_msg(sb, KERN_ERR,
-                                       "inline xattr size is out of range");
+                               "inline xattr size is out of range: %d ~ %d",
+                               min_size, max_size);
                        return -EINVAL;
                }
        }
@@ -915,6 +918,10 @@ static int f2fs_drop_inode(struct inode *inode)
                        sb_start_intwrite(inode->i_sb);
                        f2fs_i_size_write(inode, 0);
 
+                       f2fs_submit_merged_write_cond(F2FS_I_SB(inode),
+                                       inode, NULL, 0, DATA);
+                       truncate_inode_pages_final(inode->i_mapping);
+
                        if (F2FS_HAS_BLOCKS(inode))
                                f2fs_truncate(inode);
 
@@ -1048,7 +1055,7 @@ static void f2fs_put_super(struct super_block *sb)
        }
 
        /* be sure to wait for any on-going discard commands */
-       dropped = f2fs_wait_discard_bios(sbi);
+       dropped = f2fs_issue_discard_timeout(sbi);
 
        if ((f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) &&
                                        !sbi->discard_blks && !dropped) {
@@ -1075,7 +1082,10 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_bug_on(sbi, sbi->fsync_node_num);
 
        iput(sbi->node_inode);
+       sbi->node_inode = NULL;
+
        iput(sbi->meta_inode);
+       sbi->meta_inode = NULL;
 
        /*
         * iput() can update stat information, if f2fs_write_checkpoint()
@@ -1455,9 +1465,16 @@ static int f2fs_enable_quotas(struct super_block *sb);
 
 static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
 {
+       unsigned int s_flags = sbi->sb->s_flags;
        struct cp_control cpc;
-       int err;
+       int err = 0;
+       int ret;
 
+       if (s_flags & SB_RDONLY) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                               "checkpoint=disable on readonly fs");
+               return -EINVAL;
+       }
        sbi->sb->s_flags |= SB_ACTIVE;
 
        f2fs_update_time(sbi, DISABLE_TIME);
@@ -1465,18 +1482,24 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
        while (!f2fs_time_over(sbi, DISABLE_TIME)) {
                mutex_lock(&sbi->gc_mutex);
                err = f2fs_gc(sbi, true, false, NULL_SEGNO);
-               if (err == -ENODATA)
+               if (err == -ENODATA) {
+                       err = 0;
                        break;
+               }
                if (err && err != -EAGAIN)
-                       return err;
+                       break;
        }
 
-       err = sync_filesystem(sbi->sb);
-       if (err)
-               return err;
+       ret = sync_filesystem(sbi->sb);
+       if (ret || err) {
+               err = ret ? ret: err;
+               goto restore_flag;
+       }
 
-       if (f2fs_disable_cp_again(sbi))
-               return -EAGAIN;
+       if (f2fs_disable_cp_again(sbi)) {
+               err = -EAGAIN;
+               goto restore_flag;
+       }
 
        mutex_lock(&sbi->gc_mutex);
        cpc.reason = CP_PAUSE;
@@ -1485,7 +1508,9 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
 
        sbi->unusable_block_count = 0;
        mutex_unlock(&sbi->gc_mutex);
-       return 0;
+restore_flag:
+       sbi->sb->s_flags = s_flags;     /* Restore MS_RDONLY status */
+       return err;
 }
 
 static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
@@ -2023,6 +2048,12 @@ void f2fs_quota_off_umount(struct super_block *sb)
                        set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
                }
        }
+       /*
+        * In case of checkpoint=disable, we must flush quota blocks.
+        * This can cause NULL exception for node_inode in end_io, since
+        * put_super already dropped it.
+        */
+       sync_filesystem(sb);
 }
 
 static void f2fs_truncate_quota_inode_pages(struct super_block *sb)
@@ -2703,6 +2734,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL;
        sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL;
        sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL;
+       sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] =
+                               DEF_UMOUNT_DISCARD_TIMEOUT;
        clear_sbi_flag(sbi, SBI_NEED_FSCK);
 
        for (i = 0; i < NR_COUNT_TYPE; i++)
@@ -3022,10 +3055,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        struct f2fs_super_block *raw_super;
        struct inode *root;
        int err;
-       bool retry = true, need_fsck = false;
+       bool skip_recovery = false, need_fsck = false;
        char *options = NULL;
        int recovery, i, valid_super_block;
        struct curseg_info *seg_i;
+       int retry_cnt = 1;
 
 try_onemore:
        err = -EINVAL;
@@ -3097,7 +3131,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_maxbytes = sbi->max_file_blocks <<
                                le32_to_cpu(raw_super->log_blocksize);
        sb->s_max_links = F2FS_LINK_MAX;
-       get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 
 #ifdef CONFIG_QUOTA
        sb->dq_op = &f2fs_quota_operations;
@@ -3200,6 +3233,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 
        if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_QUOTA_NEED_FSCK_FLAG))
                set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+       if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_DISABLED_QUICK_FLAG)) {
+               set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
+               sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_QUICK_INTERVAL;
+       }
 
        /* Initialize device list */
        err = f2fs_scan_devices(sbi);
@@ -3288,7 +3325,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_root = d_make_root(root); /* allocate root dentry */
        if (!sb->s_root) {
                err = -ENOMEM;
-               goto free_root_inode;
+               goto free_node_inode;
        }
 
        err = f2fs_register_sysfs(sbi);
@@ -3310,7 +3347,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_meta;
 
        if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)))
-               goto skip_recovery;
+               goto reset_checkpoint;
 
        /* recover fsynced data */
        if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
@@ -3327,11 +3364,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                if (need_fsck)
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
 
-               if (!retry)
-                       goto skip_recovery;
+               if (skip_recovery)
+                       goto reset_checkpoint;
 
                err = f2fs_recover_fsync_data(sbi, false);
                if (err < 0) {
+                       if (err != -ENOMEM)
+                               skip_recovery = true;
                        need_fsck = true;
                        f2fs_msg(sb, KERN_ERR,
                                "Cannot recover all fsync data errno=%d", err);
@@ -3347,14 +3386,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                        goto free_meta;
                }
        }
-skip_recovery:
+reset_checkpoint:
        /* f2fs_recover_fsync_data() cleared this already */
        clear_sbi_flag(sbi, SBI_POR_DOING);
 
        if (test_opt(sbi, DISABLE_CHECKPOINT)) {
                err = f2fs_disable_checkpoint(sbi);
                if (err)
-                       goto free_meta;
+                       goto sync_free_meta;
        } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) {
                f2fs_enable_checkpoint(sbi);
        }
@@ -3367,7 +3406,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                /* After POR, we can run background GC thread.*/
                err = f2fs_start_gc_thread(sbi);
                if (err)
-                       goto free_meta;
+                       goto sync_free_meta;
        }
        kvfree(options);
 
@@ -3387,8 +3426,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                                cur_cp_version(F2FS_CKPT(sbi)));
        f2fs_update_time(sbi, CP_TIME);
        f2fs_update_time(sbi, REQ_TIME);
+       clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
        return 0;
 
+sync_free_meta:
+       /* safe to flush all the data */
+       sync_filesystem(sbi->sb);
+       retry_cnt = 0;
+
 free_meta:
 #ifdef CONFIG_QUOTA
        f2fs_truncate_quota_inode_pages(sb);
@@ -3402,6 +3447,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
         * falls into an infinite loop in f2fs_sync_meta_pages().
         */
        truncate_inode_pages_final(META_MAPPING(sbi));
+       /* evict some inodes being cached by GC */
+       evict_inodes(sb);
        f2fs_unregister_sysfs(sbi);
 free_root_inode:
        dput(sb->s_root);
@@ -3410,6 +3457,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        f2fs_release_ino_entry(sbi, true);
        truncate_inode_pages_final(NODE_MAPPING(sbi));
        iput(sbi->node_inode);
+       sbi->node_inode = NULL;
 free_stats:
        f2fs_destroy_stats(sbi);
 free_nm:
@@ -3422,6 +3470,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 free_meta_inode:
        make_bad_inode(sbi->meta_inode);
        iput(sbi->meta_inode);
+       sbi->meta_inode = NULL;
 free_io_dummy:
        mempool_destroy(sbi->write_io_dummy);
 free_percpu:
@@ -3443,8 +3492,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        kvfree(sbi);
 
        /* give only one another chance */
-       if (retry) {
-               retry = false;
+       if (retry_cnt > 0 && skip_recovery) {
+               retry_cnt--;
                shrink_dcache_sb(sb);
                goto try_onemore;
        }