lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ