All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem
@ 2021-03-02  5:05 ` Hyeongseok Kim
  2021-03-02  5:05   ` [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access Hyeongseok Kim
                     ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Hyeongseok Kim @ 2021-03-02  5:05 UTC (permalink / raw)
  To: namjae.jeon, sj1557.seo; +Cc: linux-kernel, linux-fsdevel, Hyeongseok Kim

This is for adding FITRIM ioctl functionality to exFAT filesystem.
Firstly, because the fstrim is long operation, introduce bitmap_lock
to narrow the lock range to prevent read operation stall.
After that, add generic ioctl function and FITRIM handler.

Changelog
=========
v3->v4:
- Introduce bitmap_lock mutex to narrow the lock range for bitmap access
  and change to use bitmap_lock instead of s_lock in FITRIM handler to
  prevent read stall while ongoing fstrim.
- Minor code style fix

v2->v3:
- Remove unnecessary local variable
- Merge all changes to a single patch

v1->v2:
- Change variable declaration order as reverse tree style.
- Return -EOPNOTSUPP from sb_issue_discard() just as it is.
- Remove cond_resched() in while loop.
- Move ioctl related code into it's helper function.

Hyeongseok Kim (2):
  exfat: introduce bitmap_lock for cluster bitmap access
  exfat: add support ioctl and FITRIM function

 fs/exfat/balloc.c   | 80 +++++++++++++++++++++++++++++++++++++++++++++
 fs/exfat/dir.c      |  5 +++
 fs/exfat/exfat_fs.h |  5 +++
 fs/exfat/fatent.c   | 37 ++++++++++++++++-----
 fs/exfat/file.c     | 53 ++++++++++++++++++++++++++++++
 fs/exfat/super.c    |  1 +
 6 files changed, 173 insertions(+), 8 deletions(-)

-- 
2.27.0.83.g0313f36


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access
  2021-03-02  5:05 ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Hyeongseok Kim
@ 2021-03-02  5:05   ` Hyeongseok Kim
  2021-03-02  6:54     ` Sungjong Seo
  2021-03-02  5:05   ` [PATCH v4 2/2] exfat: add support ioctl and FITRIM function Hyeongseok Kim
  2021-03-04  3:43   ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Namjae Jeon
  2 siblings, 1 reply; 6+ messages in thread
From: Hyeongseok Kim @ 2021-03-02  5:05 UTC (permalink / raw)
  To: namjae.jeon, sj1557.seo; +Cc: linux-kernel, linux-fsdevel, Hyeongseok Kim

s_lock which is for protecting concurrent access of file operations is
too huge for cluster bitmap protection, so introduce a new bitmap_lock
to narrow the lock range if only need to access cluster bitmap.

Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>
---
 fs/exfat/exfat_fs.h |  1 +
 fs/exfat/fatent.c   | 37 +++++++++++++++++++++++++++++--------
 fs/exfat/super.c    |  1 +
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 764bc645241e..1ce422d7e9ae 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -238,6 +238,7 @@ struct exfat_sb_info {
 	unsigned int used_clusters; /* number of used clusters */
 
 	struct mutex s_lock; /* superblock lock */
+	struct mutex bitmap_lock; /* bitmap lock */
 	struct exfat_mount_options options;
 	struct nls_table *nls_io; /* Charset used for input and display */
 	struct ratelimit_state ratelimit;
diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c
index 7b2e8af17193..fd6c7fd12762 100644
--- a/fs/exfat/fatent.c
+++ b/fs/exfat/fatent.c
@@ -151,13 +151,14 @@ int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
 	return 0;
 }
 
-int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
+/* This function must be called with bitmap_lock held */
+static int __exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
 {
-	unsigned int num_clusters = 0;
-	unsigned int clu;
 	struct super_block *sb = inode->i_sb;
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
 	int cur_cmap_i, next_cmap_i;
+	unsigned int num_clusters = 0;
+	unsigned int clu;
 
 	/* invalid cluster number */
 	if (p_chain->dir == EXFAT_FREE_CLUSTER ||
@@ -230,6 +231,17 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
 	return 0;
 }
 
+int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
+{
+	int ret = 0;
+
+	mutex_lock(&EXFAT_SB(inode->i_sb)->bitmap_lock);
+	ret = __exfat_free_cluster(inode, p_chain);
+	mutex_unlock(&EXFAT_SB(inode->i_sb)->bitmap_lock);
+
+	return ret;
+}
+
 int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
 		unsigned int *ret_clu)
 {
@@ -328,6 +340,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 	if (num_alloc > total_cnt - sbi->used_clusters)
 		return -ENOSPC;
 
+	mutex_lock(&sbi->bitmap_lock);
+
 	hint_clu = p_chain->dir;
 	/* find new cluster */
 	if (hint_clu == EXFAT_EOF_CLUSTER) {
@@ -338,8 +352,10 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 		}
 
 		hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr);
-		if (hint_clu == EXFAT_EOF_CLUSTER)
-			return -ENOSPC;
+		if (hint_clu == EXFAT_EOF_CLUSTER) {
+			ret = -ENOSPC;
+			goto unlock;
+		}
 	}
 
 	/* check cluster validation */
@@ -349,8 +365,10 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 		hint_clu = EXFAT_FIRST_CLUSTER;
 		if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
 			if (exfat_chain_cont_cluster(sb, p_chain->dir,
-					num_clusters))
-				return -EIO;
+					num_clusters)) {
+				ret = -EIO;
+				goto unlock;
+			}
 			p_chain->flags = ALLOC_FAT_CHAIN;
 		}
 	}
@@ -400,6 +418,7 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 			sbi->used_clusters += num_clusters;
 
 			p_chain->size += num_clusters;
+			mutex_unlock(&sbi->bitmap_lock);
 			return 0;
 		}
 
@@ -419,7 +438,9 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
 	}
 free_cluster:
 	if (num_clusters)
-		exfat_free_cluster(inode, p_chain);
+		__exfat_free_cluster(inode, p_chain);
+unlock:
+	mutex_unlock(&sbi->bitmap_lock);
 	return ret;
 }
 
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index c6d8d2e53486..d38d17a77e76 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -752,6 +752,7 @@ static int exfat_init_fs_context(struct fs_context *fc)
 		return -ENOMEM;
 
 	mutex_init(&sbi->s_lock);
+	mutex_init(&sbi->bitmap_lock);
 	ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
 			DEFAULT_RATELIMIT_BURST);
 
-- 
2.27.0.83.g0313f36


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v4 2/2] exfat: add support ioctl and FITRIM function
  2021-03-02  5:05 ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Hyeongseok Kim
  2021-03-02  5:05   ` [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access Hyeongseok Kim
@ 2021-03-02  5:05   ` Hyeongseok Kim
  2021-03-02  6:58     ` Sungjong Seo
  2021-03-04  3:43   ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Namjae Jeon
  2 siblings, 1 reply; 6+ messages in thread
From: Hyeongseok Kim @ 2021-03-02  5:05 UTC (permalink / raw)
  To: namjae.jeon, sj1557.seo
  Cc: linux-kernel, linux-fsdevel, Hyeongseok Kim, Chaitanya Kulkarni

Add FITRIM ioctl to enable discarding unused blocks while mounted.
As current exFAT doesn't have generic ioctl handler, add empty ioctl
function first, and add FITRIM handler.

Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>
---
 fs/exfat/balloc.c   | 80 +++++++++++++++++++++++++++++++++++++++++++++
 fs/exfat/dir.c      |  5 +++
 fs/exfat/exfat_fs.h |  4 +++
 fs/exfat/file.c     | 53 ++++++++++++++++++++++++++++++
 4 files changed, 142 insertions(+)

diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
index 761c79c3a4ba..8e5e9f037574 100644
--- a/fs/exfat/balloc.c
+++ b/fs/exfat/balloc.c
@@ -273,3 +273,83 @@ int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count)
 	*ret_count = count;
 	return 0;
 }
+
+int exfat_trim_fs(struct inode *inode, struct fstrim_range *range)
+{
+	unsigned int trim_begin, trim_end, count, next_free_clu;
+	u64 clu_start, clu_end, trim_minlen, trimmed_total = 0;
+	struct super_block *sb = inode->i_sb;
+	struct exfat_sb_info *sbi = EXFAT_SB(sb);
+	int err = 0;
+
+	clu_start = max_t(u64, range->start >> sbi->cluster_size_bits,
+				EXFAT_FIRST_CLUSTER);
+	clu_end = clu_start + (range->len >> sbi->cluster_size_bits) - 1;
+	trim_minlen = range->minlen >> sbi->cluster_size_bits;
+
+	if (clu_start >= sbi->num_clusters || range->len < sbi->cluster_size)
+		return -EINVAL;
+
+	if (clu_end >= sbi->num_clusters)
+		clu_end = sbi->num_clusters - 1;
+
+	mutex_lock(&sbi->bitmap_lock);
+
+	trim_begin = trim_end = exfat_find_free_bitmap(sb, clu_start);
+	if (trim_begin == EXFAT_EOF_CLUSTER)
+		goto unlock;
+
+	next_free_clu = exfat_find_free_bitmap(sb, trim_end + 1);
+	if (next_free_clu == EXFAT_EOF_CLUSTER)
+		goto unlock;
+
+	do {
+		if (next_free_clu == trim_end + 1) {
+			/* extend trim range for continuous free cluster */
+			trim_end++;
+		} else {
+			/* trim current range if it's larger than trim_minlen */
+			count = trim_end - trim_begin + 1;
+			if (count >= trim_minlen) {
+				err = sb_issue_discard(sb,
+					exfat_cluster_to_sector(sbi, trim_begin),
+					count * sbi->sect_per_clus, GFP_NOFS, 0);
+				if (err)
+					goto unlock;
+
+				trimmed_total += count;
+			}
+
+			/* set next start point of the free hole */
+			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;
+	if (count >= trim_minlen) {
+		err = sb_issue_discard(sb, exfat_cluster_to_sector(sbi, trim_begin),
+			count * sbi->sect_per_clus, GFP_NOFS, 0);
+		if (err)
+			goto unlock;
+
+		trimmed_total += count;
+	}
+
+unlock:
+	mutex_unlock(&sbi->bitmap_lock);
+	range->len = trimmed_total << sbi->cluster_size_bits;
+
+	return err;
+}
diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index 916797077aad..e1d5536de948 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/compat.h>
 #include <linux/bio.h>
 #include <linux/buffer_head.h>
 
@@ -306,6 +307,10 @@ const struct file_operations exfat_dir_operations = {
 	.llseek		= generic_file_llseek,
 	.read		= generic_read_dir,
 	.iterate	= exfat_iterate,
+	.unlocked_ioctl = exfat_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = exfat_compat_ioctl,
+#endif
 	.fsync		= exfat_file_fsync,
 };
 
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 1ce422d7e9ae..80ffca67cfdc 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -412,6 +412,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu);
 void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync);
 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);
+int exfat_trim_fs(struct inode *inode, struct fstrim_range *range);
 
 /* file.c */
 extern const struct file_operations exfat_file_operations;
@@ -421,6 +422,9 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr);
 int exfat_getattr(const struct path *path, struct kstat *stat,
 		unsigned int request_mask, unsigned int query_flags);
 int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
+long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+long exfat_compat_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long arg);
 
 /* namei.c */
 extern const struct dentry_operations exfat_dentry_ops;
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index 183ffdf4d43c..56542f3f7c5a 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/compat.h>
 #include <linux/cred.h>
 #include <linux/buffer_head.h>
 #include <linux/blkdev.h>
@@ -348,6 +349,54 @@ int exfat_setattr(struct dentry *dentry, struct iattr *attr)
 	return error;
 }
 
+static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
+{
+	struct request_queue *q = bdev_get_queue(inode->i_sb->s_bdev);
+	struct fstrim_range range;
+	int ret = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!blk_queue_discard(q))
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range)))
+		return -EFAULT;
+
+	range.minlen = max_t(unsigned int, range.minlen,
+				q->limits.discard_granularity);
+
+	ret = exfat_trim_fs(inode, &range);
+	if (ret < 0)
+		return ret;
+
+	if (copy_to_user((struct fstrim_range __user *)arg, &range, sizeof(range)))
+		return -EFAULT;
+
+	return 0;
+}
+
+long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct inode *inode = file_inode(filp);
+
+	switch (cmd) {
+	case FITRIM:
+		return exfat_ioctl_fitrim(inode, arg);
+	default:
+		return -ENOTTY;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+long exfat_compat_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	return exfat_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
 	struct inode *inode = filp->f_mapping->host;
@@ -368,6 +417,10 @@ const struct file_operations exfat_file_operations = {
 	.llseek		= generic_file_llseek,
 	.read_iter	= generic_file_read_iter,
 	.write_iter	= generic_file_write_iter,
+	.unlocked_ioctl = exfat_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = exfat_compat_ioctl,
+#endif
 	.mmap		= generic_file_mmap,
 	.fsync		= exfat_file_fsync,
 	.splice_read	= generic_file_splice_read,
-- 
2.27.0.83.g0313f36


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* RE: [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access
  2021-03-02  5:05   ` [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access Hyeongseok Kim
@ 2021-03-02  6:54     ` Sungjong Seo
  0 siblings, 0 replies; 6+ messages in thread
From: Sungjong Seo @ 2021-03-02  6:54 UTC (permalink / raw)
  To: 'Hyeongseok Kim', namjae.jeon
  Cc: linux-kernel, linux-fsdevel, sj1557.seo

> s_lock which is for protecting concurrent access of file operations is too
> huge for cluster bitmap protection, so introduce a new bitmap_lock to
> narrow the lock range if only need to access cluster bitmap.
> 
> Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>

Looks good.
Thanks for your work!

Acked-by: Sungjong Seo <sj1557.seo@samsung.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v4 2/2] exfat: add support ioctl and FITRIM function
  2021-03-02  5:05   ` [PATCH v4 2/2] exfat: add support ioctl and FITRIM function Hyeongseok Kim
@ 2021-03-02  6:58     ` Sungjong Seo
  0 siblings, 0 replies; 6+ messages in thread
From: Sungjong Seo @ 2021-03-02  6:58 UTC (permalink / raw)
  To: 'Hyeongseok Kim', namjae.jeon
  Cc: linux-kernel, linux-fsdevel, 'Chaitanya Kulkarni', sj1557.seo

> Add FITRIM ioctl to enable discarding unused blocks while mounted.
> As current exFAT doesn't have generic ioctl handler, add empty ioctl
> function first, and add FITRIM handler.
> 
> Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
> Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>
> ---
>  fs/exfat/balloc.c   | 80 +++++++++++++++++++++++++++++++++++++++++++++
>  fs/exfat/dir.c      |  5 +++
>  fs/exfat/exfat_fs.h |  4 +++
>  fs/exfat/file.c     | 53 ++++++++++++++++++++++++++++++
>  4 files changed, 142 insertions(+)
> 

It looks better than v3.
Thanks for your work!

Acked-by: Sungjong Seo <sj1557.seo@samsung.com>

BTW, there is still a problem that the alloc/free cluster operation waits
until the trimfs operation is finished.
Any ideas for improvement in the future are welcome. :)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem
  2021-03-02  5:05 ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Hyeongseok Kim
  2021-03-02  5:05   ` [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access Hyeongseok Kim
  2021-03-02  5:05   ` [PATCH v4 2/2] exfat: add support ioctl and FITRIM function Hyeongseok Kim
@ 2021-03-04  3:43   ` Namjae Jeon
  2 siblings, 0 replies; 6+ messages in thread
From: Namjae Jeon @ 2021-03-04  3:43 UTC (permalink / raw)
  To: 'Hyeongseok Kim', sj1557.seo; +Cc: linux-kernel, linux-fsdevel

> This is for adding FITRIM ioctl functionality to exFAT filesystem.
> Firstly, because the fstrim is long operation, introduce bitmap_lock to narrow the lock range to
> prevent read operation stall.
> After that, add generic ioctl function and FITRIM handler.
> 
> Changelog
> =========
> v3->v4:
> - Introduce bitmap_lock mutex to narrow the lock range for bitmap access
>   and change to use bitmap_lock instead of s_lock in FITRIM handler to
>   prevent read stall while ongoing fstrim.
> - Minor code style fix
> 
> v2->v3:
> - Remove unnecessary local variable
> - Merge all changes to a single patch
> 
> v1->v2:
> - Change variable declaration order as reverse tree style.
> - Return -EOPNOTSUPP from sb_issue_discard() just as it is.
> - Remove cond_resched() in while loop.
> - Move ioctl related code into it's helper function.
> 
> Hyeongseok Kim (2):
>   exfat: introduce bitmap_lock for cluster bitmap access
>   exfat: add support ioctl and FITRIM function
Applied. Thanks for your patches!

> 
>  fs/exfat/balloc.c   | 80 +++++++++++++++++++++++++++++++++++++++++++++
>  fs/exfat/dir.c      |  5 +++
>  fs/exfat/exfat_fs.h |  5 +++
>  fs/exfat/fatent.c   | 37 ++++++++++++++++-----
>  fs/exfat/file.c     | 53 ++++++++++++++++++++++++++++++
>  fs/exfat/super.c    |  1 +
>  6 files changed, 173 insertions(+), 8 deletions(-)
> 
> --
> 2.27.0.83.g0313f36



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-03-04  3:45 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20210302050548epcas1p2ccec84f5de16f0971fc0479abe64ec3e@epcas1p2.samsung.com>
2021-03-02  5:05 ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Hyeongseok Kim
2021-03-02  5:05   ` [PATCH v4 1/2] exfat: introduce bitmap_lock for cluster bitmap access Hyeongseok Kim
2021-03-02  6:54     ` Sungjong Seo
2021-03-02  5:05   ` [PATCH v4 2/2] exfat: add support ioctl and FITRIM function Hyeongseok Kim
2021-03-02  6:58     ` Sungjong Seo
2021-03-04  3:43   ` [PATCH v4 0/2] Add FITRIM ioctl support for exFAT filesystem Namjae Jeon

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.