[PATCH 4/6] ceph: convert ceph_fill_inline_data() to take a folio

From: Tal Zussman

Date: Tue Aug 25 2026 - 17:50:44 EST


Convert the internals to folio APIs and pass a folio in from
ceph_fill_inode(). The kmap_atomic()/memcpy() pair becomes
memcpy_to_folio(), which also flushes the dcache, so drop the explicit
flush from the folio creation path. When a locked folio is passed in,
the callers flush after filling it, so the flush in memcpy_to_folio()
is redundant there, but harmless.

This removes the last caller of find_or_create_page() in ceph and saves
six calls to compound_head(). The page_folio() call added in
ceph_fill_inode() goes away once the locked page plumbing is converted.

Remove extern from the function declaration while at it.

Signed-off-by: Tal Zussman <tz2294@xxxxxxxxxxxx>
---
fs/ceph/addr.c | 47 +++++++++++++++++++++--------------------------
fs/ceph/inode.c | 3 ++-
fs/ceph/super.h | 4 ++--
3 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 988ead716991..2ff90b891fc9 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -2196,50 +2196,45 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
return ret;
}

-void ceph_fill_inline_data(struct inode *inode, struct page *locked_page,
+void ceph_fill_inline_data(struct inode *inode, struct folio *locked_folio,
char *data, size_t len)
{
struct ceph_client *cl = ceph_inode_to_client(inode);
struct address_space *mapping = inode->i_mapping;
- struct page *page;
+ struct folio *folio;

- if (locked_page) {
- page = locked_page;
+ if (locked_folio) {
+ folio = locked_folio;
} else {
if (i_size_read(inode) == 0)
return;
- page = find_or_create_page(mapping, 0,
- mapping_gfp_constraint(mapping,
- ~__GFP_FS));
- if (!page)
+ folio = __filemap_get_folio(mapping, 0,
+ FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
+ mapping_gfp_constraint(mapping, ~__GFP_FS));
+ if (IS_ERR(folio))
return;
- if (PageUptodate(page)) {
- unlock_page(page);
- put_page(page);
+ if (folio_test_uptodate(folio)) {
+ folio_unlock(folio);
+ folio_put(folio);
return;
}
}

- doutc(cl, "%p %llx.%llx len %zu locked_page %p\n", inode,
- ceph_vinop(inode), len, locked_page);
+ doutc(cl, "%p %llx.%llx len %zu locked_folio %p\n", inode,
+ ceph_vinop(inode), len, locked_folio);

- if (len > 0) {
- void *kaddr = kmap_atomic(page);
- memcpy(kaddr, data, len);
- kunmap_atomic(kaddr);
- }
+ if (len > 0)
+ memcpy_to_folio(folio, 0, data, len);

- if (page != locked_page) {
- if (len < PAGE_SIZE)
- zero_user_segment(page, len, PAGE_SIZE);
- else
- flush_dcache_page(page);
+ if (folio != locked_folio) {
+ if (len < folio_size(folio))
+ folio_zero_segment(folio, len, folio_size(folio));

if (len > 0)
- SetPageUptodate(page);
+ folio_mark_uptodate(folio);

- unlock_page(page);
- put_page(page);
+ folio_unlock(folio);
+ folio_put(folio);
}
}

diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index d52e2b389e0b..b91125567cf0 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1383,7 +1383,8 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
ceph_fscache_register_inode_cookie(inode);

if (fill_inline)
- ceph_fill_inline_data(inode, locked_page,
+ ceph_fill_inline_data(inode,
+ locked_page ? page_folio(locked_page) : NULL,
iinfo->inline_data, iinfo->inline_len);

if (wake)
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 0a779cdc8392..30e625e02398 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -1400,8 +1400,8 @@ extern ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
struct iov_iter *to, int *retry_op,
u64 *last_objver);
extern int ceph_release(struct inode *inode, struct file *filp);
-extern void ceph_fill_inline_data(struct inode *inode, struct page *locked_page,
- char *data, size_t len);
+void ceph_fill_inline_data(struct inode *inode, struct folio *locked_folio,
+ char *data, size_t len);

/* dir.c */
extern const struct file_operations ceph_dir_fops;

--
2.39.5