mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-13 19:59:34 -04:00
Merge patch series "Remove accesses to page->index from ceph"
Remove page->index access from ceph. * patches from https://lore.kernel.org/r/20250217185119.430193-1-willy@infradead.org: fs: Remove page_mkwrite_check_truncate() ceph: Pass a folio to ceph_allocate_page_array() ceph: Convert ceph_move_dirty_page_in_page_array() to move_dirty_folio_in_page_array() ceph: Remove uses of page from ceph_process_folio_batch() ceph: Convert ceph_check_page_before_write() to use a folio ceph: Convert writepage_nounlock() to write_folio_nounlock() ceph: Convert ceph_readdir_cache_control to store a folio ceph: Convert ceph_find_incompatible() to take a folio ceph: Use a folio in ceph_page_mkwrite() ceph: Remove ceph_writepage() Link: https://lore.kernel.org/r/20250217185119.430193-1-willy@infradead.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
239
fs/ceph/addr.c
239
fs/ceph/addr.c
@@ -698,22 +698,23 @@ static u64 get_writepages_data_length(struct inode *inode,
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a single page, but leave the page locked.
|
||||
* Write a folio, but leave it locked.
|
||||
*
|
||||
* If we get a write error, mark the mapping for error, but still adjust the
|
||||
* dirty page accounting (i.e., page is no longer dirty).
|
||||
* dirty page accounting (i.e., folio is no longer dirty).
|
||||
*/
|
||||
static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
||||
static int write_folio_nounlock(struct folio *folio,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
struct folio *folio = page_folio(page);
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct page *page = &folio->page;
|
||||
struct inode *inode = folio->mapping->host;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
|
||||
struct ceph_client *cl = fsc->client;
|
||||
struct ceph_snap_context *snapc, *oldest;
|
||||
loff_t page_off = page_offset(page);
|
||||
loff_t page_off = folio_pos(folio);
|
||||
int err;
|
||||
loff_t len = thp_size(page);
|
||||
loff_t len = folio_size(folio);
|
||||
loff_t wlen;
|
||||
struct ceph_writeback_ctl ceph_wbc;
|
||||
struct ceph_osd_client *osdc = &fsc->client->osdc;
|
||||
@@ -721,27 +722,27 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
||||
bool caching = ceph_is_cache_enabled(inode);
|
||||
struct page *bounce_page = NULL;
|
||||
|
||||
doutc(cl, "%llx.%llx page %p idx %lu\n", ceph_vinop(inode), page,
|
||||
page->index);
|
||||
doutc(cl, "%llx.%llx folio %p idx %lu\n", ceph_vinop(inode), folio,
|
||||
folio->index);
|
||||
|
||||
if (ceph_inode_is_shutdown(inode))
|
||||
return -EIO;
|
||||
|
||||
/* verify this is a writeable snap context */
|
||||
snapc = page_snap_context(page);
|
||||
snapc = page_snap_context(&folio->page);
|
||||
if (!snapc) {
|
||||
doutc(cl, "%llx.%llx page %p not dirty?\n", ceph_vinop(inode),
|
||||
page);
|
||||
doutc(cl, "%llx.%llx folio %p not dirty?\n", ceph_vinop(inode),
|
||||
folio);
|
||||
return 0;
|
||||
}
|
||||
oldest = get_oldest_context(inode, &ceph_wbc, snapc);
|
||||
if (snapc->seq > oldest->seq) {
|
||||
doutc(cl, "%llx.%llx page %p snapc %p not writeable - noop\n",
|
||||
ceph_vinop(inode), page, snapc);
|
||||
doutc(cl, "%llx.%llx folio %p snapc %p not writeable - noop\n",
|
||||
ceph_vinop(inode), folio, snapc);
|
||||
/* we should only noop if called by kswapd */
|
||||
WARN_ON(!(current->flags & PF_MEMALLOC));
|
||||
ceph_put_snap_context(oldest);
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
return 0;
|
||||
}
|
||||
ceph_put_snap_context(oldest);
|
||||
@@ -758,8 +759,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
||||
len = ceph_wbc.i_size - page_off;
|
||||
|
||||
wlen = IS_ENCRYPTED(inode) ? round_up(len, CEPH_FSCRYPT_BLOCK_SIZE) : len;
|
||||
doutc(cl, "%llx.%llx page %p index %lu on %llu~%llu snapc %p seq %lld\n",
|
||||
ceph_vinop(inode), page, page->index, page_off, wlen, snapc,
|
||||
doutc(cl, "%llx.%llx folio %p index %lu on %llu~%llu snapc %p seq %lld\n",
|
||||
ceph_vinop(inode), folio, folio->index, page_off, wlen, snapc,
|
||||
snapc->seq);
|
||||
|
||||
if (atomic_long_inc_return(&fsc->writeback_count) >
|
||||
@@ -772,32 +773,32 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
||||
ceph_wbc.truncate_seq,
|
||||
ceph_wbc.truncate_size, true);
|
||||
if (IS_ERR(req)) {
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
return PTR_ERR(req);
|
||||
}
|
||||
|
||||
if (wlen < len)
|
||||
len = wlen;
|
||||
|
||||
set_page_writeback(page);
|
||||
folio_start_writeback(folio);
|
||||
if (caching)
|
||||
ceph_set_page_fscache(page);
|
||||
ceph_set_page_fscache(&folio->page);
|
||||
ceph_fscache_write_to_cache(inode, page_off, len, caching);
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
bounce_page = fscrypt_encrypt_pagecache_blocks(page,
|
||||
bounce_page = fscrypt_encrypt_pagecache_blocks(&folio->page,
|
||||
CEPH_FSCRYPT_BLOCK_SIZE, 0,
|
||||
GFP_NOFS);
|
||||
if (IS_ERR(bounce_page)) {
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
end_page_writeback(page);
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
folio_end_writeback(folio);
|
||||
ceph_osdc_put_request(req);
|
||||
return PTR_ERR(bounce_page);
|
||||
}
|
||||
}
|
||||
|
||||
/* it may be a short write due to an object boundary */
|
||||
WARN_ON_ONCE(len > thp_size(page));
|
||||
WARN_ON_ONCE(len > folio_size(folio));
|
||||
osd_req_op_extent_osd_data_pages(req, 0,
|
||||
bounce_page ? &bounce_page : &page, wlen, 0,
|
||||
false, false);
|
||||
@@ -823,25 +824,25 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
||||
if (err == -ERESTARTSYS) {
|
||||
/* killed by SIGKILL */
|
||||
doutc(cl, "%llx.%llx interrupted page %p\n",
|
||||
ceph_vinop(inode), page);
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
end_page_writeback(page);
|
||||
ceph_vinop(inode), folio);
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
folio_end_writeback(folio);
|
||||
return err;
|
||||
}
|
||||
if (err == -EBLOCKLISTED)
|
||||
fsc->blocklisted = true;
|
||||
doutc(cl, "%llx.%llx setting page/mapping error %d %p\n",
|
||||
ceph_vinop(inode), err, page);
|
||||
doutc(cl, "%llx.%llx setting mapping error %d %p\n",
|
||||
ceph_vinop(inode), err, folio);
|
||||
mapping_set_error(&inode->i_data, err);
|
||||
wbc->pages_skipped++;
|
||||
} else {
|
||||
doutc(cl, "%llx.%llx cleaned page %p\n",
|
||||
ceph_vinop(inode), page);
|
||||
ceph_vinop(inode), folio);
|
||||
err = 0; /* vfs expects us to return 0 */
|
||||
}
|
||||
oldest = detach_page_private(page);
|
||||
oldest = folio_detach_private(folio);
|
||||
WARN_ON_ONCE(oldest != snapc);
|
||||
end_page_writeback(page);
|
||||
folio_end_writeback(folio);
|
||||
ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
|
||||
ceph_put_snap_context(snapc); /* page's reference */
|
||||
|
||||
@@ -852,32 +853,6 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ceph_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode = page->mapping->host;
|
||||
BUG_ON(!inode);
|
||||
ihold(inode);
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_NONE &&
|
||||
ceph_inode_to_fs_client(inode)->write_congested) {
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
return AOP_WRITEPAGE_ACTIVATE;
|
||||
}
|
||||
|
||||
folio_wait_private_2(page_folio(page)); /* [DEPRECATED] */
|
||||
|
||||
err = writepage_nounlock(page, wbc);
|
||||
if (err == -ERESTARTSYS) {
|
||||
/* direct memory reclaimer was killed by SIGKILL. return 0
|
||||
* to prevent caller from setting mapping/page error */
|
||||
err = 0;
|
||||
}
|
||||
unlock_page(page);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* async writeback completion handler.
|
||||
*
|
||||
@@ -1157,18 +1132,17 @@ int ceph_check_page_before_write(struct address_space *mapping,
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
|
||||
struct ceph_client *cl = fsc->client;
|
||||
struct ceph_snap_context *pgsnapc;
|
||||
struct page *page = &folio->page;
|
||||
|
||||
/* only dirty pages, or our accounting breaks */
|
||||
if (unlikely(!PageDirty(page)) || unlikely(page->mapping != mapping)) {
|
||||
doutc(cl, "!dirty or !mapping %p\n", page);
|
||||
/* only dirty folios, or our accounting breaks */
|
||||
if (unlikely(!folio_test_dirty(folio) || folio->mapping != mapping)) {
|
||||
doutc(cl, "!dirty or !mapping %p\n", folio);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/* only if matching snap context */
|
||||
pgsnapc = page_snap_context(page);
|
||||
pgsnapc = page_snap_context(&folio->page);
|
||||
if (pgsnapc != ceph_wbc->snapc) {
|
||||
doutc(cl, "page snapc %p %lld != oldest %p %lld\n",
|
||||
doutc(cl, "folio snapc %p %lld != oldest %p %lld\n",
|
||||
pgsnapc, pgsnapc->seq,
|
||||
ceph_wbc->snapc, ceph_wbc->snapc->seq);
|
||||
|
||||
@@ -1179,7 +1153,7 @@ int ceph_check_page_before_write(struct address_space *mapping,
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (page_offset(page) >= ceph_wbc->i_size) {
|
||||
if (folio_pos(folio) >= ceph_wbc->i_size) {
|
||||
doutc(cl, "folio at %lu beyond eof %llu\n",
|
||||
folio->index, ceph_wbc->i_size);
|
||||
|
||||
@@ -1192,8 +1166,8 @@ int ceph_check_page_before_write(struct address_space *mapping,
|
||||
}
|
||||
|
||||
if (ceph_wbc->strip_unit_end &&
|
||||
(page->index > ceph_wbc->strip_unit_end)) {
|
||||
doutc(cl, "end of strip unit %p\n", page);
|
||||
(folio->index > ceph_wbc->strip_unit_end)) {
|
||||
doutc(cl, "end of strip unit %p\n", folio);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
@@ -1217,7 +1191,7 @@ void __ceph_allocate_page_array(struct ceph_writeback_ctl *ceph_wbc,
|
||||
static inline
|
||||
void ceph_allocate_page_array(struct address_space *mapping,
|
||||
struct ceph_writeback_ctl *ceph_wbc,
|
||||
struct page *page)
|
||||
struct folio *folio)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
@@ -1226,13 +1200,13 @@ void ceph_allocate_page_array(struct address_space *mapping,
|
||||
u32 xlen;
|
||||
|
||||
/* prepare async write request */
|
||||
ceph_wbc->offset = (u64)page_offset(page);
|
||||
ceph_wbc->offset = (u64)folio_pos(folio);
|
||||
ceph_calc_file_object_mapping(&ci->i_layout,
|
||||
ceph_wbc->offset, ceph_wbc->wsize,
|
||||
&objnum, &objoff, &xlen);
|
||||
|
||||
ceph_wbc->num_ops = 1;
|
||||
ceph_wbc->strip_unit_end = page->index + ((xlen - 1) >> PAGE_SHIFT);
|
||||
ceph_wbc->strip_unit_end = folio->index + ((xlen - 1) >> PAGE_SHIFT);
|
||||
|
||||
BUG_ON(ceph_wbc->pages);
|
||||
ceph_wbc->max_pages = calc_pages_for(0, (u64)xlen);
|
||||
@@ -1242,10 +1216,10 @@ void ceph_allocate_page_array(struct address_space *mapping,
|
||||
}
|
||||
|
||||
static inline
|
||||
bool is_page_index_contiguous(struct ceph_writeback_ctl *ceph_wbc,
|
||||
struct page *page)
|
||||
bool is_folio_index_contiguous(const struct ceph_writeback_ctl *ceph_wbc,
|
||||
const struct folio *folio)
|
||||
{
|
||||
return page->index == (ceph_wbc->offset + ceph_wbc->len) >> PAGE_SHIFT;
|
||||
return folio->index == (ceph_wbc->offset + ceph_wbc->len) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static inline
|
||||
@@ -1262,11 +1236,9 @@ bool is_write_congestion_happened(struct ceph_fs_client *fsc)
|
||||
CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb);
|
||||
}
|
||||
|
||||
static inline
|
||||
int ceph_move_dirty_page_in_page_array(struct address_space *mapping,
|
||||
struct writeback_control *wbc,
|
||||
struct ceph_writeback_ctl *ceph_wbc,
|
||||
struct page *page)
|
||||
static inline int move_dirty_folio_in_page_array(struct address_space *mapping,
|
||||
struct writeback_control *wbc,
|
||||
struct ceph_writeback_ctl *ceph_wbc, struct folio *folio)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
|
||||
@@ -1276,7 +1248,7 @@ int ceph_move_dirty_page_in_page_array(struct address_space *mapping,
|
||||
gfp_t gfp_flags = ceph_wbc->locked_pages ? GFP_NOWAIT : GFP_NOFS;
|
||||
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
pages[index] = fscrypt_encrypt_pagecache_blocks(page,
|
||||
pages[index] = fscrypt_encrypt_pagecache_blocks(&folio->page,
|
||||
PAGE_SIZE,
|
||||
0,
|
||||
gfp_flags);
|
||||
@@ -1293,7 +1265,7 @@ int ceph_move_dirty_page_in_page_array(struct address_space *mapping,
|
||||
return PTR_ERR(pages[index]);
|
||||
}
|
||||
} else {
|
||||
pages[index] = page;
|
||||
pages[index] = &folio->page;
|
||||
}
|
||||
|
||||
ceph_wbc->locked_pages++;
|
||||
@@ -1310,7 +1282,6 @@ int ceph_process_folio_batch(struct address_space *mapping,
|
||||
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
|
||||
struct ceph_client *cl = fsc->client;
|
||||
struct folio *folio = NULL;
|
||||
struct page *page = NULL;
|
||||
unsigned i;
|
||||
int rc = 0;
|
||||
|
||||
@@ -1320,11 +1291,9 @@ int ceph_process_folio_batch(struct address_space *mapping,
|
||||
if (!folio)
|
||||
continue;
|
||||
|
||||
page = &folio->page;
|
||||
|
||||
doutc(cl, "? %p idx %lu, folio_test_writeback %#x, "
|
||||
"folio_test_dirty %#x, folio_test_locked %#x\n",
|
||||
page, page->index, folio_test_writeback(folio),
|
||||
folio, folio->index, folio_test_writeback(folio),
|
||||
folio_test_dirty(folio),
|
||||
folio_test_locked(folio));
|
||||
|
||||
@@ -1337,27 +1306,27 @@ int ceph_process_folio_batch(struct address_space *mapping,
|
||||
}
|
||||
|
||||
if (ceph_wbc->locked_pages == 0)
|
||||
lock_page(page); /* first page */
|
||||
else if (!trylock_page(page))
|
||||
folio_lock(folio);
|
||||
else if (!folio_trylock(folio))
|
||||
break;
|
||||
|
||||
rc = ceph_check_page_before_write(mapping, wbc,
|
||||
ceph_wbc, folio);
|
||||
if (rc == -ENODATA) {
|
||||
rc = 0;
|
||||
unlock_page(page);
|
||||
folio_unlock(folio);
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
continue;
|
||||
} else if (rc == -E2BIG) {
|
||||
rc = 0;
|
||||
unlock_page(page);
|
||||
folio_unlock(folio);
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!clear_page_dirty_for_io(page)) {
|
||||
doutc(cl, "%p !clear_page_dirty_for_io\n", page);
|
||||
unlock_page(page);
|
||||
if (!folio_clear_dirty_for_io(folio)) {
|
||||
doutc(cl, "%p !folio_clear_dirty_for_io\n", folio);
|
||||
folio_unlock(folio);
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
@@ -1369,35 +1338,35 @@ int ceph_process_folio_batch(struct address_space *mapping,
|
||||
* allocate a page array
|
||||
*/
|
||||
if (ceph_wbc->locked_pages == 0) {
|
||||
ceph_allocate_page_array(mapping, ceph_wbc, page);
|
||||
} else if (!is_page_index_contiguous(ceph_wbc, page)) {
|
||||
ceph_allocate_page_array(mapping, ceph_wbc, folio);
|
||||
} else if (!is_folio_index_contiguous(ceph_wbc, folio)) {
|
||||
if (is_num_ops_too_big(ceph_wbc)) {
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
unlock_page(page);
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
folio_unlock(folio);
|
||||
break;
|
||||
}
|
||||
|
||||
ceph_wbc->num_ops++;
|
||||
ceph_wbc->offset = (u64)page_offset(page);
|
||||
ceph_wbc->offset = (u64)folio_pos(folio);
|
||||
ceph_wbc->len = 0;
|
||||
}
|
||||
|
||||
/* note position of first page in fbatch */
|
||||
doutc(cl, "%llx.%llx will write page %p idx %lu\n",
|
||||
ceph_vinop(inode), page, page->index);
|
||||
doutc(cl, "%llx.%llx will write folio %p idx %lu\n",
|
||||
ceph_vinop(inode), folio, folio->index);
|
||||
|
||||
fsc->write_congested = is_write_congestion_happened(fsc);
|
||||
|
||||
rc = ceph_move_dirty_page_in_page_array(mapping, wbc,
|
||||
ceph_wbc, page);
|
||||
rc = move_dirty_folio_in_page_array(mapping, wbc, ceph_wbc,
|
||||
folio);
|
||||
if (rc) {
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
unlock_page(page);
|
||||
folio_redirty_for_writepage(wbc, folio);
|
||||
folio_unlock(folio);
|
||||
break;
|
||||
}
|
||||
|
||||
ceph_wbc->fbatch.folios[i] = NULL;
|
||||
ceph_wbc->len += thp_size(page);
|
||||
ceph_wbc->len += folio_size(folio);
|
||||
}
|
||||
|
||||
ceph_wbc->processed_in_fbatch = i;
|
||||
@@ -1797,56 +1766,56 @@ static int context_is_writeable_or_written(struct inode *inode,
|
||||
|
||||
/**
|
||||
* ceph_find_incompatible - find an incompatible context and return it
|
||||
* @page: page being dirtied
|
||||
* @folio: folio being dirtied
|
||||
*
|
||||
* We are only allowed to write into/dirty a page if the page is
|
||||
* We are only allowed to write into/dirty a folio if the folio is
|
||||
* clean, or already dirty within the same snap context. Returns a
|
||||
* conflicting context if there is one, NULL if there isn't, or a
|
||||
* negative error code on other errors.
|
||||
*
|
||||
* Must be called with page lock held.
|
||||
* Must be called with folio lock held.
|
||||
*/
|
||||
static struct ceph_snap_context *
|
||||
ceph_find_incompatible(struct page *page)
|
||||
ceph_find_incompatible(struct folio *folio)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct inode *inode = folio->mapping->host;
|
||||
struct ceph_client *cl = ceph_inode_to_client(inode);
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
|
||||
if (ceph_inode_is_shutdown(inode)) {
|
||||
doutc(cl, " %llx.%llx page %p is shutdown\n",
|
||||
ceph_vinop(inode), page);
|
||||
doutc(cl, " %llx.%llx folio %p is shutdown\n",
|
||||
ceph_vinop(inode), folio);
|
||||
return ERR_PTR(-ESTALE);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct ceph_snap_context *snapc, *oldest;
|
||||
|
||||
wait_on_page_writeback(page);
|
||||
folio_wait_writeback(folio);
|
||||
|
||||
snapc = page_snap_context(page);
|
||||
snapc = page_snap_context(&folio->page);
|
||||
if (!snapc || snapc == ci->i_head_snapc)
|
||||
break;
|
||||
|
||||
/*
|
||||
* this page is already dirty in another (older) snap
|
||||
* this folio is already dirty in another (older) snap
|
||||
* context! is it writeable now?
|
||||
*/
|
||||
oldest = get_oldest_context(inode, NULL, NULL);
|
||||
if (snapc->seq > oldest->seq) {
|
||||
/* not writeable -- return it for the caller to deal with */
|
||||
ceph_put_snap_context(oldest);
|
||||
doutc(cl, " %llx.%llx page %p snapc %p not current or oldest\n",
|
||||
ceph_vinop(inode), page, snapc);
|
||||
doutc(cl, " %llx.%llx folio %p snapc %p not current or oldest\n",
|
||||
ceph_vinop(inode), folio, snapc);
|
||||
return ceph_get_snap_context(snapc);
|
||||
}
|
||||
ceph_put_snap_context(oldest);
|
||||
|
||||
/* yay, writeable, do it now (without dropping page lock) */
|
||||
doutc(cl, " %llx.%llx page %p snapc %p not current, but oldest\n",
|
||||
ceph_vinop(inode), page, snapc);
|
||||
if (clear_page_dirty_for_io(page)) {
|
||||
int r = writepage_nounlock(page, NULL);
|
||||
/* yay, writeable, do it now (without dropping folio lock) */
|
||||
doutc(cl, " %llx.%llx folio %p snapc %p not current, but oldest\n",
|
||||
ceph_vinop(inode), folio, snapc);
|
||||
if (folio_clear_dirty_for_io(folio)) {
|
||||
int r = write_folio_nounlock(folio, NULL);
|
||||
if (r < 0)
|
||||
return ERR_PTR(r);
|
||||
}
|
||||
@@ -1861,7 +1830,7 @@ static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_snap_context *snapc;
|
||||
|
||||
snapc = ceph_find_incompatible(folio_page(*foliop, 0));
|
||||
snapc = ceph_find_incompatible(*foliop);
|
||||
if (snapc) {
|
||||
int r;
|
||||
|
||||
@@ -1944,7 +1913,6 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
|
||||
const struct address_space_operations ceph_aops = {
|
||||
.read_folio = netfs_read_folio,
|
||||
.readahead = netfs_readahead,
|
||||
.writepage = ceph_writepage,
|
||||
.writepages = ceph_writepages_start,
|
||||
.write_begin = ceph_write_begin,
|
||||
.write_end = ceph_write_end,
|
||||
@@ -1952,6 +1920,7 @@ const struct address_space_operations ceph_aops = {
|
||||
.invalidate_folio = ceph_invalidate_folio,
|
||||
.release_folio = netfs_release_folio,
|
||||
.direct_IO = noop_direct_IO,
|
||||
.migrate_folio = filemap_migrate_folio,
|
||||
};
|
||||
|
||||
static void ceph_block_sigs(sigset_t *oldset)
|
||||
@@ -2068,8 +2037,8 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
|
||||
struct ceph_inode_info *ci = ceph_inode(inode);
|
||||
struct ceph_file_info *fi = vma->vm_file->private_data;
|
||||
struct ceph_cap_flush *prealloc_cf;
|
||||
struct page *page = vmf->page;
|
||||
loff_t off = page_offset(page);
|
||||
struct folio *folio = page_folio(vmf->page);
|
||||
loff_t off = folio_pos(folio);
|
||||
loff_t size = i_size_read(inode);
|
||||
size_t len;
|
||||
int want, got, err;
|
||||
@@ -2086,10 +2055,10 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
|
||||
sb_start_pagefault(inode->i_sb);
|
||||
ceph_block_sigs(&oldset);
|
||||
|
||||
if (off + thp_size(page) <= size)
|
||||
len = thp_size(page);
|
||||
if (off + folio_size(folio) <= size)
|
||||
len = folio_size(folio);
|
||||
else
|
||||
len = offset_in_thp(page, size);
|
||||
len = offset_in_folio(folio, size);
|
||||
|
||||
doutc(cl, "%llx.%llx %llu~%zd getting caps i_size %llu\n",
|
||||
ceph_vinop(inode), off, len, size);
|
||||
@@ -2106,30 +2075,30 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf)
|
||||
doutc(cl, "%llx.%llx %llu~%zd got cap refs on %s\n", ceph_vinop(inode),
|
||||
off, len, ceph_cap_string(got));
|
||||
|
||||
/* Update time before taking page lock */
|
||||
/* Update time before taking folio lock */
|
||||
file_update_time(vma->vm_file);
|
||||
inode_inc_iversion_raw(inode);
|
||||
|
||||
do {
|
||||
struct ceph_snap_context *snapc;
|
||||
|
||||
lock_page(page);
|
||||
folio_lock(folio);
|
||||
|
||||
if (page_mkwrite_check_truncate(page, inode) < 0) {
|
||||
unlock_page(page);
|
||||
if (folio_mkwrite_check_truncate(folio, inode) < 0) {
|
||||
folio_unlock(folio);
|
||||
ret = VM_FAULT_NOPAGE;
|
||||
break;
|
||||
}
|
||||
|
||||
snapc = ceph_find_incompatible(page);
|
||||
snapc = ceph_find_incompatible(folio);
|
||||
if (!snapc) {
|
||||
/* success. we'll keep the page locked. */
|
||||
set_page_dirty(page);
|
||||
/* success. we'll keep the folio locked. */
|
||||
folio_mark_dirty(folio);
|
||||
ret = VM_FAULT_LOCKED;
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_page(page);
|
||||
folio_unlock(folio);
|
||||
|
||||
if (IS_ERR(snapc)) {
|
||||
ret = VM_FAULT_SIGBUS;
|
||||
|
||||
@@ -141,17 +141,18 @@ __dcache_find_get_entry(struct dentry *parent, u64 idx,
|
||||
if (ptr_pos >= i_size_read(dir))
|
||||
return NULL;
|
||||
|
||||
if (!cache_ctl->page || ptr_pgoff != cache_ctl->page->index) {
|
||||
if (!cache_ctl->folio || ptr_pgoff != cache_ctl->folio->index) {
|
||||
ceph_readdir_cache_release(cache_ctl);
|
||||
cache_ctl->page = find_lock_page(&dir->i_data, ptr_pgoff);
|
||||
if (!cache_ctl->page) {
|
||||
doutc(cl, " page %lu not found\n", ptr_pgoff);
|
||||
cache_ctl->folio = filemap_lock_folio(&dir->i_data, ptr_pgoff);
|
||||
if (IS_ERR(cache_ctl->folio)) {
|
||||
cache_ctl->folio = NULL;
|
||||
doutc(cl, " folio %lu not found\n", ptr_pgoff);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
/* reading/filling the cache are serialized by
|
||||
i_rwsem, no need to use page lock */
|
||||
unlock_page(cache_ctl->page);
|
||||
cache_ctl->dentries = kmap(cache_ctl->page);
|
||||
i_rwsem, no need to use folio lock */
|
||||
folio_unlock(cache_ctl->folio);
|
||||
cache_ctl->dentries = kmap_local_folio(cache_ctl->folio, 0);
|
||||
}
|
||||
|
||||
cache_ctl->index = idx & idx_mask;
|
||||
|
||||
@@ -1845,10 +1845,9 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req,
|
||||
|
||||
void ceph_readdir_cache_release(struct ceph_readdir_cache_control *ctl)
|
||||
{
|
||||
if (ctl->page) {
|
||||
kunmap(ctl->page);
|
||||
put_page(ctl->page);
|
||||
ctl->page = NULL;
|
||||
if (ctl->folio) {
|
||||
folio_release_kmap(ctl->folio, ctl->dentries);
|
||||
ctl->folio = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1862,20 +1861,23 @@ static int fill_readdir_cache(struct inode *dir, struct dentry *dn,
|
||||
unsigned idx = ctl->index % nsize;
|
||||
pgoff_t pgoff = ctl->index / nsize;
|
||||
|
||||
if (!ctl->page || pgoff != ctl->page->index) {
|
||||
if (!ctl->folio || pgoff != ctl->folio->index) {
|
||||
ceph_readdir_cache_release(ctl);
|
||||
fgf_t fgf = FGP_LOCK;
|
||||
|
||||
if (idx == 0)
|
||||
ctl->page = grab_cache_page(&dir->i_data, pgoff);
|
||||
else
|
||||
ctl->page = find_lock_page(&dir->i_data, pgoff);
|
||||
if (!ctl->page) {
|
||||
fgf |= FGP_ACCESSED | FGP_CREAT;
|
||||
|
||||
ctl->folio = __filemap_get_folio(&dir->i_data, pgoff,
|
||||
fgf, mapping_gfp_mask(&dir->i_data));
|
||||
if (!ctl->folio) {
|
||||
ctl->index = -1;
|
||||
return idx == 0 ? -ENOMEM : 0;
|
||||
}
|
||||
/* reading/filling the cache are serialized by
|
||||
* i_rwsem, no need to use page lock */
|
||||
unlock_page(ctl->page);
|
||||
ctl->dentries = kmap(ctl->page);
|
||||
* i_rwsem, no need to use folio lock */
|
||||
folio_unlock(ctl->folio);
|
||||
ctl->dentries = kmap_local_folio(ctl->folio, 0);
|
||||
if (idx == 0)
|
||||
memset(ctl->dentries, 0, PAGE_SIZE);
|
||||
}
|
||||
|
||||
@@ -903,7 +903,7 @@ ceph_find_rw_context(struct ceph_file_info *cf)
|
||||
}
|
||||
|
||||
struct ceph_readdir_cache_control {
|
||||
struct page *page;
|
||||
struct folio *folio;
|
||||
struct dentry **dentries;
|
||||
int index;
|
||||
};
|
||||
|
||||
@@ -1602,34 +1602,6 @@ static inline ssize_t folio_mkwrite_check_truncate(struct folio *folio,
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* page_mkwrite_check_truncate - check if page was truncated
|
||||
* @page: the page to check
|
||||
* @inode: the inode to check the page against
|
||||
*
|
||||
* Returns the number of bytes in the page up to EOF,
|
||||
* or -EFAULT if the page was truncated.
|
||||
*/
|
||||
static inline int page_mkwrite_check_truncate(struct page *page,
|
||||
struct inode *inode)
|
||||
{
|
||||
loff_t size = i_size_read(inode);
|
||||
pgoff_t index = size >> PAGE_SHIFT;
|
||||
int offset = offset_in_page(size);
|
||||
|
||||
if (page->mapping != inode->i_mapping)
|
||||
return -EFAULT;
|
||||
|
||||
/* page is wholly inside EOF */
|
||||
if (page->index < index)
|
||||
return PAGE_SIZE;
|
||||
/* page is wholly past EOF */
|
||||
if (page->index > index || !offset)
|
||||
return -EFAULT;
|
||||
/* page is partially inside EOF */
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* i_blocks_per_folio - How many blocks fit in this folio.
|
||||
* @inode: The inode which contains the blocks.
|
||||
|
||||
Reference in New Issue
Block a user