[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240122094536.198454-2-libaokun1@huawei.com>
Date: Mon, 22 Jan 2024 17:45:35 +0800
From: Baokun Li <libaokun1@...wei.com>
To: <linux-fsdevel@...r.kernel.org>
CC: <torvalds@...ux-foundation.org>, <viro@...iv.linux.org.uk>,
<brauner@...nel.org>, <jack@...e.cz>, <willy@...radead.org>,
<akpm@...ux-foundation.org>, <linux-kernel@...r.kernel.org>,
<yi.zhang@...wei.com>, <yangerkun@...wei.com>, <yukuai3@...wei.com>,
<libaokun1@...wei.com>
Subject: [PATCH 1/2] fs: make the i_size_read/write helpers be smp_load_acquire/store_release()
In [Link] linus mentions that acquire/release makes it clear which
_particular_ memory accesses are the ordered ones, and it's unlikely
to make any performance difference, so it's much better to pair up
the release->acquire ordering than have a "wmb->rmb" ordering.
=========================================================
update pagecache
folio_mark_uptodate(folio)
smp_wmb()
set_bit PG_uptodate
=== ↑↑↑ STLR ↑↑↑ === smp_store_release(&inode->i_size, i_size)
folio_test_uptodate(folio)
test_bit PG_uptodate
smp_rmb()
=== ↓↓↓ LDAR ↓↓↓ === smp_load_acquire(&inode->i_size)
copy_page_to_iter()
=========================================================
Calling smp_store_release() in i_size_write() ensures that the data
in the page and the PG_uptodate bit are updated before the isize is
updated, and calling smp_load_acquire() in i_size_read ensures that
it will not read a newer isize than the data in the page. Therefore,
this avoids buffered read-write inconsistencies caused by Load-Load
reordering.
Link: https://lore.kernel.org/r/CAHk-=wifOnmeJq+sn+2s-P46zw0SFEbw9BSCGgp2c5fYPtRPGw@mail.gmail.com/
Suggested-by: Linus Torvalds <torvalds@...ux-foundation.org>
Signed-off-by: Baokun Li <libaokun1@...wei.com>
---
include/linux/fs.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 06ecccbb5bfe..077849bfe89a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -907,7 +907,8 @@ static inline loff_t i_size_read(const struct inode *inode)
preempt_enable();
return i_size;
#else
- return inode->i_size;
+ /* Pairs with smp_store_release() in i_size_write() */
+ return smp_load_acquire(&inode->i_size);
#endif
}
@@ -929,7 +930,12 @@ static inline void i_size_write(struct inode *inode, loff_t i_size)
inode->i_size = i_size;
preempt_enable();
#else
- inode->i_size = i_size;
+ /*
+ * Pairs with smp_load_acquire() in i_size_read() to ensure
+ * changes related to inode size (such as page contents) are
+ * visible before we see the changed inode size.
+ */
+ smp_store_release(&inode->i_size, i_size);
#endif
}
--
2.31.1
Powered by blists - more mailing lists