2024-01-30 08:22:41

by Matthew Wilcox

[permalink] [raw]
Subject: [PATCH 0/3] Start moving write_begin/write_end out of aops

Christoph wants to remove write_begin/write_end from aops and pass them
to filemap as callback functions. Hre's one possible route to do this.
I combined it with the folio conversion (because why touch the same code
twice?) and tweaked some of the other things (support for ridiculously
large folios with size_t lengths, remove the need to initialise fsdata
by passing only a pointer to the fsdata pointer). And then I converted
ext4, which is probably the worst filesystem to convert because it needs
three different bwops. Most fs will only need one.

Not written yet: convert all the other fs, remove wrappers.

Matthew Wilcox (Oracle) (3):
fs: Introduce buffered_write_operations
fs: Supply optional buffered_write_operations in buffer.c
ext4: Convert to buffered_write_operations

fs/buffer.c | 62 +++++++++++++++++++++++--------
fs/ext4/ext4.h | 8 +++-
fs/ext4/file.c | 10 ++++-
fs/ext4/inline.c | 15 +++-----
fs/ext4/inode.c | 73 +++++++++++++++++++------------------
fs/jfs/file.c | 3 +-
fs/ramfs/file-mmu.c | 3 +-
fs/ufs/file.c | 2 +-
include/linux/buffer_head.h | 22 +++++++++--
include/linux/fs.h | 3 --
include/linux/pagemap.h | 22 +++++++++++
mm/filemap.c | 70 +++++++++++++++++++++++------------
12 files changed, 193 insertions(+), 100 deletions(-)

--
2.43.0



2024-01-30 08:58:54

by Matthew Wilcox

[permalink] [raw]
Subject: [PATCH 2/3] fs: Supply optional buffered_write_operations in buffer.c

generic_cont_expand_simple() and cont_expand_zero() currently call
->write_begin and ->write_end, so will also need to be converted to use
buffered_write_operations. Use macro magic again to pass in optional
buffered_write_operations.

Signed-off-by: Matthew Wilcox (Oracle) <[email protected]>
---
fs/buffer.c | 62 +++++++++++++++++++++++++++----------
include/linux/buffer_head.h | 22 ++++++++++---
2 files changed, 64 insertions(+), 20 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index d3bcf601d3e5..8ed76fc6cff0 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2441,11 +2441,13 @@ EXPORT_SYMBOL(block_read_full_folio);
* truncates. Uses filesystem pagecache writes to allow the filesystem to
* deal with the hole.
*/
-int generic_cont_expand_simple(struct inode *inode, loff_t size)
+int generic_cont_expand_simple(struct inode *inode, loff_t size,
+ const struct buffered_write_operations *ops)
{
struct address_space *mapping = inode->i_mapping;
const struct address_space_operations *aops = mapping->a_ops;
struct page *page;
+ struct folio *folio;
void *fsdata = NULL;
int err;

@@ -2453,11 +2455,17 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size)
if (err)
goto out;

- err = aops->write_begin(NULL, mapping, size, 0, &page, &fsdata);
+ if (ops)
+ err = ops->write_begin(NULL, mapping, size, 0, &folio, &fsdata);
+ else
+ err = aops->write_begin(NULL, mapping, size, 0, &page, &fsdata);
if (err)
goto out;

- err = aops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
+ if (ops)
+ err = ops->write_end(NULL, mapping, size, 0, 0, folio, &fsdata);
+ else
+ err = aops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
BUG_ON(err > 0);

out:
@@ -2466,12 +2474,14 @@ int generic_cont_expand_simple(struct inode *inode, loff_t size)
EXPORT_SYMBOL(generic_cont_expand_simple);

static int cont_expand_zero(struct file *file, struct address_space *mapping,
- loff_t pos, loff_t *bytes)
+ loff_t pos, loff_t *bytes,
+ const struct buffered_write_operations *ops)
{
struct inode *inode = mapping->host;
const struct address_space_operations *aops = mapping->a_ops;
unsigned int blocksize = i_blocksize(inode);
struct page *page;
+ struct folio *folio;
void *fsdata = NULL;
pgoff_t index, curidx;
loff_t curpos;
@@ -2489,13 +2499,23 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
}
len = PAGE_SIZE - zerofrom;

- err = aops->write_begin(file, mapping, curpos, len,
- &page, &fsdata);
+ if (ops) {
+ err = ops->write_begin(file, mapping, curpos, len,
+ &folio, &fsdata);
+ page = &folio->page;
+ } else {
+ err = aops->write_begin(file, mapping, curpos, len,
+ &page, &fsdata);
+ }
if (err)
goto out;
zero_user(page, zerofrom, len);
- err = aops->write_end(file, mapping, curpos, len, len,
- page, fsdata);
+ if (ops)
+ err = ops->write_end(file, mapping, curpos, len, len,
+ folio, &fsdata);
+ else
+ err = aops->write_end(file, mapping, curpos, len, len,
+ page, fsdata);
if (err < 0)
goto out;
BUG_ON(err != len);
@@ -2522,13 +2542,23 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
}
len = offset - zerofrom;

- err = aops->write_begin(file, mapping, curpos, len,
- &page, &fsdata);
+ if (ops) {
+ err = ops->write_begin(file, mapping, curpos, len,
+ &folio, &fsdata);
+ page = &folio->page;
+ } else {
+ err = aops->write_begin(file, mapping, curpos, len,
+ &page, &fsdata);
+ }
if (err)
goto out;
zero_user(page, zerofrom, len);
- err = aops->write_end(file, mapping, curpos, len, len,
- page, fsdata);
+ if (ops)
+ err = ops->write_end(file, mapping, curpos, len, len,
+ folio, &fsdata);
+ else
+ err = aops->write_end(file, mapping, curpos, len, len,
+ page, fsdata);
if (err < 0)
goto out;
BUG_ON(err != len);
@@ -2543,16 +2573,16 @@ static int cont_expand_zero(struct file *file, struct address_space *mapping,
* We may have to extend the file.
*/
int cont_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len,
- struct page **pagep, void **fsdata,
- get_block_t *get_block, loff_t *bytes)
+ loff_t pos, unsigned len, struct page **pagep, void **fsdata,
+ get_block_t *get_block, loff_t *bytes,
+ const struct buffered_write_operations *ops)
{
struct inode *inode = mapping->host;
unsigned int blocksize = i_blocksize(inode);
unsigned int zerofrom;
int err;

- err = cont_expand_zero(file, mapping, pos, bytes);
+ err = cont_expand_zero(file, mapping, pos, bytes, ops);
if (err)
return err;

diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index d78454a4dd1f..80de88c12d23 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -268,16 +268,30 @@ int generic_write_end(struct file *, struct address_space *,
loff_t, unsigned, unsigned,
struct page *, void *);
void folio_zero_new_buffers(struct folio *folio, size_t from, size_t to);
-int cont_write_begin(struct file *, struct address_space *, loff_t,
- unsigned, struct page **, void **,
- get_block_t *, loff_t *);
-int generic_cont_expand_simple(struct inode *inode, loff_t size);
+int cont_write_begin(struct file *, struct address_space *, loff_t pos,
+ unsigned len, struct page **, void **fsdata, get_block_t *,
+ loff_t *bytes, const struct buffered_write_operations *);
+int generic_cont_expand_simple(struct inode *inode, loff_t size,
+ const struct buffered_write_operations *ops);
void block_commit_write(struct page *page, unsigned int from, unsigned int to);
int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
get_block_t get_block);
sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
int block_truncate_page(struct address_space *, loff_t, get_block_t *);

+#define _cont_write_begin(file, mapping, pos, len, pagep, fsdata, \
+ getblk, bytes, ops, extra...) \
+ cont_write_begin(file, mapping, pos, len, pagep, fsdata, \
+ getblk,bytes, ops)
+#define cont_write_begin(file, mapping, pos, len, pagep, fsdata, \
+ getblk, bytes, ops...) \
+ _cont_write_begin(file, mapping, pos, len, pagep, fsdata, \
+ getblk, bytes, ## ops, NULL)
+#define _generic_cont_expand_simple(inode, size, ops, extra...) \
+ generic_cont_expand_simple(inode, size, ops)
+#define generic_cont_expand_simple(inode, size, ops...) \
+ _generic_cont_expand_simple(inode, size, ## ops, NULL)
+
#ifdef CONFIG_MIGRATION
extern int buffer_migrate_folio(struct address_space *,
struct folio *dst, struct folio *src, enum migrate_mode);
--
2.43.0