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@xxxxxxxxx/config) compiler: csky-linux-gcc (GCC) 11.5.0 reproduce: (https://download.01.org/0day-ci/archive/20250721/202507210558.sazSHcm1-lkp@xxxxxxxxx/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@xxxxxxxxx> | Closes: https://lore.kernel.org/oe-kbuild-all/202507210558.sazSHcm1-lkp@xxxxxxxxx/ 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