[PATCH] exfat: keep FITRIM within the requested range
Yang Wen <[email protected]>
| Newsgroups | dev.linux.lists.exfat,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
exfat_find_free_bitmap() searches the entire allocation bitmap and may wrap around to its beginning. exfat_trim_fs() does not verify that the returned cluster is still within the requested FITRIM range. As a result, a partial FITRIM operation may discard free clusters outside the user-specified range and report a trimmed length larger than the requested length. Validate each returned cluster against the requested range and stop the search when it wraps around or passes the range end. Signed-off-by: Yang Wen <[email protected]> --- fs/exfat/balloc.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index e66ebf899778..c0ddd522c1e1 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -340,14 +340,27 @@ int exfat_trim_fs(struct inode *inode, struct fstrim_range *range) mutex_lock(&sbi->bitmap_lock); trim_begin = trim_end = exfat_find_free_bitmap(sb, clu_start); - if (trim_begin == EXFAT_EOF_CLUSTER) + /* + * exfat_find_free_bitmap() may wrap around to the beginning of + * the bitmap. Reject a cluster outside the requested range. + */ + if (trim_begin == EXFAT_EOF_CLUSTER || + trim_begin < clu_start || trim_begin > clu_end) goto unlock; - next_free_clu = exfat_find_free_bitmap(sb, trim_end + 1); - if (next_free_clu == EXFAT_EOF_CLUSTER) - goto unlock; + for (;;) { + if (trim_end >= clu_end) + break; + + next_free_clu = exfat_find_free_bitmap(sb, trim_end + 1); + /* + * Stop if the search wrapped around or moved beyond the requested + * FITRIM range. + */ + if (next_free_clu == EXFAT_EOF_CLUSTER || + next_free_clu <= trim_end || next_free_clu > clu_end) + break; - do { if (next_free_clu == trim_end + 1) { /* extend trim range for continuous free cluster */ trim_end++; @@ -368,17 +381,11 @@ int exfat_trim_fs(struct inode *inode, struct fstrim_range *range) trim_begin = trim_end = next_free_clu; } - if (next_free_clu >= clu_end) - break; - if (fatal_signal_pending(current)) { err = -ERESTARTSYS; goto unlock; } - - next_free_clu = exfat_find_free_bitmap(sb, next_free_clu + 1); - } while (next_free_clu != EXFAT_EOF_CLUSTER && - next_free_clu > trim_end); + } /* try to trim remainder */ count = trim_end - trim_begin + 1; -- 2.34.1