diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-03-31 17:49:35 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-03-31 17:49:35 -0700 |
| commit | 172f7c91674fb3e55a7a00cfcba76719000811df (patch) | |
| tree | 60decc8c777e2cb1b3437b9e6fb7551e5d164dc1 /fs/exfat/fatent.c | |
| parent | f64a72bc767f6e9ddb18fdacaeb99708c4810ada (diff) | |
| parent | c73e680d1f84059e1b1ea82a537f6ccc1c563eb4 (diff) | |
Merge tag 'exfat-for-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat
Pull exfat updates from Namjae Jeon:
- Fix random stack corruption and incorrect error returns in
exfat_get_block()
- Optimize exfat_get_block() by improving checking corner cases
- Fix an endless loop by self-linked chain in exfat_find_last_cluster
- Remove dead EXFAT_CLUSTERS_UNTRACKED codes
- Add missing shutdown check
- Improve the delete performance with discard mount option
* tag 'exfat-for-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
exfat: call bh_read in get_block only when necessary
exfat: fix potential wrong error return from get_block
exfat: fix missing shutdown check
exfat: fix the infinite loop in exfat_find_last_cluster()
exfat: fix random stack corruption after get_block
exfat: remove count used cluster from exfat_statfs()
exfat: support batch discard of clusters when freeing clusters
Diffstat (limited to 'fs/exfat/fatent.c')
| -rw-r--r-- | fs/exfat/fatent.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 6f3651c6ca91..23065f948ae7 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -144,6 +144,20 @@ int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, return 0; } +static inline void exfat_discard_cluster(struct super_block *sb, + unsigned int clu, unsigned int num_clusters) +{ + int ret; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + ret = sb_issue_discard(sb, exfat_cluster_to_sector(sbi, clu), + sbi->sect_per_clus * num_clusters, GFP_NOFS, 0); + if (ret == -EOPNOTSUPP) { + exfat_err(sb, "discard not supported by device, disabling"); + sbi->options.discard = 0; + } +} + /* This function must be called with bitmap_lock held */ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) { @@ -196,7 +210,12 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain clu++; num_clusters++; } while (num_clusters < p_chain->size); + + if (sbi->options.discard) + exfat_discard_cluster(sb, p_chain->dir, p_chain->size); } else { + unsigned int nr_clu = 1; + do { bool sync = false; unsigned int n_clu = clu; @@ -215,6 +234,16 @@ static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain if (exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)))) break; + + if (sbi->options.discard) { + if (n_clu == clu + 1) + nr_clu++; + else { + exfat_discard_cluster(sb, clu - nr_clu + 1, nr_clu); + nr_clu = 1; + } + } + clu = n_clu; num_clusters++; @@ -265,7 +294,7 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, clu = next; if (exfat_ent_get(sb, clu, &next)) return -EIO; - } while (next != EXFAT_EOF_CLUSTER); + } while (next != EXFAT_EOF_CLUSTER && count <= p_chain->size); if (p_chain->size != count) { exfat_fs_error(sb, |
