]> Git Repo - linux.git/commitdiff
Merge tag 'f2fs-for-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
authorLinus Torvalds <[email protected]>
Sat, 4 Nov 2023 19:26:23 +0000 (09:26 -1000)
committerLinus Torvalds <[email protected]>
Sat, 4 Nov 2023 19:26:23 +0000 (09:26 -1000)
Pull f2fs updates from Jaegeuk Kim:
 "In this cycle, we introduce a bigger page size support by changing the
  internal f2fs's block size aligned to the page size. We also continue
  to improve zoned block device support regarding the power off
  recovery. As usual, there are some bug fixes regarding the error
  handling routines in compression and ioctl.

  Enhancements:
   - Support Block Size == Page Size
   - let f2fs_precache_extents() traverses in file range
   - stop iterating f2fs_map_block if hole exists
   - preload extent_cache for POSIX_FADV_WILLNEED
   - compress: fix to avoid fragment w/ OPU during f2fs_ioc_compress_file()

  Bug fixes:
   - do not return EFSCORRUPTED, but try to run online repair
   - finish previous checkpoints before returning from remount
   - fix error handling of __get_node_page and __f2fs_build_free_nids
   - clean up zones when not successfully unmounted
   - fix to initialize map.m_pblk in f2fs_precache_extents()
   - fix to drop meta_inode's page cache in f2fs_put_super()
   - set the default compress_level on ioctl
   - fix to avoid use-after-free on dic
   - fix to avoid redundant compress extension
   - do sanity check on cluster when CONFIG_F2FS_CHECK_FS is on
   - fix deadloop in f2fs_write_cache_pages()"

* tag 'f2fs-for-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: finish previous checkpoints before returning from remount
  f2fs: fix error handling of __get_node_page
  f2fs: do not return EFSCORRUPTED, but try to run online repair
  f2fs: fix error path of __f2fs_build_free_nids
  f2fs: Clean up errors in segment.h
  f2fs: clean up zones when not successfully unmounted
  f2fs: let f2fs_precache_extents() traverses in file range
  f2fs: avoid format-overflow warning
  f2fs: fix to initialize map.m_pblk in f2fs_precache_extents()
  f2fs: Support Block Size == Page Size
  f2fs: stop iterating f2fs_map_block if hole exists
  f2fs: preload extent_cache for POSIX_FADV_WILLNEED
  f2fs: set the default compress_level on ioctl
  f2fs: compress: fix to avoid fragment w/ OPU during f2fs_ioc_compress_file()
  f2fs: fix to drop meta_inode's page cache in f2fs_put_super()
  f2fs: split initial and dynamic conditions for extent_cache
  f2fs: compress: fix to avoid redundant compress extension
  f2fs: compress: do sanity check on cluster when CONFIG_F2FS_CHECK_FS is on
  f2fs: compress: fix to avoid use-after-free on dic
  f2fs: compress: fix deadloop in f2fs_write_cache_pages()

1  2 
fs/f2fs/file.c
fs/f2fs/inode.c
fs/f2fs/super.c
fs/f2fs/xattr.c

diff --combined fs/f2fs/file.c
index dd99abbb7186aa340ae1636f52b7416519a92514,304d0516d3a42dae7819e41b50de64b94a6dcc3f..e50363583f019a227ce3280ddb3ecd85760f8226
@@@ -798,7 -798,7 +798,7 @@@ int f2fs_truncate(struct inode *inode
        if (err)
                return err;
  
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        f2fs_mark_inode_dirty_sync(inode, false);
        return 0;
  }
@@@ -905,9 -905,9 +905,9 @@@ static void __setattr_copy(struct mnt_i
        i_uid_update(idmap, attr, inode);
        i_gid_update(idmap, attr, inode);
        if (ia_valid & ATTR_ATIME)
 -              inode->i_atime = attr->ia_atime;
 +              inode_set_atime_to_ts(inode, attr->ia_atime);
        if (ia_valid & ATTR_MTIME)
 -              inode->i_mtime = attr->ia_mtime;
 +              inode_set_mtime_to_ts(inode, attr->ia_mtime);
        if (ia_valid & ATTR_CTIME)
                inode_set_ctime_to_ts(inode, attr->ia_ctime);
        if (ia_valid & ATTR_MODE) {
@@@ -1012,7 -1012,7 +1012,7 @@@ int f2fs_setattr(struct mnt_idmap *idma
                        return err;
  
                spin_lock(&F2FS_I(inode)->i_size_lock);
 -              inode->i_mtime = inode_set_ctime_current(inode);
 +              inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
                F2FS_I(inode)->last_disk_size = i_size_read(inode);
                spin_unlock(&F2FS_I(inode)->i_size_lock);
        }
@@@ -1840,7 -1840,7 +1840,7 @@@ static long f2fs_fallocate(struct file 
        }
  
        if (!ret) {
 -              inode->i_mtime = inode_set_ctime_current(inode);
 +              inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
                f2fs_mark_inode_dirty_sync(inode, false);
                f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        }
@@@ -2888,10 -2888,10 +2888,10 @@@ out_src
        if (ret)
                goto out_unlock;
  
 -      src->i_mtime = inode_set_ctime_current(src);
 +      inode_set_mtime_to_ts(src, inode_set_ctime_current(src));
        f2fs_mark_inode_dirty_sync(src, false);
        if (src != dst) {
 -              dst->i_mtime = inode_set_ctime_current(dst);
 +              inode_set_mtime_to_ts(dst, inode_set_ctime_current(dst));
                f2fs_mark_inode_dirty_sync(dst, false);
        }
        f2fs_update_time(sbi, REQ_TIME);
@@@ -3258,11 -3258,12 +3258,12 @@@ int f2fs_precache_extents(struct inode 
                return -EOPNOTSUPP;
  
        map.m_lblk = 0;
+       map.m_pblk = 0;
        map.m_next_pgofs = NULL;
        map.m_next_extent = &m_next_extent;
        map.m_seg_type = NO_CHECK_TYPE;
        map.m_may_create = false;
-       end = max_file_blocks(inode);
+       end = F2FS_BLK_ALIGN(i_size_read(inode));
  
        while (map.m_lblk < end) {
                map.m_len = end - map.m_lblk;
                f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
                err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE);
                f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
-               if (err)
+               if (err || !map.m_len)
                        return err;
  
                map.m_lblk = m_next_extent;
@@@ -4005,6 -4006,15 +4006,15 @@@ static int f2fs_ioc_set_compress_option
        F2FS_I(inode)->i_compress_algorithm = option.algorithm;
        F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size;
        F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size);
+       /* Set default level */
+       if (F2FS_I(inode)->i_compress_algorithm == COMPRESS_ZSTD)
+               F2FS_I(inode)->i_compress_level = F2FS_ZSTD_DEFAULT_CLEVEL;
+       else
+               F2FS_I(inode)->i_compress_level = 0;
+       /* Adjust mount option level */
+       if (option.algorithm == F2FS_OPTION(sbi).compress_algorithm &&
+           F2FS_OPTION(sbi).compress_level)
+               F2FS_I(inode)->i_compress_level = F2FS_OPTION(sbi).compress_level;
        f2fs_mark_inode_dirty_sync(inode, true);
  
        if (!f2fs_is_compress_backend_ready(inode))
@@@ -4849,6 -4859,9 +4859,9 @@@ static int f2fs_file_fadvise(struct fil
                filp->f_mode &= ~FMODE_RANDOM;
                spin_unlock(&filp->f_lock);
                return 0;
+       } else if (advice == POSIX_FADV_WILLNEED && offset == 0) {
+               /* Load extent cache at the first readahead. */
+               f2fs_precache_extents(inode);
        }
  
        err = generic_fadvise(filp, offset, len, advice);
diff --combined fs/f2fs/inode.c
index 5779c7edd49b753d3e032d50f00ed0f79ecfa65b,cafb815883594df2eebca034a2690b8b1bd8a180..560bfcad1af2356c761446c93c67d90110f041f3
@@@ -315,7 -315,7 +315,7 @@@ static bool sanity_check_inode(struct i
                        f2fs_has_inline_xattr(inode) &&
                        (!fi->i_inline_xattr_size ||
                        fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) {
-                       f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, max: %zu",
+                       f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, max: %lu",
                                  __func__, inode->i_ino, fi->i_inline_xattr_size,
                                  MAX_INLINE_XATTR_SIZE);
                        return false;
@@@ -386,9 -386,9 +386,9 @@@ static void init_idisk_time(struct inod
  {
        struct f2fs_inode_info *fi = F2FS_I(inode);
  
 -      fi->i_disk_time[0] = inode->i_atime;
 +      fi->i_disk_time[0] = inode_get_atime(inode);
        fi->i_disk_time[1] = inode_get_ctime(inode);
 -      fi->i_disk_time[2] = inode->i_mtime;
 +      fi->i_disk_time[2] = inode_get_mtime(inode);
  }
  
  static int do_read_inode(struct inode *inode)
        inode->i_size = le64_to_cpu(ri->i_size);
        inode->i_blocks = SECTOR_FROM_BLOCK(le64_to_cpu(ri->i_blocks) - 1);
  
 -      inode->i_atime.tv_sec = le64_to_cpu(ri->i_atime);
 +      inode_set_atime(inode, le64_to_cpu(ri->i_atime),
 +                      le32_to_cpu(ri->i_atime_nsec));
        inode_set_ctime(inode, le64_to_cpu(ri->i_ctime),
                        le32_to_cpu(ri->i_ctime_nsec));
 -      inode->i_mtime.tv_sec = le64_to_cpu(ri->i_mtime);
 -      inode->i_atime.tv_nsec = le32_to_cpu(ri->i_atime_nsec);
 -      inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
 +      inode_set_mtime(inode, le64_to_cpu(ri->i_mtime),
 +                      le32_to_cpu(ri->i_mtime_nsec));
        inode->i_generation = le32_to_cpu(ri->i_generation);
        if (S_ISDIR(inode->i_mode))
                fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
@@@ -698,12 -698,12 +698,12 @@@ void f2fs_update_inode(struct inode *in
        }
        set_raw_inline(inode, ri);
  
 -      ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
 -      ri->i_ctime = cpu_to_le64(inode_get_ctime(inode).tv_sec);
 -      ri->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec);
 -      ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
 -      ri->i_ctime_nsec = cpu_to_le32(inode_get_ctime(inode).tv_nsec);
 -      ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
 +      ri->i_atime = cpu_to_le64(inode_get_atime_sec(inode));
 +      ri->i_ctime = cpu_to_le64(inode_get_ctime_sec(inode));
 +      ri->i_mtime = cpu_to_le64(inode_get_mtime_sec(inode));
 +      ri->i_atime_nsec = cpu_to_le32(inode_get_atime_nsec(inode));
 +      ri->i_ctime_nsec = cpu_to_le32(inode_get_ctime_nsec(inode));
 +      ri->i_mtime_nsec = cpu_to_le32(inode_get_mtime_nsec(inode));
        if (S_ISDIR(inode->i_mode))
                ri->i_current_depth =
                        cpu_to_le32(F2FS_I(inode)->i_current_depth);
diff --combined fs/f2fs/super.c
index 05f9f7b6ebf8c63a2f482bd1ba1a50836727cd40,f266cc385d71fe8c43e4114af9d060673316c3ac..1ed68158bac5c8935bd01b10e76020f2575e67b9
@@@ -83,26 -83,11 +83,26 @@@ void f2fs_build_fault_attr(struct f2fs_
  #endif
  
  /* f2fs-wide shrinker description */
 -static struct shrinker f2fs_shrinker_info = {
 -      .scan_objects = f2fs_shrink_scan,
 -      .count_objects = f2fs_shrink_count,
 -      .seeks = DEFAULT_SEEKS,
 -};
 +static struct shrinker *f2fs_shrinker_info;
 +
 +static int __init f2fs_init_shrinker(void)
 +{
 +      f2fs_shrinker_info = shrinker_alloc(0, "f2fs-shrinker");
 +      if (!f2fs_shrinker_info)
 +              return -ENOMEM;
 +
 +      f2fs_shrinker_info->count_objects = f2fs_shrink_count;
 +      f2fs_shrinker_info->scan_objects = f2fs_shrink_scan;
 +
 +      shrinker_register(f2fs_shrinker_info);
 +
 +      return 0;
 +}
 +
 +static void f2fs_exit_shrinker(void)
 +{
 +      shrinker_free(f2fs_shrinker_info);
 +}
  
  enum {
        Opt_gc_background,
@@@ -562,6 -547,29 +562,29 @@@ static int f2fs_set_test_dummy_encrypti
  }
  
  #ifdef CONFIG_F2FS_FS_COMPRESSION
+ static bool is_compress_extension_exist(struct f2fs_sb_info *sbi,
+                                       const char *new_ext, bool is_ext)
+ {
+       unsigned char (*ext)[F2FS_EXTENSION_LEN];
+       int ext_cnt;
+       int i;
+       if (is_ext) {
+               ext = F2FS_OPTION(sbi).extensions;
+               ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
+       } else {
+               ext = F2FS_OPTION(sbi).noextensions;
+               ext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
+       }
+       for (i = 0; i < ext_cnt; i++) {
+               if (!strcasecmp(new_ext, ext[i]))
+                       return true;
+       }
+       return false;
+ }
  /*
   * 1. The same extension name cannot not appear in both compress and non-compress extension
   * at the same time.
@@@ -1164,6 -1172,11 +1187,11 @@@ static int parse_options(struct super_b
                                return -EINVAL;
                        }
  
+                       if (is_compress_extension_exist(sbi, name, true)) {
+                               kfree(name);
+                               break;
+                       }
                        strcpy(ext[ext_cnt], name);
                        F2FS_OPTION(sbi).compress_ext_cnt++;
                        kfree(name);
                                return -EINVAL;
                        }
  
+                       if (is_compress_extension_exist(sbi, name, false)) {
+                               kfree(name);
+                               break;
+                       }
                        strcpy(noext[noext_cnt], name);
                        F2FS_OPTION(sbi).nocompress_ext_cnt++;
                        kfree(name);
@@@ -1577,7 -1595,7 +1610,7 @@@ static void destroy_device_list(struct 
  
        for (i = 0; i < sbi->s_ndevs; i++) {
                if (i > 0)
 -                      blkdev_put(FDEV(i).bdev, sbi->sb);
 +                      bdev_release(FDEV(i).bdev_handle);
  #ifdef CONFIG_BLK_DEV_ZONED
                kvfree(FDEV(i).blkz_seq);
  #endif
@@@ -1644,7 -1662,7 +1677,7 @@@ static void f2fs_put_super(struct super
  
        f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA);
  
-       if (err) {
+       if (err || f2fs_cp_error(sbi)) {
                truncate_inode_pages_final(NODE_MAPPING(sbi));
                truncate_inode_pages_final(META_MAPPING(sbi));
        }
@@@ -2301,9 -2319,9 +2334,9 @@@ static int f2fs_remount(struct super_bl
        unsigned long old_sb_flags;
        int err;
        bool need_restart_gc = false, need_stop_gc = false;
-       bool need_restart_ckpt = false, need_stop_ckpt = false;
        bool need_restart_flush = false, need_stop_flush = false;
        bool need_restart_discard = false, need_stop_discard = false;
+       bool need_enable_checkpoint = false, need_disable_checkpoint = false;
        bool no_read_extent_cache = !test_opt(sbi, READ_EXTENT_CACHE);
        bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE);
        bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT);
                clear_sbi_flag(sbi, SBI_IS_CLOSE);
        }
  
-       if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
-                       !test_opt(sbi, MERGE_CHECKPOINT)) {
-               f2fs_stop_ckpt_thread(sbi);
-               need_restart_ckpt = true;
-       } else {
-               /* Flush if the prevous checkpoint, if exists. */
-               f2fs_flush_ckpt_thread(sbi);
-               err = f2fs_start_ckpt_thread(sbi);
-               if (err) {
-                       f2fs_err(sbi,
-                           "Failed to start F2FS issue_checkpoint_thread (%d)",
-                           err);
-                       goto restore_gc;
-               }
-               need_stop_ckpt = true;
-       }
        /*
         * We stop issue flush thread if FS is mounted as RO
         * or if flush_merge is not passed in mount option.
        } else {
                err = f2fs_create_flush_cmd_control(sbi);
                if (err)
-                       goto restore_ckpt;
+                       goto restore_gc;
                need_stop_flush = true;
        }
  
                        err = f2fs_disable_checkpoint(sbi);
                        if (err)
                                goto restore_discard;
+                       need_enable_checkpoint = true;
                } else {
                        f2fs_enable_checkpoint(sbi);
+                       need_disable_checkpoint = true;
+               }
+       }
+       /*
+        * Place this routine at the end, since a new checkpoint would be
+        * triggered while remount and we need to take care of it before
+        * returning from remount.
+        */
+       if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
+                       !test_opt(sbi, MERGE_CHECKPOINT)) {
+               f2fs_stop_ckpt_thread(sbi);
+       } else {
+               /* Flush if the prevous checkpoint, if exists. */
+               f2fs_flush_ckpt_thread(sbi);
+               err = f2fs_start_ckpt_thread(sbi);
+               if (err) {
+                       f2fs_err(sbi,
+                           "Failed to start F2FS issue_checkpoint_thread (%d)",
+                           err);
+                       goto restore_checkpoint;
                }
        }
  
@@@ -2537,6 -2560,13 +2575,13 @@@ skip
        adjust_unusable_cap_perc(sbi);
        *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
        return 0;
+ restore_checkpoint:
+       if (need_enable_checkpoint) {
+               f2fs_enable_checkpoint(sbi);
+       } else if (need_disable_checkpoint) {
+               if (f2fs_disable_checkpoint(sbi))
+                       f2fs_warn(sbi, "checkpoint has not been disabled");
+       }
  restore_discard:
        if (need_restart_discard) {
                if (f2fs_start_discard_thread(sbi))
@@@ -2552,13 -2582,6 +2597,6 @@@ restore_flush
                clear_opt(sbi, FLUSH_MERGE);
                f2fs_destroy_flush_cmd_control(sbi, false);
        }
- restore_ckpt:
-       if (need_restart_ckpt) {
-               if (f2fs_start_ckpt_thread(sbi))
-                       f2fs_warn(sbi, "background ckpt thread has stopped");
-       } else if (need_stop_ckpt) {
-               f2fs_stop_ckpt_thread(sbi);
-       }
  restore_gc:
        if (need_restart_gc) {
                if (f2fs_start_gc_thread(sbi))
@@@ -2725,7 -2748,7 +2763,7 @@@ retry
  
        if (len == towrite)
                return err;
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        f2fs_mark_inode_dirty_sync(inode, false);
        return len - towrite;
  }
@@@ -3218,6 -3241,13 +3256,6 @@@ static bool f2fs_has_stable_inodes(stru
        return true;
  }
  
 -static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
 -                                     int *ino_bits_ret, int *lblk_bits_ret)
 -{
 -      *ino_bits_ret = 8 * sizeof(nid_t);
 -      *lblk_bits_ret = 8 * sizeof(block_t);
 -}
 -
  static struct block_device **f2fs_get_devices(struct super_block *sb,
                                              unsigned int *num_devs)
  {
  }
  
  static const struct fscrypt_operations f2fs_cryptops = {
 -      .key_prefix             = "f2fs:",
 +      .needs_bounce_pages     = 1,
 +      .has_32bit_inodes       = 1,
 +      .supports_subblock_data_units = 1,
 +      .legacy_key_prefix      = "f2fs:",
        .get_context            = f2fs_get_context,
        .set_context            = f2fs_set_context,
        .get_dummy_policy       = f2fs_get_dummy_policy,
        .empty_dir              = f2fs_empty_dir,
        .has_stable_inodes      = f2fs_has_stable_inodes,
 -      .get_ino_and_lblk_bits  = f2fs_get_ino_and_lblk_bits,
        .get_devices            = f2fs_get_devices,
  };
  #endif
@@@ -3479,7 -3507,7 +3517,7 @@@ static int sanity_check_raw_super(struc
                return -EFSCORRUPTED;
        }
  
-       /* Currently, support 512/1024/2048/4096 bytes sector size */
+       /* Currently, support 512/1024/2048/4096/16K bytes sector size */
        if (le32_to_cpu(raw_super->log_sectorsize) >
                                F2FS_MAX_LOG_SECTOR_SIZE ||
                le32_to_cpu(raw_super->log_sectorsize) <
@@@ -4208,7 -4236,7 +4246,7 @@@ static int f2fs_scan_devices(struct f2f
  
        for (i = 0; i < max_devices; i++) {
                if (i == 0)
 -                      FDEV(0).bdev = sbi->sb->s_bdev;
 +                      FDEV(0).bdev_handle = sbi->sb->s_bdev_handle;
                else if (!RDEV(i).path[0])
                        break;
  
                                FDEV(i).end_blk = FDEV(i).start_blk +
                                        (FDEV(i).total_segments <<
                                        sbi->log_blocks_per_seg) - 1;
 -                              FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path,
 -                                      mode, sbi->sb, NULL);
 +                              FDEV(i).bdev_handle = bdev_open_by_path(
 +                                      FDEV(i).path, mode, sbi->sb, NULL);
                        }
                }
 -              if (IS_ERR(FDEV(i).bdev))
 -                      return PTR_ERR(FDEV(i).bdev);
 +              if (IS_ERR(FDEV(i).bdev_handle))
 +                      return PTR_ERR(FDEV(i).bdev_handle);
  
 +              FDEV(i).bdev = FDEV(i).bdev_handle->bdev;
                /* to release errored devices */
                sbi->s_ndevs = i + 1;
  
@@@ -4926,7 -4953,7 +4964,7 @@@ static int __init init_f2fs_fs(void
        int err;
  
        if (PAGE_SIZE != F2FS_BLKSIZE) {
-               printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n",
+               printk("F2FS not supported on PAGE_SIZE(%lu) != BLOCK_SIZE(%lu)\n",
                                PAGE_SIZE, F2FS_BLKSIZE);
                return -EINVAL;
        }
        err = f2fs_init_sysfs();
        if (err)
                goto free_garbage_collection_cache;
 -      err = register_shrinker(&f2fs_shrinker_info, "f2fs-shrinker");
 +      err = f2fs_init_shrinker();
        if (err)
                goto free_sysfs;
        err = register_filesystem(&f2fs_fs_type);
@@@ -5000,7 -5027,7 +5038,7 @@@ free_root_stats
        f2fs_destroy_root_stats();
        unregister_filesystem(&f2fs_fs_type);
  free_shrinker:
 -      unregister_shrinker(&f2fs_shrinker_info);
 +      f2fs_exit_shrinker();
  free_sysfs:
        f2fs_exit_sysfs();
  free_garbage_collection_cache:
@@@ -5032,7 -5059,7 +5070,7 @@@ static void __exit exit_f2fs_fs(void
        f2fs_destroy_post_read_processing();
        f2fs_destroy_root_stats();
        unregister_filesystem(&f2fs_fs_type);
 -      unregister_shrinker(&f2fs_shrinker_info);
 +      f2fs_exit_shrinker();
        f2fs_exit_sysfs();
        f2fs_destroy_garbage_collection_cache();
        f2fs_destroy_extent_cache();
diff --combined fs/f2fs/xattr.c
index 4314456854f64cbebc0b1fa6e47504da957e7639,465d145360de31f406e116560b70875ef030ef8d..47e88b4d4e7d01aaadc38c61922060e5a8884399
@@@ -189,7 -189,7 +189,7 @@@ const struct xattr_handler f2fs_xattr_s
        .set    = f2fs_xattr_generic_set,
  };
  
 -static const struct xattr_handler *f2fs_xattr_handler_map[] = {
 +static const struct xattr_handler * const f2fs_xattr_handler_map[] = {
        [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler,
  #ifdef CONFIG_F2FS_FS_POSIX_ACL
        [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &nop_posix_acl_access,
        [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler,
  };
  
 -const struct xattr_handler *f2fs_xattr_handlers[] = {
 +const struct xattr_handler * const f2fs_xattr_handlers[] = {
        &f2fs_xattr_user_handler,
        &f2fs_xattr_trusted_handler,
  #ifdef CONFIG_F2FS_FS_SECURITY
@@@ -364,10 -364,10 +364,10 @@@ static int lookup_all_xattrs(struct ino
  
        *xe = __find_xattr(cur_addr, last_txattr_addr, NULL, index, len, name);
        if (!*xe) {
-               f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+               f2fs_err(F2FS_I_SB(inode), "lookup inode (%lu) has corrupted xattr",
                                                                inode->i_ino);
                set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
-               err = -EFSCORRUPTED;
+               err = -ENODATA;
                f2fs_handle_error(F2FS_I_SB(inode),
                                        ERROR_CORRUPTED_XATTR);
                goto out;
@@@ -584,13 -584,12 +584,12 @@@ ssize_t f2fs_listxattr(struct dentry *d
  
                if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
                        (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
-                       f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+                       f2fs_err(F2FS_I_SB(inode), "list inode (%lu) has corrupted xattr",
                                                inode->i_ino);
                        set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
-                       error = -EFSCORRUPTED;
                        f2fs_handle_error(F2FS_I_SB(inode),
                                                ERROR_CORRUPTED_XATTR);
-                       goto cleanup;
+                       break;
                }
  
                if (!prefix)
@@@ -650,7 -649,7 +649,7 @@@ static int __f2fs_setxattr(struct inod
  
        if (size > MAX_VALUE_LEN(inode))
                return -E2BIG;
+ retry:
        error = read_all_xattrs(inode, ipage, &base_addr);
        if (error)
                return error;
        /* find entry with wanted name. */
        here = __find_xattr(base_addr, last_base_addr, NULL, index, len, name);
        if (!here) {
-               f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+               if (!F2FS_I(inode)->i_xattr_nid) {
+                       f2fs_notice(F2FS_I_SB(inode),
+                               "recover xattr in inode (%lu)", inode->i_ino);
+                       f2fs_recover_xattr_data(inode, NULL);
+                       kfree(base_addr);
+                       goto retry;
+               }
+               f2fs_err(F2FS_I_SB(inode), "set inode (%lu) has corrupted xattr",
                                                                inode->i_ino);
                set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
                error = -EFSCORRUPTED;
This page took 0.114893 seconds and 4 git commands to generate.