[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <202507210558.sazSHcm1-lkp@intel.com>
Date: Mon, 21 Jul 2025 06:41:09 +0800
From: kernel test robot <lkp@...el.com>
To: Nicolas Bretz <bretznic@...il.com>, tytso@....edu,
adilger.kernel@...ger.ca
Cc: oe-kbuild-all@...ts.linux.dev, linux-ext4@...r.kernel.org,
Nicolas Bretz <bretznic@...il.com>,
kernel test robot <lkp@...el.com>
Subject: Re: [PATCH v2] ext4: clear extent index structure after file delete
Hi Nicolas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tytso-ext4/dev]
[also build test WARNING on linus/master v6.16-rc6 next-20250718]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nicolas-Bretz/ext4-clear-extent-index-structure-after-file-delete/20250718-202802
base: https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev
patch link: https://lore.kernel.org/r/20250718122654.1431747-1-bretznic%40gmail.com
patch subject: [PATCH v2] ext4: clear extent index structure after file delete
config: csky-randconfig-r121-20250720 (https://download.01.org/0day-ci/archive/20250721/202507210558.sazSHcm1-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 11.5.0
reproduce: (https://download.01.org/0day-ci/archive/20250721/202507210558.sazSHcm1-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@...el.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202507210558.sazSHcm1-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> fs/ext4/extents.c:3065:55: sparse: sparse: restricted __le16 degrades to integer
vim +3065 fs/ext4/extents.c
2818
2819 int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
2820 ext4_lblk_t end)
2821 {
2822 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
2823 int depth = ext_depth(inode);
2824 struct ext4_ext_path *path = NULL;
2825 struct ext4_extent_idx *ix = NULL;
2826 struct partial_cluster partial;
2827 handle_t *handle;
2828 int i = 0, err = 0;
2829 int flags = EXT4_EX_NOCACHE | EXT4_EX_NOFAIL;
2830
2831 partial.pclu = 0;
2832 partial.lblk = 0;
2833 partial.state = initial;
2834
2835 ext_debug(inode, "truncate since %u to %u\n", start, end);
2836
2837 /* probably first extent we're gonna free will be last in block */
2838 handle = ext4_journal_start_with_revoke(inode, EXT4_HT_TRUNCATE,
2839 depth + 1,
2840 ext4_free_metadata_revoke_credits(inode->i_sb, depth));
2841 if (IS_ERR(handle))
2842 return PTR_ERR(handle);
2843
2844 again:
2845 trace_ext4_ext_remove_space(inode, start, end, depth);
2846
2847 /*
2848 * Check if we are removing extents inside the extent tree. If that
2849 * is the case, we are going to punch a hole inside the extent tree
2850 * so we have to check whether we need to split the extent covering
2851 * the last block to remove so we can easily remove the part of it
2852 * in ext4_ext_rm_leaf().
2853 */
2854 if (end < EXT_MAX_BLOCKS - 1) {
2855 struct ext4_extent *ex;
2856 ext4_lblk_t ee_block, ex_end, lblk;
2857 ext4_fsblk_t pblk;
2858
2859 /* find extent for or closest extent to this block */
2860 path = ext4_find_extent(inode, end, NULL, flags);
2861 if (IS_ERR(path)) {
2862 ext4_journal_stop(handle);
2863 return PTR_ERR(path);
2864 }
2865 depth = ext_depth(inode);
2866 /* Leaf not may not exist only if inode has no blocks at all */
2867 ex = path[depth].p_ext;
2868 if (!ex) {
2869 if (depth) {
2870 EXT4_ERROR_INODE(inode,
2871 "path[%d].p_hdr == NULL",
2872 depth);
2873 err = -EFSCORRUPTED;
2874 }
2875 goto out;
2876 }
2877
2878 ee_block = le32_to_cpu(ex->ee_block);
2879 ex_end = ee_block + ext4_ext_get_actual_len(ex) - 1;
2880
2881 /*
2882 * See if the last block is inside the extent, if so split
2883 * the extent at 'end' block so we can easily remove the
2884 * tail of the first part of the split extent in
2885 * ext4_ext_rm_leaf().
2886 */
2887 if (end >= ee_block && end < ex_end) {
2888
2889 /*
2890 * If we're going to split the extent, note that
2891 * the cluster containing the block after 'end' is
2892 * in use to avoid freeing it when removing blocks.
2893 */
2894 if (sbi->s_cluster_ratio > 1) {
2895 pblk = ext4_ext_pblock(ex) + end - ee_block + 1;
2896 partial.pclu = EXT4_B2C(sbi, pblk);
2897 partial.state = nofree;
2898 }
2899
2900 /*
2901 * Split the extent in two so that 'end' is the last
2902 * block in the first new extent. Also we should not
2903 * fail removing space due to ENOSPC so try to use
2904 * reserved block if that happens.
2905 */
2906 path = ext4_force_split_extent_at(handle, inode, path,
2907 end + 1, 1);
2908 if (IS_ERR(path)) {
2909 err = PTR_ERR(path);
2910 goto out;
2911 }
2912 } else if (sbi->s_cluster_ratio > 1 && end >= ex_end &&
2913 partial.state == initial) {
2914 /*
2915 * If we're punching, there's an extent to the right.
2916 * If the partial cluster hasn't been set, set it to
2917 * that extent's first cluster and its state to nofree
2918 * so it won't be freed should it contain blocks to be
2919 * removed. If it's already set (tofree/nofree), we're
2920 * retrying and keep the original partial cluster info
2921 * so a cluster marked tofree as a result of earlier
2922 * extent removal is not lost.
2923 */
2924 lblk = ex_end + 1;
2925 err = ext4_ext_search_right(inode, path, &lblk, &pblk,
2926 NULL, flags);
2927 if (err < 0)
2928 goto out;
2929 if (pblk) {
2930 partial.pclu = EXT4_B2C(sbi, pblk);
2931 partial.state = nofree;
2932 }
2933 }
2934 }
2935 /*
2936 * We start scanning from right side, freeing all the blocks
2937 * after i_size and walking into the tree depth-wise.
2938 */
2939 depth = ext_depth(inode);
2940 if (path) {
2941 int k = i = depth;
2942 while (--k > 0)
2943 path[k].p_block =
2944 le16_to_cpu(path[k].p_hdr->eh_entries)+1;
2945 } else {
2946 path = kcalloc(depth + 1, sizeof(struct ext4_ext_path),
2947 GFP_NOFS | __GFP_NOFAIL);
2948 if (path == NULL) {
2949 ext4_journal_stop(handle);
2950 return -ENOMEM;
2951 }
2952 path[0].p_maxdepth = path[0].p_depth = depth;
2953 path[0].p_hdr = ext_inode_hdr(inode);
2954 i = 0;
2955
2956 if (ext4_ext_check(inode, path[0].p_hdr, depth, 0)) {
2957 err = -EFSCORRUPTED;
2958 goto out;
2959 }
2960 }
2961 err = 0;
2962
2963 while (i >= 0 && err == 0) {
2964 if (i == depth) {
2965 /* this is leaf block */
2966 err = ext4_ext_rm_leaf(handle, inode, path,
2967 &partial, start, end);
2968 /* root level has p_bh == NULL, brelse() eats this */
2969 ext4_ext_path_brelse(path + i);
2970 i--;
2971 continue;
2972 }
2973
2974 /* this is index block */
2975 if (!path[i].p_hdr) {
2976 ext_debug(inode, "initialize header\n");
2977 path[i].p_hdr = ext_block_hdr(path[i].p_bh);
2978 }
2979
2980 if (!path[i].p_idx) {
2981 /* this level hasn't been touched yet */
2982 path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
2983 path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1;
2984 ext_debug(inode, "init index ptr: hdr 0x%p, num %d\n",
2985 path[i].p_hdr,
2986 le16_to_cpu(path[i].p_hdr->eh_entries));
2987 } else {
2988 /* we were already here, see at next index */
2989 path[i].p_idx--;
2990 }
2991
2992 ext_debug(inode, "level %d - index, first 0x%p, cur 0x%p\n",
2993 i, EXT_FIRST_INDEX(path[i].p_hdr),
2994 path[i].p_idx);
2995 if (ext4_ext_more_to_rm(path + i)) {
2996 struct buffer_head *bh;
2997 /* go to the next level */
2998 ext_debug(inode, "move to level %d (block %llu)\n",
2999 i + 1, ext4_idx_pblock(path[i].p_idx));
3000 memset(path + i + 1, 0, sizeof(*path));
3001 bh = read_extent_tree_block(inode, path[i].p_idx,
3002 depth - i - 1, flags);
3003 if (IS_ERR(bh)) {
3004 /* should we reset i_size? */
3005 err = PTR_ERR(bh);
3006 break;
3007 }
3008 /* Yield here to deal with large extent trees.
3009 * Should be a no-op if we did IO above. */
3010 cond_resched();
3011 if (WARN_ON(i + 1 > depth)) {
3012 err = -EFSCORRUPTED;
3013 break;
3014 }
3015 path[i + 1].p_bh = bh;
3016
3017 /* save actual number of indexes since this
3018 * number is changed at the next iteration */
3019 path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries);
3020 i++;
3021 } else {
3022 /* we finished processing this index, go up */
3023 if (path[i].p_hdr->eh_entries == 0 && i > 0) {
3024 /* index is empty, remove it;
3025 * handle must be already prepared by the
3026 * truncatei_leaf() */
3027 err = ext4_ext_rm_idx(handle, inode, path, i);
3028 }
3029 /* root level has p_bh == NULL, brelse() eats this */
3030 ext4_ext_path_brelse(path + i);
3031 i--;
3032 ext_debug(inode, "return to level %d\n", i);
3033 }
3034 }
3035
3036 trace_ext4_ext_remove_space_done(inode, start, end, depth, &partial,
3037 path->p_hdr->eh_entries);
3038
3039 /*
3040 * if there's a partial cluster and we have removed the first extent
3041 * in the file, then we also free the partial cluster, if any
3042 */
3043 if (partial.state == tofree && err == 0) {
3044 int flags = get_default_free_blocks_flags(inode);
3045
3046 if (ext4_is_pending(inode, partial.lblk))
3047 flags |= EXT4_FREE_BLOCKS_RERESERVE_CLUSTER;
3048 ext4_free_blocks(handle, inode, NULL,
3049 EXT4_C2B(sbi, partial.pclu),
3050 sbi->s_cluster_ratio, flags);
3051 if (flags & EXT4_FREE_BLOCKS_RERESERVE_CLUSTER)
3052 ext4_rereserve_cluster(inode, partial.lblk);
3053 partial.state = initial;
3054 }
3055
3056 /* TODO: flexible tree reduction should be here */
3057 if (path->p_hdr->eh_entries == 0) {
3058 /*
3059 * truncate to zero freed all the tree,
3060 * so we need to correct eh_depth
3061 */
3062 err = ext4_ext_get_access(handle, inode, path);
3063 if (err == 0) {
3064 ix = EXT_FIRST_INDEX(path->p_hdr);
> 3065 if (ix && ext_inode_hdr(inode)->eh_depth > 0)
3066 ext4_idx_store_pblock(ix, 0);
3067 ext_inode_hdr(inode)->eh_depth = 0;
3068 ext_inode_hdr(inode)->eh_max =
3069 cpu_to_le16(ext4_ext_space_root(inode, 0));
3070 err = ext4_ext_dirty(handle, inode, path);
3071 }
3072 }
3073 out:
3074 ext4_free_ext_path(path);
3075 path = NULL;
3076 if (err == -EAGAIN)
3077 goto again;
3078 ext4_journal_stop(handle);
3079
3080 return err;
3081 }
3082
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Powered by blists - more mailing lists