f2fs: fix UAF in f2fs_available_free_memory
[linux-2.6-microblaze.git] / fs / f2fs / super.c
index 78ebc30..60cb2ed 100644 (file)
@@ -58,6 +58,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
        [FAULT_DISCARD]         = "discard error",
        [FAULT_WRITE_IO]        = "write IO error",
        [FAULT_SLAB_ALLOC]      = "slab alloc",
+       [FAULT_DQUOT_INIT]      = "dquot initialize",
 };
 
 void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
@@ -817,6 +818,10 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                                F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
                        } else if (!strcmp(name, "lfs")) {
                                F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
+                       } else if (!strcmp(name, "fragment:segment")) {
+                               F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG;
+                       } else if (!strcmp(name, "fragment:block")) {
+                               F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK;
                        } else {
                                kfree(name);
                                return -EINVAL;
@@ -1292,7 +1297,7 @@ default_check:
        /* Not pass down write hints if the number of active logs is lesser
         * than NR_CURSEG_PERSIST_TYPE.
         */
-       if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE)
+       if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_PERSIST_TYPE)
                F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
 
        if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
@@ -1896,6 +1901,10 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, "adaptive");
        else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS)
                seq_puts(seq, "lfs");
+       else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG)
+               seq_puts(seq, "fragment:segment");
+       else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
+               seq_puts(seq, "fragment:block");
        seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
        if (test_opt(sbi, RESERVE_ROOT))
                seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
@@ -2491,6 +2500,16 @@ retry:
        return len - towrite;
 }
 
+int f2fs_dquot_initialize(struct inode *inode)
+{
+       if (time_to_inject(F2FS_I_SB(inode), FAULT_DQUOT_INIT)) {
+               f2fs_show_injection_info(F2FS_I_SB(inode), FAULT_DQUOT_INIT);
+               return -ESRCH;
+       }
+
+       return dquot_initialize(inode);
+}
+
 static struct dquot **f2fs_get_dquots(struct inode *inode)
 {
        return F2FS_I(inode)->i_dquot;
@@ -2875,6 +2894,11 @@ static const struct quotactl_ops f2fs_quotactl_ops = {
        .get_nextdqblk  = dquot_get_next_dqblk,
 };
 #else
+int f2fs_dquot_initialize(struct inode *inode)
+{
+       return 0;
+}
+
 int f2fs_quota_sync(struct super_block *sb, int type)
 {
        return 0;
@@ -3487,7 +3511,7 @@ skip_cross:
                NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) {
                f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)",
                          cp_payload, nat_bits_blocks);
-               return -EFSCORRUPTED;
+               return 1;
        }
 
        if (unlikely(f2fs_cp_error(sbi))) {
@@ -3523,6 +3547,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH;
        sbi->migration_granularity = sbi->segs_per_sec;
        sbi->seq_file_ra_mul = MIN_RA_MUL;
+       sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
+       sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
 
        sbi->dir_level = DEF_DIR_LEVEL;
        sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
@@ -3747,6 +3773,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        unsigned int max_devices = MAX_DEVICES;
+       unsigned int logical_blksize;
        int i;
 
        /* Initialize single device information */
@@ -3767,6 +3794,9 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
        if (!sbi->devs)
                return -ENOMEM;
 
+       logical_blksize = bdev_logical_block_size(sbi->sb->s_bdev);
+       sbi->aligned_blksize = true;
+
        for (i = 0; i < max_devices; i++) {
 
                if (i > 0 && !RDEV(i).path[0])
@@ -3803,6 +3833,9 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                /* to release errored devices */
                sbi->s_ndevs = i + 1;
 
+               if (logical_blksize != bdev_logical_block_size(FDEV(i).bdev))
+                       sbi->aligned_blksize = false;
+
 #ifdef CONFIG_BLK_DEV_ZONED
                if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
                                !f2fs_sb_has_blkzoned(sbi)) {
@@ -4352,6 +4385,8 @@ free_node_inode:
 free_stats:
        f2fs_destroy_stats(sbi);
 free_nm:
+       /* stop discard thread before destroying node manager */
+       f2fs_stop_discard_thread(sbi);
        f2fs_destroy_node_manager(sbi);
 free_sm:
        f2fs_destroy_segment_manager(sbi);