From: Jun <hljhnu@gmail.com>
To: namjae.jeon@samsung.com, sj1557.seo@samsung.com
Cc: linux-fsdevel@vger.kernel.org, hljhnu@gmail.com
Subject: [RFC PATCH] exfat: optimize performance of deleting a file
Date: Wed, 6 Jul 2022 15:21:17 +0800 [thread overview]
Message-ID: <20220706072117.GA29711@ubuntu> (raw)
When a large file is deleted, it's cluster bitmap is cleared.
After a bit is cleared, the buffer_head is synced.
A buffer_head can be synced many times repeatedly.
We can clear all bits first and then sync all buffer_heads.
So each buffer_head is synced only once, which significantly improves performance.
In my test, It takes about 2 minitues to delete a 5GB file without the patch.
After applying the patch, the file is deleted in almost less than 1s.
Signed-off-by: Jun <hljhnu@gmail.com>
Change-Id: I7637032db04042b8ad1ca73fe7db09d43a253255
---
fs/exfat/balloc.c | 28 ++++++++++++++++++++++++++--
fs/exfat/exfat_fs.h | 2 ++
fs/exfat/fatent.c | 45 +++++++++++++++++++++++++++++++++++++++++----
3 files changed, 69 insertions(+), 6 deletions(-)
diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
index 579c10f57c2b..58bdfb58bf1d 100644
--- a/fs/exfat/balloc.c
+++ b/fs/exfat/balloc.c
@@ -164,7 +164,6 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
unsigned int ent_idx;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
- struct exfat_mount_options *opts = &sbi->options;
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
@@ -172,7 +171,32 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
clear_bit_le(b, sbi->vol_amap[i]->b_data);
- exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));
+ set_buffer_uptodate(sbi->vol_amap[i]);
+ mark_buffer_dirty(sbi->vol_amap[i]);
+}
+
+void exfat_wait_bitmap(struct inode *inode, unsigned int clu)
+{
+ int i;
+ unsigned int ent_idx;
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ WARN_ON(clu < EXFAT_FIRST_CLUSTER);
+ ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
+ i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
+
+ if (IS_DIRSYNC(inode))
+ sync_dirty_buffer(sbi->vol_amap[i]);
+}
+
+void exfat_discard_cluster(struct inode *inode, unsigned int clu)
+{
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct exfat_mount_options *opts = &sbi->options;
+
+ WARN_ON(clu < EXFAT_FIRST_CLUSTER);
if (opts->discard) {
int ret_discard;
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index b8f0e829ecbd..1ecd2379022d 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -409,6 +409,8 @@ int exfat_load_bitmap(struct super_block *sb);
void exfat_free_bitmap(struct exfat_sb_info *sbi);
int exfat_set_bitmap(struct inode *inode, unsigned int clu);
void exfat_clear_bitmap(struct inode *inode, unsigned int clu);
+void exfat_wait_bitmap(struct inode *inode, unsigned int clu);
+void exfat_discard_cluster(struct inode *inode, unsigned int clu);
unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu);
int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index c3c9afee7418..f39a912a7da7 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -183,19 +183,56 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
num_clusters++;
} while (num_clusters < p_chain->size);
+ sbi->used_clusters -= num_clusters;
+
+ clu = p_chain->dir;
+ num_clusters = 0;
+ do {
+ exfat_wait_bitmap(inode, clu);
+ clu++;
+
+ num_clusters++;
+ } while (num_clusters < p_chain->size);
+
+ clu = p_chain->dir;
+ num_clusters = 0;
+ do {
+ exfat_discard_cluster(inode, clu);
+ clu++;
+
+ num_clusters++;
+ } while (num_clusters < p_chain->size);
+
} else {
do {
exfat_clear_bitmap(inode, clu);
if (exfat_get_next_cluster(sb, &clu))
- goto dec_used_clus;
+ goto exit;
+
+ sbi->used_clusters--;
+ } while (clu != EXFAT_EOF_CLUSTER);
+
+ clu = p_chain->dir;
+ do {
+ exfat_wait_bitmap(inode, clu);
+
+ if (exfat_get_next_cluster(sb, &clu))
+ goto exit;
+
+ } while (clu != EXFAT_EOF_CLUSTER);
+
+ clu = p_chain->dir;
+ do {
+ exfat_discard_cluster(inode, clu);
+
+ if (exfat_get_next_cluster(sb, &clu))
+ goto exit;
- num_clusters++;
} while (clu != EXFAT_EOF_CLUSTER);
}
-dec_used_clus:
- sbi->used_clusters -= num_clusters;
+exit:
return 0;
}
--
2.36.1
next reply other threads:[~2022-07-06 7:21 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20220706072124epcas1p42f5e7b4bde0cdb4d0fb80ac5ea18158a@epcas1p4.samsung.com>
2022-07-06 7:21 ` Jun [this message]
2022-07-06 15:05 ` [RFC PATCH] exfat: optimize performance of deleting a file Sungjong Seo
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=20220706072117.GA29711@ubuntu \
--to=hljhnu@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=namjae.jeon@samsung.com \
--cc=sj1557.seo@samsung.com \
/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.