From: kernel test robot <lkp@intel.com>
To: Nicolas Bretz <bretznic@gmail.com>,
tytso@mit.edu, adilger.kernel@dilger.ca
Cc: oe-kbuild-all@lists.linux.dev, linux-ext4@vger.kernel.org,
Nicolas Bretz <bretznic@gmail.com>,
kernel test robot <lkp@intel.com>
Subject: Re: [PATCH v2] ext4: clear extent index structure after file delete
Date: Mon, 21 Jul 2025 06:41:09 +0800 [thread overview]
Message-ID: <202507210558.sazSHcm1-lkp@intel.com> (raw)
In-Reply-To: <20250718122654.1431747-1-bretznic@gmail.com>
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@intel.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
prev parent reply other threads:[~2025-07-20 22:42 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-18 12:26 [PATCH v2] ext4: clear extent index structure after file delete Nicolas Bretz
2025-07-20 22:41 ` kernel test robot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=202507210558.sazSHcm1-lkp@intel.com \
--to=lkp@intel.com \
--cc=adilger.kernel@dilger.ca \
--cc=bretznic@gmail.com \
--cc=linux-ext4@vger.kernel.org \
--cc=oe-kbuild-all@lists.linux.dev \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.