* [RFC PATCH v1 3/6] exfat: use atomic bit ops for volume dirty flag
2026-08-21 10:05 [RFC PATCH 0/6] exfat: take s_lock in read mode for iomap mapping paths Chi Zhiling
2026-08-21 10:05 ` [RFC PATCH v1 1/6] exfat: remove dead hint_bmap updates in I/O and truncate paths Chi Zhiling
2026-08-21 10:05 ` [RFC PATCH v1 2/6] exfat: take bitmap_lock at the start of exfat_alloc_cluster() Chi Zhiling
@ 2026-08-21 10:05 ` Chi Zhiling
2026-08-21 10:05 ` [RFC PATCH v1 4/6] exfat: lock FAT2 buffer while copying mirrored FAT entries Chi Zhiling
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Chi Zhiling @ 2026-08-21 10:05 UTC (permalink / raw)
To: exfat, linux-kernel; +Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling
From: Chi Zhiling <chizhiling@kylinos.cn>
After converting s_lock to a reader-writer lock, multiple operations can
execute concurrently under the read lock. As a result, multiple threads may
concurrently update sbi->vol_flags, causing a race in the existing
read-modify-write sequence.
Convert sbi->vol_flags to an unsigned long bitmap and use
test_and_set_bit() / test_and_clear_bit() to atomically update the volume
dirty bit. Only the thread performing the 0 -> 1 transition updates the
boot sector, avoiding concurrent unsynchronized modifications of vol_flags
and the boot-sector buffer.
Remove vol_flags_persistent, since the bitmap can directly retain the
MEDIA_FAILURE state while preserving the complete 16-bit on-disk volume
flags field when writing it back.
Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
fs/exfat/exfat_fs.h | 3 +--
fs/exfat/exfat_raw.h | 4 ++--
fs/exfat/super.c | 28 ++++++++++++----------------
3 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index a9131fe03302..f1505c013248 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -232,8 +232,7 @@ struct exfat_sb_info {
unsigned int num_FAT_sectors; /* num of FAT sectors */
unsigned int root_dir; /* root dir cluster */
unsigned int dentries_per_clu; /* num of dentries per cluster */
- unsigned int vol_flags; /* volume flags */
- unsigned int vol_flags_persistent; /* volume flags to retain */
+ unsigned long vol_flags; /* volume flags (bitmap) */
struct buffer_head *boot_bh; /* buffer_head of BOOT sector */
unsigned int map_clu; /* allocation bitmap start cluster */
diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h
index ec70cd35bba0..222fee5c2adf 100644
--- a/fs/exfat/exfat_raw.h
+++ b/fs/exfat/exfat_raw.h
@@ -14,8 +14,8 @@
#define EXFAT_MAX_FILE_LEN 255
-#define VOLUME_DIRTY 0x0002
-#define MEDIA_FAILURE 0x0004
+#define VOLUME_DIRTY_BIT 1
+#define MEDIA_FAILURE_BIT 2
#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu
#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index a9ea36ba2693..491273d8eeb6 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -69,27 +69,18 @@ static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flags)
+static int exfat_sync_vol_flags(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct boot_sector *p_boot = (struct boot_sector *)sbi->boot_bh->b_data;
- /* retain persistent-flags */
- new_flags |= sbi->vol_flags_persistent;
-
- /* flags are not changed */
- if (sbi->vol_flags == new_flags)
- return 0;
-
- sbi->vol_flags = new_flags;
-
/* skip updating volume dirty flag,
* if this volume has been mounted with read-only
*/
if (sb_rdonly(sb))
return 0;
- p_boot->vol_flags = cpu_to_le16(new_flags);
+ p_boot->vol_flags = cpu_to_le16((unsigned short)READ_ONCE(sbi->vol_flags));
set_buffer_uptodate(sbi->boot_bh);
mark_buffer_dirty(sbi->boot_bh);
@@ -103,14 +94,20 @@ int exfat_set_volume_dirty(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
- return exfat_set_vol_flags(sb, sbi->vol_flags | VOLUME_DIRTY);
+ if (test_and_set_bit(VOLUME_DIRTY_BIT, &sbi->vol_flags))
+ return 0;
+
+ return exfat_sync_vol_flags(sb);
}
int exfat_clear_volume_dirty(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
- return exfat_set_vol_flags(sb, sbi->vol_flags & ~VOLUME_DIRTY);
+ if (!test_and_clear_bit(VOLUME_DIRTY_BIT, &sbi->vol_flags))
+ return 0;
+
+ return exfat_sync_vol_flags(sb);
}
static int exfat_show_options(struct seq_file *m, struct dentry *root)
@@ -509,7 +506,6 @@ static int exfat_read_boot_sector(struct super_block *sb)
(sbi->cluster_size_bits - DENTRY_SIZE_BITS);
sbi->vol_flags = le16_to_cpu(p_boot->vol_flags);
- sbi->vol_flags_persistent = sbi->vol_flags & (VOLUME_DIRTY | MEDIA_FAILURE);
sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
/* check consistencies */
@@ -526,9 +522,9 @@ static int exfat_read_boot_sector(struct super_block *sb)
return -EINVAL;
}
- if (sbi->vol_flags & VOLUME_DIRTY)
+ if (test_bit(VOLUME_DIRTY_BIT, &sbi->vol_flags))
exfat_warn(sb, "Volume was not properly unmounted. Some data may be corrupt. Please run fsck.");
- if (sbi->vol_flags & MEDIA_FAILURE)
+ if (test_bit(MEDIA_FAILURE_BIT, &sbi->vol_flags))
exfat_warn(sb, "Medium has reported failures. Some data may be lost.");
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH v1 5/6] exfat: convert s_lock mutex to rw_semaphore using write lock
2026-08-21 10:05 [RFC PATCH 0/6] exfat: take s_lock in read mode for iomap mapping paths Chi Zhiling
` (3 preceding siblings ...)
2026-08-21 10:05 ` [RFC PATCH v1 4/6] exfat: lock FAT2 buffer while copying mirrored FAT entries Chi Zhiling
@ 2026-08-21 10:05 ` Chi Zhiling
2026-08-21 10:05 ` [RFC PATCH v1 6/6] exfat: take s_lock in read mode for iomap mapping paths Chi Zhiling
5 siblings, 0 replies; 7+ messages in thread
From: Chi Zhiling @ 2026-08-21 10:05 UTC (permalink / raw)
To: exfat, linux-kernel; +Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling
From: Chi Zhiling <chizhiling@kylinos.cn>
Convert sbi->s_lock from a mutex to an rw_semaphore and acquire it in
write mode at every existing use site. This is a mechanical conversion
with no behavioral change, preparing the lock for read-mode access in
the iomap mapping paths so that concurrent mappings of distinct inodes
can proceed in parallel.
Lock ordering stays consistent (inode_lock -> s_lock -> bitmap_lock),
so no deadlock is introduced.
Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
fs/exfat/dir.c | 14 +++++++-------
fs/exfat/exfat_fs.h | 2 +-
fs/exfat/file.c | 4 ++--
fs/exfat/inode.c | 10 +++++-----
fs/exfat/iomap.c | 4 ++--
fs/exfat/namei.c | 26 +++++++++++++-------------
fs/exfat/super.c | 10 +++++-----
7 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index fe73b1380c5d..ea454574260e 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -223,7 +223,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
if (err)
goto out;
get_new:
- mutex_lock(&EXFAT_SB(sb)->s_lock);
+ down_write(&EXFAT_SB(sb)->s_lock);
if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode))
goto end_of_dir;
@@ -255,7 +255,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
inum = iunique(sb, EXFAT_ROOT_INO);
}
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum,
(de.attr & EXFAT_ATTR_SUBDIR) ? DT_DIR : DT_REG))
goto out;
@@ -266,7 +266,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
if (!cpos && fake_offset)
cpos = ITER_POS_FILLED_DOTS;
ctx->pos = cpos;
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
out:
/*
* To improve performance, free namebuf after unlock sb_lock.
@@ -1294,7 +1294,7 @@ int exfat_read_volume_label(struct super_block *sb, struct exfat_uni_name *label
struct exfat_entry_set_cache es;
struct exfat_dentry *ep;
- mutex_lock(&sbi->s_lock);
+ down_write(&sbi->s_lock);
memset(label_out, 0, sizeof(*label_out));
ret = exfat_get_volume_label_dentry(sb, &es);
@@ -1322,7 +1322,7 @@ int exfat_read_volume_label(struct super_block *sb, struct exfat_uni_name *label
exfat_put_dentry_set(&es, false);
unlock:
- mutex_unlock(&sbi->s_lock);
+ up_write(&sbi->s_lock);
return ret;
}
@@ -1339,7 +1339,7 @@ int exfat_write_volume_label(struct super_block *sb,
if (label->name_len > EXFAT_VOLUME_LABEL_LEN)
return -EINVAL;
- mutex_lock(&sbi->s_lock);
+ down_write(&sbi->s_lock);
ret = exfat_get_volume_label_dentry(sb, &es);
if (ret == -ENOENT) {
@@ -1376,6 +1376,6 @@ int exfat_write_volume_label(struct super_block *sb,
ret = exfat_put_dentry_set(&es, IS_DIRSYNC(root_inode));
unlock:
- mutex_unlock(&sbi->s_lock);
+ up_write(&sbi->s_lock);
return ret;
}
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index f1505c013248..16ce508e0946 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -246,7 +246,7 @@ struct exfat_sb_info {
unsigned long s_exfat_flags; /* Exfat superblock flags */
- struct mutex s_lock; /* superblock lock */
+ struct rw_semaphore 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 */
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index 29c5db12288e..8abef3d2294a 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -297,7 +297,7 @@ static void exfat_truncate(struct inode *inode)
struct exfat_inode_info *ei = EXFAT_I(inode);
int err;
- mutex_lock(&sbi->s_lock);
+ down_write(&sbi->s_lock);
if (ei->start_clu == 0) {
/*
* Empty start_clu != ~0 (not allocated)
@@ -312,7 +312,7 @@ static void exfat_truncate(struct inode *inode)
inode->i_blocks = round_up(i_size_read(inode), sbi->cluster_size) >> 9;
write_size:
- mutex_unlock(&sbi->s_lock);
+ up_write(&sbi->s_lock);
}
int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index d041f893b1c3..a89826e08e1c 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -116,16 +116,16 @@ int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
if (unlikely(exfat_forced_shutdown(inode->i_sb)))
return -EIO;
- mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
+ down_write(&EXFAT_SB(inode->i_sb)->s_lock);
ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
- mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
+ up_write(&EXFAT_SB(inode->i_sb)->s_lock);
return ret;
}
void exfat_sync_inode(struct inode *inode)
{
- lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock);
+ lockdep_assert_held_write(&EXFAT_SB(inode->i_sb)->s_lock);
__exfat_write_inode(inode, 1);
}
@@ -443,9 +443,9 @@ void exfat_evict_inode(struct inode *inode)
if (!inode->i_nlink) {
i_size_write(inode, 0);
- mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
+ down_write(&EXFAT_SB(inode->i_sb)->s_lock);
__exfat_truncate(inode);
- mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
+ up_write(&EXFAT_SB(inode->i_sb)->s_lock);
}
clear_inode(inode);
diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
index 0c805bf6676a..bc8bdfa9bb80 100644
--- a/fs/exfat/iomap.c
+++ b/fs/exfat/iomap.c
@@ -68,7 +68,7 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
num_clusters = exfat_bytes_to_cluster_round_up(sbi,
offset + length) - exfat_bytes_to_cluster(sbi, offset);
- mutex_lock(&sbi->s_lock);
+ down_write(&sbi->s_lock);
iomap->bdev = inode->i_sb->s_bdev;
iomap->offset = offset;
@@ -135,7 +135,7 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
iomap->flags |= IOMAP_F_MERGED;
out:
- mutex_unlock(&sbi->s_lock);
+ up_write(&sbi->s_lock);
return err;
}
diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
index f26f987a34cf..0c28040e97d6 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -565,7 +565,7 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;
- mutex_lock(&EXFAT_SB(sb)->s_lock);
+ down_write(&EXFAT_SB(sb)->s_lock);
exfat_set_volume_dirty(sb);
err = exfat_add_entry(dir, dentry->d_name.name, TYPE_FILE, &info);
if (err)
@@ -592,7 +592,7 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
d_instantiate(dentry, inode);
unlock:
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
return err;
}
@@ -732,7 +732,7 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
int err;
loff_t i_pos;
- mutex_lock(&EXFAT_SB(sb)->s_lock);
+ down_write(&EXFAT_SB(sb)->s_lock);
err = exfat_find(dir, &dentry->d_name, &info);
if (err) {
if (unlikely(err != -ENOENT))
@@ -761,12 +761,12 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
*/
d_move(alias, dentry);
iput(inode);
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
return alias;
}
dput(alias);
out:
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
if (!inode)
exfat_d_version_set(dentry, inode_query_iversion(dir));
@@ -785,7 +785,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;
- mutex_lock(&EXFAT_SB(sb)->s_lock);
+ down_write(&EXFAT_SB(sb)->s_lock);
if (ei->dir.dir == DIR_DELETED) {
exfat_err(sb, "abnormal access to deleted dentry");
err = -ENOENT;
@@ -821,7 +821,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock:
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
return err;
}
@@ -838,7 +838,7 @@ static struct dentry *exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
if (unlikely(exfat_forced_shutdown(sb)))
return ERR_PTR(-EIO);
- mutex_lock(&EXFAT_SB(sb)->s_lock);
+ down_write(&EXFAT_SB(sb)->s_lock);
exfat_set_volume_dirty(sb);
err = exfat_add_entry(dir, dentry->d_name.name, TYPE_DIR, &info);
if (err)
@@ -867,7 +867,7 @@ static struct dentry *exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
d_instantiate(dentry, inode);
unlock:
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
return err ? ERR_PTR(err) : NULL;
}
@@ -929,7 +929,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;
- mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
+ down_write(&EXFAT_SB(inode->i_sb)->s_lock);
if (ei->dir.dir == DIR_DELETED) {
exfat_err(sb, "abnormal access to deleted dentry");
@@ -979,7 +979,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
exfat_unhash_inode(inode);
exfat_d_version_set(dentry, inode_query_iversion(dir));
unlock:
- mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
+ up_write(&EXFAT_SB(inode->i_sb)->s_lock);
return err;
}
@@ -1282,7 +1282,7 @@ static int exfat_rename(struct mnt_idmap *idmap,
if (flags & ~RENAME_NOREPLACE)
return -EINVAL;
- mutex_lock(&EXFAT_SB(sb)->s_lock);
+ down_write(&EXFAT_SB(sb)->s_lock);
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
@@ -1334,7 +1334,7 @@ static int exfat_rename(struct mnt_idmap *idmap,
}
unlock:
- mutex_unlock(&EXFAT_SB(sb)->s_lock);
+ up_write(&EXFAT_SB(sb)->s_lock);
return err;
}
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 491273d8eeb6..72a35f4079b4 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -45,11 +45,11 @@ static void exfat_put_super(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
- mutex_lock(&sbi->s_lock);
+ down_write(&sbi->s_lock);
exfat_clear_volume_dirty(sb);
exfat_free_bitmap(sbi);
brelse(sbi->boot_bh);
- mutex_unlock(&sbi->s_lock);
+ up_write(&sbi->s_lock);
}
static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -771,9 +771,9 @@ static int exfat_reconfigure(struct fs_context *fc)
fc->sb_flags |= SB_NODIRATIME;
sync_filesystem(sb);
- mutex_lock(&sbi->s_lock);
+ down_write(&sbi->s_lock);
exfat_clear_volume_dirty(sb);
- mutex_unlock(&sbi->s_lock);
+ up_write(&sbi->s_lock);
if (new_opts->allow_utime == (unsigned short)-1)
new_opts->allow_utime = ~new_opts->fs_dmask & 0022;
@@ -820,7 +820,7 @@ static int exfat_init_fs_context(struct fs_context *fc)
if (!sbi)
return -ENOMEM;
- mutex_init(&sbi->s_lock);
+ init_rwsem(&sbi->s_lock);
mutex_init(&sbi->bitmap_lock);
ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [RFC PATCH v1 6/6] exfat: take s_lock in read mode for iomap mapping paths
2026-08-21 10:05 [RFC PATCH 0/6] exfat: take s_lock in read mode for iomap mapping paths Chi Zhiling
` (4 preceding siblings ...)
2026-08-21 10:05 ` [RFC PATCH v1 5/6] exfat: convert s_lock mutex to rw_semaphore using write lock Chi Zhiling
@ 2026-08-21 10:05 ` Chi Zhiling
5 siblings, 0 replies; 7+ messages in thread
From: Chi Zhiling @ 2026-08-21 10:05 UTC (permalink / raw)
To: exfat, linux-kernel; +Cc: Namjae Jeon, Sungjong Seo, Yuezhang Mo, Chi Zhiling
From: Chi Zhiling <chizhiling@kylinos.cn>
The iomap mapping paths mainly access the FAT chain of the file itself.
Concurrent mappings of distinct inodes can therefore proceed in
parallel by taking s_lock in read mode instead of write mode. The
superblock-wide state shared between files is already protected by the
preceding patches: the allocation bitmap, used_clusters and clu_srch_ptr
by bitmap_lock, and the volume dirty flag / boot sector by atomic bit
ops with a single writer on the 0 -> 1 transition.
Concurrent access to the same inode stays serialized by the exclusive
inode_lock held in exfat_file_write_iter().
Writeback takes the read lock even though it does not hold inode_lock.
Folios under writeback are marked writeback, and truncate first flushes
and truncates the page cache, so truncate cannot run concurrently with
writeback. Writeback therefore only maps clusters that are still
committed or owned by the inode and cannot race with cluster freeing.
The lock ordering remains inode_lock -> s_lock -> bitmap_lock, so this
change does not introduce any new deadlock scenarios.
Signed-off-by: Chi Zhiling <chizhiling@kylinos.cn>
---
fs/exfat/iomap.c | 4 ++--
fs/exfat/super.c | 4 ++++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c
index bc8bdfa9bb80..147e9da01a47 100644
--- a/fs/exfat/iomap.c
+++ b/fs/exfat/iomap.c
@@ -68,7 +68,7 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
num_clusters = exfat_bytes_to_cluster_round_up(sbi,
offset + length) - exfat_bytes_to_cluster(sbi, offset);
- down_write(&sbi->s_lock);
+ down_read(&sbi->s_lock);
iomap->bdev = inode->i_sb->s_bdev;
iomap->offset = offset;
@@ -135,7 +135,7 @@ static int __exfat_iomap_begin(struct inode *inode, loff_t offset, loff_t length
iomap->flags |= IOMAP_F_MERGED;
out:
- up_write(&sbi->s_lock);
+ up_read(&sbi->s_lock);
return err;
}
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 72a35f4079b4..64ec4d2d1bf6 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -94,6 +94,8 @@ int exfat_set_volume_dirty(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ lockdep_assert_held(&sbi->s_lock);
+
if (test_and_set_bit(VOLUME_DIRTY_BIT, &sbi->vol_flags))
return 0;
@@ -104,6 +106,8 @@ int exfat_clear_volume_dirty(struct super_block *sb)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ lockdep_assert_held_write(&sbi->s_lock);
+
if (!test_and_clear_bit(VOLUME_DIRTY_BIT, &sbi->vol_flags))
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread