Commit 0f7ddea6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'netfs-folio-20211111' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull netfs, 9p, afs and ceph (partial) foliation from David Howells:
 "This converts netfslib, 9p and afs to use folios. It also partially
  converts ceph so that it uses folios on the boundaries with netfslib.

  To help with this, a couple of folio helper functions are added in the
  first two patches.

  These patches don't touch fscache and cachefiles as I intend to remove
  all the code that deals with pages directly from there. Only nfs and
  cifs are using the old fscache I/O API now. The new API uses iov_iter
  instead.

  Thanks to Jeff Layton, Dominique Martinet and AuriStor for testing and
  retesting the patches"

* tag 'netfs-folio-20211111' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: Use folios in directory handling
  netfs, 9p, afs, ceph: Use folios
  folio: Add a function to get the host inode for a folio
  folio: Add a function to change the private data attached to a folio
parents a9b9669d 255ed636
...@@ -108,7 +108,9 @@ static const struct netfs_read_request_ops v9fs_req_ops = { ...@@ -108,7 +108,9 @@ static const struct netfs_read_request_ops v9fs_req_ops = {
*/ */
static int v9fs_vfs_readpage(struct file *file, struct page *page) static int v9fs_vfs_readpage(struct file *file, struct page *page)
{ {
return netfs_readpage(file, page, &v9fs_req_ops, NULL); struct folio *folio = page_folio(page);
return netfs_readpage(file, folio, &v9fs_req_ops, NULL);
} }
/** /**
...@@ -130,13 +132,15 @@ static void v9fs_vfs_readahead(struct readahead_control *ractl) ...@@ -130,13 +132,15 @@ static void v9fs_vfs_readahead(struct readahead_control *ractl)
static int v9fs_release_page(struct page *page, gfp_t gfp) static int v9fs_release_page(struct page *page, gfp_t gfp)
{ {
if (PagePrivate(page)) struct folio *folio = page_folio(page);
if (folio_test_private(folio))
return 0; return 0;
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
if (PageFsCache(page)) { if (folio_test_fscache(folio)) {
if (!(gfp & __GFP_DIRECT_RECLAIM) || !(gfp & __GFP_FS)) if (!(gfp & __GFP_DIRECT_RECLAIM) || !(gfp & __GFP_FS))
return 0; return 0;
wait_on_page_fscache(page); folio_wait_fscache(folio);
} }
#endif #endif
return 1; return 1;
...@@ -152,55 +156,58 @@ static int v9fs_release_page(struct page *page, gfp_t gfp) ...@@ -152,55 +156,58 @@ static int v9fs_release_page(struct page *page, gfp_t gfp)
static void v9fs_invalidate_page(struct page *page, unsigned int offset, static void v9fs_invalidate_page(struct page *page, unsigned int offset,
unsigned int length) unsigned int length)
{ {
wait_on_page_fscache(page); struct folio *folio = page_folio(page);
folio_wait_fscache(folio);
} }
static int v9fs_vfs_writepage_locked(struct page *page) static int v9fs_vfs_write_folio_locked(struct folio *folio)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = folio_inode(folio);
struct v9fs_inode *v9inode = V9FS_I(inode); struct v9fs_inode *v9inode = V9FS_I(inode);
loff_t start = page_offset(page); loff_t start = folio_pos(folio);
loff_t size = i_size_read(inode); loff_t i_size = i_size_read(inode);
struct iov_iter from; struct iov_iter from;
int err, len; size_t len = folio_size(folio);
int err;
if (start >= i_size)
return 0; /* Simultaneous truncation occurred */
if (page->index == size >> PAGE_SHIFT) len = min_t(loff_t, i_size - start, len);
len = size & ~PAGE_MASK;
else
len = PAGE_SIZE;
iov_iter_xarray(&from, WRITE, &page->mapping->i_pages, start, len); iov_iter_xarray(&from, WRITE, &folio_mapping(folio)->i_pages, start, len);
/* We should have writeback_fid always set */ /* We should have writeback_fid always set */
BUG_ON(!v9inode->writeback_fid); BUG_ON(!v9inode->writeback_fid);
set_page_writeback(page); folio_start_writeback(folio);
p9_client_write(v9inode->writeback_fid, start, &from, &err); p9_client_write(v9inode->writeback_fid, start, &from, &err);
end_page_writeback(page); folio_end_writeback(folio);
return err; return err;
} }
static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc) static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)
{ {
struct folio *folio = page_folio(page);
int retval; int retval;
p9_debug(P9_DEBUG_VFS, "page %p\n", page); p9_debug(P9_DEBUG_VFS, "folio %p\n", folio);
retval = v9fs_vfs_writepage_locked(page); retval = v9fs_vfs_write_folio_locked(folio);
if (retval < 0) { if (retval < 0) {
if (retval == -EAGAIN) { if (retval == -EAGAIN) {
redirty_page_for_writepage(wbc, page); folio_redirty_for_writepage(wbc, folio);
retval = 0; retval = 0;
} else { } else {
SetPageError(page); mapping_set_error(folio_mapping(folio), retval);
mapping_set_error(page->mapping, retval);
} }
} else } else
retval = 0; retval = 0;
unlock_page(page); folio_unlock(folio);
return retval; return retval;
} }
...@@ -213,14 +220,15 @@ static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -213,14 +220,15 @@ static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)
static int v9fs_launder_page(struct page *page) static int v9fs_launder_page(struct page *page)
{ {
struct folio *folio = page_folio(page);
int retval; int retval;
if (clear_page_dirty_for_io(page)) { if (folio_clear_dirty_for_io(folio)) {
retval = v9fs_vfs_writepage_locked(page); retval = v9fs_vfs_write_folio_locked(folio);
if (retval) if (retval)
return retval; return retval;
} }
wait_on_page_fscache(page); folio_wait_fscache(folio);
return 0; return 0;
} }
...@@ -265,10 +273,10 @@ v9fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -265,10 +273,10 @@ v9fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
static int v9fs_write_begin(struct file *filp, struct address_space *mapping, static int v9fs_write_begin(struct file *filp, struct address_space *mapping,
loff_t pos, unsigned int len, unsigned int flags, loff_t pos, unsigned int len, unsigned int flags,
struct page **pagep, void **fsdata) struct page **subpagep, void **fsdata)
{ {
int retval; int retval;
struct page *page; struct folio *folio;
struct v9fs_inode *v9inode = V9FS_I(mapping->host); struct v9fs_inode *v9inode = V9FS_I(mapping->host);
p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping); p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
...@@ -279,31 +287,32 @@ static int v9fs_write_begin(struct file *filp, struct address_space *mapping, ...@@ -279,31 +287,32 @@ static int v9fs_write_begin(struct file *filp, struct address_space *mapping,
* file. We need to do this before we get a lock on the page in case * file. We need to do this before we get a lock on the page in case
* there's more than one writer competing for the same cache block. * there's more than one writer competing for the same cache block.
*/ */
retval = netfs_write_begin(filp, mapping, pos, len, flags, &page, fsdata, retval = netfs_write_begin(filp, mapping, pos, len, flags, &folio, fsdata,
&v9fs_req_ops, NULL); &v9fs_req_ops, NULL);
if (retval < 0) if (retval < 0)
return retval; return retval;
*pagep = find_subpage(page, pos / PAGE_SIZE); *subpagep = &folio->page;
return retval; return retval;
} }
static int v9fs_write_end(struct file *filp, struct address_space *mapping, static int v9fs_write_end(struct file *filp, struct address_space *mapping,
loff_t pos, unsigned int len, unsigned int copied, loff_t pos, unsigned int len, unsigned int copied,
struct page *page, void *fsdata) struct page *subpage, void *fsdata)
{ {
loff_t last_pos = pos + copied; loff_t last_pos = pos + copied;
struct inode *inode = page->mapping->host; struct folio *folio = page_folio(subpage);
struct inode *inode = mapping->host;
p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping); p9_debug(P9_DEBUG_VFS, "filp %p, mapping %p\n", filp, mapping);
if (!PageUptodate(page)) { if (!folio_test_uptodate(folio)) {
if (unlikely(copied < len)) { if (unlikely(copied < len)) {
copied = 0; copied = 0;
goto out; goto out;
} }
SetPageUptodate(page); folio_mark_uptodate(folio);
} }
/* /*
...@@ -314,10 +323,10 @@ static int v9fs_write_end(struct file *filp, struct address_space *mapping, ...@@ -314,10 +323,10 @@ static int v9fs_write_end(struct file *filp, struct address_space *mapping,
inode_add_bytes(inode, last_pos - inode->i_size); inode_add_bytes(inode, last_pos - inode->i_size);
i_size_write(inode, last_pos); i_size_write(inode, last_pos);
} }
set_page_dirty(page); folio_mark_dirty(folio);
out: out:
unlock_page(page); folio_unlock(folio);
put_page(page); folio_put(folio);
return copied; return copied;
} }
......
...@@ -528,13 +528,13 @@ static vm_fault_t ...@@ -528,13 +528,13 @@ static vm_fault_t
v9fs_vm_page_mkwrite(struct vm_fault *vmf) v9fs_vm_page_mkwrite(struct vm_fault *vmf)
{ {
struct v9fs_inode *v9inode; struct v9fs_inode *v9inode;
struct page *page = vmf->page; struct folio *folio = page_folio(vmf->page);
struct file *filp = vmf->vma->vm_file; struct file *filp = vmf->vma->vm_file;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
p9_debug(P9_DEBUG_VFS, "page %p fid %lx\n", p9_debug(P9_DEBUG_VFS, "folio %p fid %lx\n",
page, (unsigned long)filp->private_data); folio, (unsigned long)filp->private_data);
v9inode = V9FS_I(inode); v9inode = V9FS_I(inode);
...@@ -542,24 +542,24 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -542,24 +542,24 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf)
* be modified. We then assume the entire page will need writing back. * be modified. We then assume the entire page will need writing back.
*/ */
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
if (PageFsCache(page) && if (folio_test_fscache(folio) &&
wait_on_page_fscache_killable(page) < 0) folio_wait_fscache_killable(folio) < 0)
return VM_FAULT_RETRY; return VM_FAULT_NOPAGE;
#endif #endif
/* Update file times before taking page lock */ /* Update file times before taking page lock */
file_update_time(filp); file_update_time(filp);
BUG_ON(!v9inode->writeback_fid); BUG_ON(!v9inode->writeback_fid);
if (lock_page_killable(page) < 0) if (folio_lock_killable(folio) < 0)
return VM_FAULT_RETRY; return VM_FAULT_RETRY;
if (page->mapping != inode->i_mapping) if (folio_mapping(folio) != inode->i_mapping)
goto out_unlock; goto out_unlock;
wait_for_stable_page(page); folio_wait_stable(folio);
return VM_FAULT_LOCKED; return VM_FAULT_LOCKED;
out_unlock: out_unlock:
unlock_page(page); folio_unlock(folio);
return VM_FAULT_NOPAGE; return VM_FAULT_NOPAGE;
} }
......
This diff is collapsed.
...@@ -104,6 +104,25 @@ static void afs_clear_contig_bits(union afs_xdr_dir_block *block, ...@@ -104,6 +104,25 @@ static void afs_clear_contig_bits(union afs_xdr_dir_block *block,
block->hdr.bitmap[7] &= ~(u8)(mask >> 7 * 8); block->hdr.bitmap[7] &= ~(u8)(mask >> 7 * 8);
} }
/*
* Get a new directory folio.
*/
static struct folio *afs_dir_get_folio(struct afs_vnode *vnode, pgoff_t index)
{
struct address_space *mapping = vnode->vfs_inode.i_mapping;
struct folio *folio;
folio = __filemap_get_folio(mapping, index,
FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
mapping->gfp_mask);
if (!folio)
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
else if (folio && !folio_test_private(folio))
folio_attach_private(folio, (void *)1);
return folio;
}
/* /*
* Scan a directory block looking for a dirent of the right name. * Scan a directory block looking for a dirent of the right name.
*/ */
...@@ -188,13 +207,11 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -188,13 +207,11 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
enum afs_edit_dir_reason why) enum afs_edit_dir_reason why)
{ {
union afs_xdr_dir_block *meta, *block; union afs_xdr_dir_block *meta, *block;
struct afs_xdr_dir_page *meta_page, *dir_page;
union afs_xdr_dirent *de; union afs_xdr_dirent *de;
struct page *page0, *page; struct folio *folio0, *folio;
unsigned int need_slots, nr_blocks, b; unsigned int need_slots, nr_blocks, b;
pgoff_t index; pgoff_t index;
loff_t i_size; loff_t i_size;
gfp_t gfp;
int slot; int slot;
_enter(",,{%d,%s},", name->len, name->name); _enter(",,{%d,%s},", name->len, name->name);
...@@ -206,10 +223,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -206,10 +223,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
return; return;
} }
gfp = vnode->vfs_inode.i_mapping->gfp_mask; folio0 = afs_dir_get_folio(vnode, 0);
page0 = find_or_create_page(vnode->vfs_inode.i_mapping, 0, gfp); if (!folio0) {
if (!page0) {
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
_leave(" [fgp]"); _leave(" [fgp]");
return; return;
} }
...@@ -217,42 +232,35 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -217,42 +232,35 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
/* Work out how many slots we're going to need. */ /* Work out how many slots we're going to need. */
need_slots = afs_dir_calc_slots(name->len); need_slots = afs_dir_calc_slots(name->len);
meta_page = kmap(page0); meta = kmap_local_folio(folio0, 0);
meta = &meta_page->blocks[0];
if (i_size == 0) if (i_size == 0)
goto new_directory; goto new_directory;
nr_blocks = i_size / AFS_DIR_BLOCK_SIZE; nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
/* Find a block that has sufficient slots available. Each VM page /* Find a block that has sufficient slots available. Each folio
* contains two or more directory blocks. * contains two or more directory blocks.
*/ */
for (b = 0; b < nr_blocks + 1; b++) { for (b = 0; b < nr_blocks + 1; b++) {
/* If the directory extended into a new page, then we need to /* If the directory extended into a new folio, then we need to
* tack a new page on the end. * tack a new folio on the end.
*/ */
index = b / AFS_DIR_BLOCKS_PER_PAGE; index = b / AFS_DIR_BLOCKS_PER_PAGE;
if (index == 0) { if (nr_blocks >= AFS_DIR_MAX_BLOCKS)
page = page0; goto error;
dir_page = meta_page; if (index >= folio_nr_pages(folio0)) {
} else { folio = afs_dir_get_folio(vnode, index);
if (nr_blocks >= AFS_DIR_MAX_BLOCKS) if (!folio)
goto error;
gfp = vnode->vfs_inode.i_mapping->gfp_mask;
page = find_or_create_page(vnode->vfs_inode.i_mapping,
index, gfp);
if (!page)
goto error; goto error;
if (!PagePrivate(page)) } else {
attach_page_private(page, (void *)1); folio = folio0;
dir_page = kmap(page);
} }
block = kmap_local_folio(folio, b * AFS_DIR_BLOCK_SIZE - folio_file_pos(folio));
/* Abandon the edit if we got a callback break. */ /* Abandon the edit if we got a callback break. */
if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
goto invalidated; goto invalidated;
block = &dir_page->blocks[b % AFS_DIR_BLOCKS_PER_PAGE];
_debug("block %u: %2u %3u %u", _debug("block %u: %2u %3u %u",
b, b,
(b < AFS_DIR_BLOCKS_WITH_CTR) ? meta->meta.alloc_ctrs[b] : 99, (b < AFS_DIR_BLOCKS_WITH_CTR) ? meta->meta.alloc_ctrs[b] : 99,
...@@ -266,7 +274,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -266,7 +274,7 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
afs_set_i_size(vnode, (b + 1) * AFS_DIR_BLOCK_SIZE); afs_set_i_size(vnode, (b + 1) * AFS_DIR_BLOCK_SIZE);
} }
/* Only lower dir pages have a counter in the header. */ /* Only lower dir blocks have a counter in the header. */
if (b >= AFS_DIR_BLOCKS_WITH_CTR || if (b >= AFS_DIR_BLOCKS_WITH_CTR ||
meta->meta.alloc_ctrs[b] >= need_slots) { meta->meta.alloc_ctrs[b] >= need_slots) {
/* We need to try and find one or more consecutive /* We need to try and find one or more consecutive
...@@ -279,10 +287,10 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -279,10 +287,10 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
} }
} }
if (page != page0) { kunmap_local(block);
unlock_page(page); if (folio != folio0) {
kunmap(page); folio_unlock(folio);
put_page(page); folio_put(folio);
} }
} }
...@@ -298,8 +306,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -298,8 +306,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
i_size = AFS_DIR_BLOCK_SIZE; i_size = AFS_DIR_BLOCK_SIZE;
afs_set_i_size(vnode, i_size); afs_set_i_size(vnode, i_size);
slot = AFS_DIR_RESV_BLOCKS0; slot = AFS_DIR_RESV_BLOCKS0;
page = page0; folio = folio0;
block = meta; block = kmap_local_folio(folio, 0);
nr_blocks = 1; nr_blocks = 1;
b = 0; b = 0;
...@@ -318,10 +326,10 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -318,10 +326,10 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
/* Adjust the bitmap. */ /* Adjust the bitmap. */
afs_set_contig_bits(block, slot, need_slots); afs_set_contig_bits(block, slot, need_slots);
if (page != page0) { kunmap_local(block);
unlock_page(page); if (folio != folio0) {
kunmap(page); folio_unlock(folio);
put_page(page); folio_put(folio);
} }
/* Adjust the allocation counter. */ /* Adjust the allocation counter. */
...@@ -333,18 +341,19 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -333,18 +341,19 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
_debug("Insert %s in %u[%u]", name->name, b, slot); _debug("Insert %s in %u[%u]", name->name, b, slot);
out_unmap: out_unmap:
unlock_page(page0); kunmap_local(meta);
kunmap(page0); folio_unlock(folio0);
put_page(page0); folio_put(folio0);
_leave(""); _leave("");
return; return;
invalidated: invalidated:
trace_afs_edit_dir(vnode, why, afs_edit_dir_create_inval, 0, 0, 0, 0, name->name); trace_afs_edit_dir(vnode, why, afs_edit_dir_create_inval, 0, 0, 0, 0, name->name);
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
if (page != page0) { kunmap_local(block);
kunmap(page); if (folio != folio0) {
put_page(page); folio_unlock(folio);
folio_put(folio);
} }
goto out_unmap; goto out_unmap;
...@@ -364,10 +373,9 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -364,10 +373,9 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
void afs_edit_dir_remove(struct afs_vnode *vnode, void afs_edit_dir_remove(struct afs_vnode *vnode,
struct qstr *name, enum afs_edit_dir_reason why) struct qstr *name, enum afs_edit_dir_reason why)
{ {
struct afs_xdr_dir_page *meta_page, *dir_page;
union afs_xdr_dir_block *meta, *block; union afs_xdr_dir_block *meta, *block;
union afs_xdr_dirent *de; union afs_xdr_dirent *de;
struct page *page0, *page; struct folio *folio0, *folio;
unsigned int need_slots, nr_blocks, b; unsigned int need_slots, nr_blocks, b;
pgoff_t index; pgoff_t index;
loff_t i_size; loff_t i_size;
...@@ -384,9 +392,8 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, ...@@ -384,9 +392,8 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
} }
nr_blocks = i_size / AFS_DIR_BLOCK_SIZE; nr_blocks = i_size / AFS_DIR_BLOCK_SIZE;
page0 = find_lock_page(vnode->vfs_inode.i_mapping, 0); folio0 = afs_dir_get_folio(vnode, 0);
if (!page0) { if (!folio0) {
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
_leave(" [fgp]"); _leave(" [fgp]");
return; return;
} }
...@@ -394,30 +401,27 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, ...@@ -394,30 +401,27 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
/* Work out how many slots we're going to discard. */ /* Work out how many slots we're going to discard. */
need_slots = afs_dir_calc_slots(name->len); need_slots = afs_dir_calc_slots(name->len);
meta_page = kmap(page0); meta = kmap_local_folio(folio0, 0);
meta = &meta_page->blocks[0];
/* Find a page that has sufficient slots available. Each VM page /* Find a block that has sufficient slots available. Each folio
* contains two or more directory blocks. * contains two or more directory blocks.
*/ */
for (b = 0; b < nr_blocks; b++) { for (b = 0; b < nr_blocks; b++) {
index = b / AFS_DIR_BLOCKS_PER_PAGE; index = b / AFS_DIR_BLOCKS_PER_PAGE;
if (index != 0) { if (index >= folio_nr_pages(folio0)) {
page = find_lock_page(vnode->vfs_inode.i_mapping, index); folio = afs_dir_get_folio(vnode, index);
if (!page) if (!folio)
goto error; goto error;
dir_page = kmap(page);
} else { } else {
page = page0; folio = folio0;
dir_page = meta_page;
} }
block = kmap_local_folio(folio, b * AFS_DIR_BLOCK_SIZE - folio_file_pos(folio));
/* Abandon the edit if we got a callback break. */ /* Abandon the edit if we got a callback break. */
if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags))
goto invalidated; goto invalidated;
block = &dir_page->blocks[b % AFS_DIR_BLOCKS_PER_PAGE];
if (b > AFS_DIR_BLOCKS_WITH_CTR || if (b > AFS_DIR_BLOCKS_WITH_CTR ||
meta->meta.alloc_ctrs[b] <= AFS_DIR_SLOTS_PER_BLOCK - 1 - need_slots) { meta->meta.alloc_ctrs[b] <= AFS_DIR_SLOTS_PER_BLOCK - 1 - need_slots) {
slot = afs_dir_scan_block(block, name, b); slot = afs_dir_scan_block(block, name, b);
...@@ -425,10 +429,10 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, ...@@ -425,10 +429,10 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
goto found_dirent; goto found_dirent;
} }
if (page != page0) { kunmap_local(block);
unlock_page(page); if (folio != folio0) {
kunmap(page); folio_unlock(folio);
put_page(page); folio_put(folio);
} }
} }
...@@ -449,10 +453,10 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, ...@@ -449,10 +453,10 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
/* Adjust the bitmap. */ /* Adjust the bitmap. */
afs_clear_contig_bits(block, slot, need_slots); afs_clear_contig_bits(block, slot, need_slots);
if (page != page0) { kunmap_local(block);
unlock_page(page); if (folio != folio0) {
kunmap(page); folio_unlock(folio);
put_page(page); folio_put(folio);
} }
/* Adjust the allocation counter. */ /* Adjust the allocation counter. */
...@@ -464,9 +468,9 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, ...@@ -464,9 +468,9 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
_debug("Remove %s from %u[%u]", name->name, b, slot); _debug("Remove %s from %u[%u]", name->name, b, slot);
out_unmap: out_unmap:
unlock_page(page0); kunmap_local(meta);
kunmap(page0); folio_unlock(folio0);
put_page(page0); folio_put(folio0);
_leave(""); _leave("");
return; return;
...@@ -474,10 +478,10 @@ void afs_edit_dir_remove(struct afs_vnode *vnode, ...@@ -474,10 +478,10 @@ void afs_edit_dir_remove(struct afs_vnode *vnode,
trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_inval, trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_inval,
0, 0, 0, 0, name->name); 0, 0, 0, 0, name->name);
clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
if (page != page0) { kunmap_local(block);
unlock_page(page); if (folio != folio0) {
kunmap(page); folio_unlock(folio);
put_page(page); folio_put(folio);
} }
goto out_unmap; goto out_unmap;
......
...@@ -324,21 +324,24 @@ static int afs_symlink_readpage(struct file *file, struct page *page) ...@@ -324,21 +324,24 @@ static int afs_symlink_readpage(struct file *file, struct page *page)
{ {
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
struct afs_read *fsreq; struct afs_read *fsreq;
struct folio *folio = page_folio(page);
int ret; int ret;
fsreq = afs_alloc_read(GFP_NOFS); fsreq = afs_alloc_read(GFP_NOFS);
if (!fsreq) if (!fsreq)
return -ENOMEM; return -ENOMEM;
fsreq->pos = page->index * PAGE_SIZE; fsreq->pos = folio_pos(folio);
fsreq->len = PAGE_SIZE; fsreq->len = folio_size(folio);
fsreq->vnode = vnode; fsreq->vnode = vnode;
fsreq->iter = &fsreq->def_iter; fsreq->iter = &fsreq->def_iter;
iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages, iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages,
fsreq->pos, fsreq->len); fsreq->pos, fsreq->len);
ret = afs_fetch_data(fsreq->vnode, fsreq); ret = afs_fetch_data(fsreq->vnode, fsreq);
page_endio(page, false, ret); if (ret == 0)
SetPageUptodate(page);
unlock_page(page);
return ret; return ret;
} }
...@@ -362,7 +365,7 @@ static int afs_begin_cache_operation(struct netfs_read_request *rreq) ...@@ -362,7 +365,7 @@ static int afs_begin_cache_operation(struct netfs_read_request *rreq)
} }
static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len, static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len,
struct page *page, void **_fsdata) struct folio *folio, void **_fsdata)
{ {
struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
...@@ -385,7 +388,9 @@ const struct netfs_read_request_ops afs_req_ops = { ...@@ -385,7 +388,9 @@ const struct netfs_read_request_ops afs_req_ops = {
static int afs_readpage(struct file *file, struct page *page) static int afs_readpage(struct file *file, struct page *page)
{ {
return netfs_readpage(file, page, &afs_req_ops, NULL); struct folio *folio = page_folio(page);
return netfs_readpage(file, folio, &afs_req_ops, NULL);
} }
static void afs_readahead(struct readahead_control *ractl) static void afs_readahead(struct readahead_control *ractl)
...@@ -397,29 +402,29 @@ static void afs_readahead(struct readahead_control *ractl) ...@@ -397,29 +402,29 @@ static void afs_readahead(struct readahead_control *ractl)
* Adjust the dirty region of the page on truncation or full invalidation, * Adjust the dirty region of the page on truncation or full invalidation,
* getting rid of the markers altogether if the region is entirely invalidated. * getting rid of the markers altogether if the region is entirely invalidated.
*/ */
static void afs_invalidate_dirty(struct page *page, unsigned int offset, static void afs_invalidate_dirty(struct folio *folio, unsigned int offset,
unsigned int length) unsigned int length)
{ {
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); struct afs_vnode *vnode = AFS_FS_I(folio_inode(folio));
unsigned long priv; unsigned long priv;
unsigned int f, t, end = offset + length; unsigned int f, t, end = offset + length;
priv = page_private(page); priv = (unsigned long)folio_get_private(folio);
/* we clean up only if the entire page is being invalidated */ /* we clean up only if the entire page is being invalidated */
if (offset == 0 && length == thp_size(page)) if (offset == 0 && length == folio_size(folio))
goto full_invalidate; goto full_invalidate;
/* If the page was dirtied by page_mkwrite(), the PTE stays writable /* If the page was dirtied by page_mkwrite(), the PTE stays writable
* and we don't get another notification to tell us to expand it * and we don't get another notification to tell us to expand it
* again. * again.
*/ */
if (afs_is_page_dirty_mmapped(priv)) if (afs_is_folio_dirty_mmapped(priv))
return; return;
/* We may need to shorten the dirty region */ /* We may need to shorten the dirty region */
f = afs_page_dirty_from(page, priv); f = afs_folio_dirty_from(folio, priv);
t = afs_page_dirty_to(page, priv); t = afs_folio_dirty_to(folio, priv);
if (t <= offset || f >= end) if (t <= offset || f >= end)
return; /* Doesn't overlap */ return; /* Doesn't overlap */
...@@ -437,17 +442,17 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset, ...@@ -437,17 +442,17 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset,
if (f == t) if (f == t)
goto undirty; goto undirty;
priv = afs_page_dirty(page, f, t); priv = afs_folio_dirty(folio, f, t);
set_page_private(page, priv); folio_change_private(folio, (void *)priv);
trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page); trace_afs_folio_dirty(vnode, tracepoint_string("trunc"), folio);
return; return;
undirty: undirty:
trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page); trace_afs_folio_dirty(vnode, tracepoint_string("undirty"), folio);
clear_page_dirty_for_io(page); folio_clear_dirty_for_io(folio);
full_invalidate: full_invalidate:
trace_afs_page_dirty(vnode, tracepoint_string("inval"), page); trace_afs_folio_dirty(vnode, tracepoint_string("inval"), folio);
detach_page_private(page); folio_detach_private(folio);
} }
/* /*
...@@ -458,14 +463,16 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset, ...@@ -458,14 +463,16 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset,
static void afs_invalidatepage(struct page *page, unsigned int offset, static void afs_invalidatepage(struct page *page, unsigned int offset,
unsigned int length) unsigned int length)
{ {
_enter("{%lu},%u,%u", page->index, offset, length); struct folio *folio = page_folio(page);
_enter("{%lu},%u,%u", folio_index(folio), offset, length);
BUG_ON(!PageLocked(page)); BUG_ON(!PageLocked(page));
if (PagePrivate(page)) if (PagePrivate(page))
afs_invalidate_dirty(page, offset, length); afs_invalidate_dirty(folio, offset, length);
wait_on_page_fscache(page); folio_wait_fscache(folio);
_leave(""); _leave("");
} }
...@@ -475,30 +482,31 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, ...@@ -475,30 +482,31 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
*/ */
static int afs_releasepage(struct page *page, gfp_t gfp_flags) static int afs_releasepage(struct page *page, gfp_t gfp_flags)
{ {
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); struct folio *folio = page_folio(page);
struct afs_vnode *vnode = AFS_FS_I(folio_inode(folio));
_enter("{{%llx:%llu}[%lu],%lx},%x", _enter("{{%llx:%llu}[%lu],%lx},%x",
vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, vnode->fid.vid, vnode->fid.vnode, folio_index(folio), folio->flags,
gfp_flags); gfp_flags);
/* deny if page is being written to the cache and the caller hasn't /* deny if page is being written to the cache and the caller hasn't
* elected to wait */ * elected to wait */
#ifdef CONFIG_AFS_FSCACHE #ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page)) { if (folio_test_fscache(folio)) {
if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS)) if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS))
return false; return false;
wait_on_page_fscache(page); folio_wait_fscache(folio);
} }
#endif #endif
if (PagePrivate(page)) { if (folio_test_private(folio)) {
trace_afs_page_dirty(vnode, tracepoint_string("rel"), page); trace_afs_folio_dirty(vnode, tracepoint_string("rel"), folio);
detach_page_private(page); folio_detach_private(folio);
} }
/* indicate that the page can be released */ /* Indicate that the folio can be released */
_leave(" = T"); _leave(" = T");
return 1; return true;
} }
static void afs_add_open_mmap(struct afs_vnode *vnode) static void afs_add_open_mmap(struct afs_vnode *vnode)
......
...@@ -876,59 +876,59 @@ struct afs_vnode_cache_aux { ...@@ -876,59 +876,59 @@ struct afs_vnode_cache_aux {
} __packed; } __packed;
/* /*
* We use page->private to hold the amount of the page that we've written to, * We use folio->private to hold the amount of the folio that we've written to,
* splitting the field into two parts. However, we need to represent a range * splitting the field into two parts. However, we need to represent a range
* 0...PAGE_SIZE, so we reduce the resolution if the size of the page * 0...FOLIO_SIZE, so we reduce the resolution if the size of the folio
* exceeds what we can encode. * exceeds what we can encode.
*/ */
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#define __AFS_PAGE_PRIV_MASK 0x7fffffffUL #define __AFS_FOLIO_PRIV_MASK 0x7fffffffUL
#define __AFS_PAGE_PRIV_SHIFT 32 #define __AFS_FOLIO_PRIV_SHIFT 32
#define __AFS_PAGE_PRIV_MMAPPED 0x80000000UL #define __AFS_FOLIO_PRIV_MMAPPED 0x80000000UL
#else #else
#define __AFS_PAGE_PRIV_MASK 0x7fffUL #define __AFS_FOLIO_PRIV_MASK 0x7fffUL
#define __AFS_PAGE_PRIV_SHIFT 16 #define __AFS_FOLIO_PRIV_SHIFT 16
#define __AFS_PAGE_PRIV_MMAPPED 0x8000UL #define __AFS_FOLIO_PRIV_MMAPPED 0x8000UL
#endif #endif
static inline unsigned int afs_page_dirty_resolution(struct page *page) static inline unsigned int afs_folio_dirty_resolution(struct folio *folio)
{ {
int shift = thp_order(page) + PAGE_SHIFT - (__AFS_PAGE_PRIV_SHIFT - 1); int shift = folio_shift(folio) - (__AFS_FOLIO_PRIV_SHIFT - 1);
return (shift > 0) ? shift : 0; return (shift > 0) ? shift : 0;
} }
static inline size_t afs_page_dirty_from(struct page *page, unsigned long priv) static inline size_t afs_folio_dirty_from(struct folio *folio, unsigned long priv)
{ {
unsigned long x = priv & __AFS_PAGE_PRIV_MASK; unsigned long x = priv & __AFS_FOLIO_PRIV_MASK;
/* The lower bound is inclusive */ /* The lower bound is inclusive */
return x << afs_page_dirty_resolution(page); return x << afs_folio_dirty_resolution(folio);
} }
static inline size_t afs_page_dirty_to(struct page *page, unsigned long priv) static inline size_t afs_folio_dirty_to(struct folio *folio, unsigned long priv)
{ {
unsigned long x = (priv >> __AFS_PAGE_PRIV_SHIFT) & __AFS_PAGE_PRIV_MASK; unsigned long x = (priv >> __AFS_FOLIO_PRIV_SHIFT) & __AFS_FOLIO_PRIV_MASK;
/* The upper bound is immediately beyond the region */ /* The upper bound is immediately beyond the region */
return (x + 1) << afs_page_dirty_resolution(page); return (x + 1) << afs_folio_dirty_resolution(folio);
} }
static inline unsigned long afs_page_dirty(struct page *page, size_t from, size_t to) static inline unsigned long afs_folio_dirty(struct folio *folio, size_t from, size_t to)
{ {
unsigned int res = afs_page_dirty_resolution(page); unsigned int res = afs_folio_dirty_resolution(folio);
from >>= res; from >>= res;
to = (to - 1) >> res; to = (to - 1) >> res;
return (to << __AFS_PAGE_PRIV_SHIFT) | from; return (to << __AFS_FOLIO_PRIV_SHIFT) | from;
} }
static inline unsigned long afs_page_dirty_mmapped(unsigned long priv) static inline unsigned long afs_folio_dirty_mmapped(unsigned long priv)
{ {
return priv | __AFS_PAGE_PRIV_MMAPPED; return priv | __AFS_FOLIO_PRIV_MMAPPED;
} }
static inline bool afs_is_page_dirty_mmapped(unsigned long priv) static inline bool afs_is_folio_dirty_mmapped(unsigned long priv)
{ {
return priv & __AFS_PAGE_PRIV_MMAPPED; return priv & __AFS_FOLIO_PRIV_MMAPPED;
} }
#include <trace/events/afs.h> #include <trace/events/afs.h>
......
This diff is collapsed.
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
(CONGESTION_ON_THRESH(congestion_kb) >> 2)) (CONGESTION_ON_THRESH(congestion_kb) >> 2))
static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len, static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
struct page *page, void **_fsdata); struct folio *folio, void **_fsdata);
static inline struct ceph_snap_context *page_snap_context(struct page *page) static inline struct ceph_snap_context *page_snap_context(struct page *page)
{ {
...@@ -317,13 +317,14 @@ static const struct netfs_read_request_ops ceph_netfs_read_ops = { ...@@ -317,13 +317,14 @@ static const struct netfs_read_request_ops ceph_netfs_read_ops = {
}; };
/* read a single page, without unlocking it. */ /* read a single page, without unlocking it. */
static int ceph_readpage(struct file *file, struct page *page) static int ceph_readpage(struct file *file, struct page *subpage)
{ {
struct folio *folio = page_folio(subpage);
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_vino vino = ceph_vino(inode); struct ceph_vino vino = ceph_vino(inode);
u64 off = page_offset(page); size_t len = folio_size(folio);
u64 len = thp_size(page); u64 off = folio_file_pos(folio);
if (ci->i_inline_version != CEPH_INLINE_NONE) { if (ci->i_inline_version != CEPH_INLINE_NONE) {
/* /*
...@@ -331,19 +332,19 @@ static int ceph_readpage(struct file *file, struct page *page) ...@@ -331,19 +332,19 @@ static int ceph_readpage(struct file *file, struct page *page)
* into page cache while getting Fcr caps. * into page cache while getting Fcr caps.
*/ */
if (off == 0) { if (off == 0) {
unlock_page(page); folio_unlock(folio);
return -EINVAL; return -EINVAL;
} }
zero_user_segment(page, 0, thp_size(page)); zero_user_segment(&folio->page, 0, folio_size(folio));
SetPageUptodate(page); folio_mark_uptodate(folio);
unlock_page(page); folio_unlock(folio);
return 0; return 0;
} }
dout("readpage ino %llx.%llx file %p off %llu len %llu page %p index %lu\n", dout("readpage ino %llx.%llx file %p off %llu len %zu folio %p index %lu\n",
vino.ino, vino.snap, file, off, len, page, page->index); vino.ino, vino.snap, file, off, len, folio, folio_index(folio));
return netfs_readpage(file, page, &ceph_netfs_read_ops, NULL); return netfs_readpage(file, folio, &ceph_netfs_read_ops, NULL);
} }
static void ceph_readahead(struct readahead_control *ractl) static void ceph_readahead(struct readahead_control *ractl)
...@@ -1187,18 +1188,18 @@ ceph_find_incompatible(struct page *page) ...@@ -1187,18 +1188,18 @@ ceph_find_incompatible(struct page *page)
} }
static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len, static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
struct page *page, void **_fsdata) struct folio *folio, void **_fsdata)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_snap_context *snapc; struct ceph_snap_context *snapc;
snapc = ceph_find_incompatible(page); snapc = ceph_find_incompatible(folio_page(folio, 0));
if (snapc) { if (snapc) {
int r; int r;
unlock_page(page); folio_unlock(folio);
put_page(page); folio_put(folio);
if (IS_ERR(snapc)) if (IS_ERR(snapc))
return PTR_ERR(snapc); return PTR_ERR(snapc);
...@@ -1216,12 +1217,12 @@ static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned ...@@ -1216,12 +1217,12 @@ static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned
* clean, or already dirty within the same snap context. * clean, or already dirty within the same snap context.
*/ */
static int ceph_write_begin(struct file *file, struct address_space *mapping, static int ceph_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned aop_flags,
struct page **pagep, void **fsdata) struct page **pagep, void **fsdata)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct page *page = NULL; struct folio *folio = NULL;
pgoff_t index = pos >> PAGE_SHIFT; pgoff_t index = pos >> PAGE_SHIFT;
int r; int r;
...@@ -1230,39 +1231,43 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, ...@@ -1230,39 +1231,43 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
* for inline_version sent to the MDS. * for inline_version sent to the MDS.
*/ */
if (ci->i_inline_version != CEPH_INLINE_NONE) { if (ci->i_inline_version != CEPH_INLINE_NONE) {
page = grab_cache_page_write_begin(mapping, index, flags); unsigned int fgp_flags = FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE;
if (!page) if (aop_flags & AOP_FLAG_NOFS)
fgp_flags |= FGP_NOFS;
folio = __filemap_get_folio(mapping, index, fgp_flags,
mapping_gfp_mask(mapping));
if (!folio)
return -ENOMEM; return -ENOMEM;
/* /*
* The inline_version on a new inode is set to 1. If that's the * The inline_version on a new inode is set to 1. If that's the
* case, then the page is brand new and isn't yet Uptodate. * case, then the folio is brand new and isn't yet Uptodate.
*/ */
r = 0; r = 0;
if (index == 0 && ci->i_inline_version != 1) { if (index == 0 && ci->i_inline_version != 1) {
if (!PageUptodate(page)) { if (!folio_test_uptodate(folio)) {
WARN_ONCE(1, "ceph: write_begin called on still-inlined inode (inline_version %llu)!\n", WARN_ONCE(1, "ceph: write_begin called on still-inlined inode (inline_version %llu)!\n",
ci->i_inline_version); ci->i_inline_version);
r = -EINVAL; r = -EINVAL;
} }
goto out; goto out;
} }
zero_user_segment(page, 0, thp_size(page)); zero_user_segment(&folio->page, 0, folio_size(folio));
SetPageUptodate(page); folio_mark_uptodate(folio);
goto out; goto out;
} }
r = netfs_write_begin(file, inode->i_mapping, pos, len, 0, &page, NULL, r = netfs_write_begin(file, inode->i_mapping, pos, len, 0, &folio, NULL,
&ceph_netfs_read_ops, NULL); &ceph_netfs_read_ops, NULL);
out: out:
if (r == 0) if (r == 0)
wait_on_page_fscache(page); folio_wait_fscache(folio);
if (r < 0) { if (r < 0) {
if (page) if (folio)
put_page(page); folio_put(folio);
} else { } else {
WARN_ON_ONCE(!PageLocked(page)); WARN_ON_ONCE(!folio_test_locked(folio));
*pagep = page; *pagep = &folio->page;
} }
return r; return r;
} }
...@@ -1273,32 +1278,33 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, ...@@ -1273,32 +1278,33 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
*/ */
static int ceph_write_end(struct file *file, struct address_space *mapping, static int ceph_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied, loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata) struct page *subpage, void *fsdata)
{ {
struct folio *folio = page_folio(subpage);
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
bool check_cap = false; bool check_cap = false;
dout("write_end file %p inode %p page %p %d~%d (%d)\n", file, dout("write_end file %p inode %p folio %p %d~%d (%d)\n", file,
inode, page, (int)pos, (int)copied, (int)len); inode, folio, (int)pos, (int)copied, (int)len);
if (!PageUptodate(page)) { if (!folio_test_uptodate(folio)) {
/* just return that nothing was copied on a short copy */ /* just return that nothing was copied on a short copy */
if (copied < len) { if (copied < len) {
copied = 0; copied = 0;
goto out; goto out;
} }
SetPageUptodate(page); folio_mark_uptodate(folio);
} }
/* did file size increase? */ /* did file size increase? */
if (pos+copied > i_size_read(inode)) if (pos+copied > i_size_read(inode))
check_cap = ceph_inode_set_size(inode, pos+copied); check_cap = ceph_inode_set_size(inode, pos+copied);
set_page_dirty(page); folio_mark_dirty(folio);
out: out:
unlock_page(page); folio_unlock(folio);
put_page(page); folio_put(folio);
if (check_cap) if (check_cap)
ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, NULL); ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, NULL);
......
This diff is collapsed.
...@@ -166,13 +166,13 @@ struct netfs_read_request { ...@@ -166,13 +166,13 @@ struct netfs_read_request {
short error; /* 0 or error that occurred */ short error; /* 0 or error that occurred */
loff_t i_size; /* Size of the file */ loff_t i_size; /* Size of the file */
loff_t start; /* Start position */ loff_t start; /* Start position */
pgoff_t no_unlock_page; /* Don't unlock this page after read */ pgoff_t no_unlock_folio; /* Don't unlock this folio after read */
refcount_t usage; refcount_t usage;
unsigned long flags; unsigned long flags;
#define NETFS_RREQ_INCOMPLETE_IO 0 /* Some ioreqs terminated short or with error */ #define NETFS_RREQ_INCOMPLETE_IO 0 /* Some ioreqs terminated short or with error */
#define NETFS_RREQ_WRITE_TO_CACHE 1 /* Need to write to the cache */ #define NETFS_RREQ_WRITE_TO_CACHE 1 /* Need to write to the cache */
#define NETFS_RREQ_NO_UNLOCK_PAGE 2 /* Don't unlock no_unlock_page on completion */ #define NETFS_RREQ_NO_UNLOCK_FOLIO 2 /* Don't unlock no_unlock_folio on completion */
#define NETFS_RREQ_DONT_UNLOCK_PAGES 3 /* Don't unlock the pages on completion */ #define NETFS_RREQ_DONT_UNLOCK_FOLIOS 3 /* Don't unlock the folios on completion */
#define NETFS_RREQ_FAILED 4 /* The request failed */ #define NETFS_RREQ_FAILED 4 /* The request failed */
#define NETFS_RREQ_IN_PROGRESS 5 /* Unlocked when the request completes */ #define NETFS_RREQ_IN_PROGRESS 5 /* Unlocked when the request completes */
const struct netfs_read_request_ops *netfs_ops; const struct netfs_read_request_ops *netfs_ops;
...@@ -190,7 +190,7 @@ struct netfs_read_request_ops { ...@@ -190,7 +190,7 @@ struct netfs_read_request_ops {
void (*issue_op)(struct netfs_read_subrequest *subreq); void (*issue_op)(struct netfs_read_subrequest *subreq);
bool (*is_still_valid)(struct netfs_read_request *rreq); bool (*is_still_valid)(struct netfs_read_request *rreq);
int (*check_write_begin)(struct file *file, loff_t pos, unsigned len, int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
struct page *page, void **_fsdata); struct folio *folio, void **_fsdata);
void (*done)(struct netfs_read_request *rreq); void (*done)(struct netfs_read_request *rreq);
void (*cleanup)(struct address_space *mapping, void *netfs_priv); void (*cleanup)(struct address_space *mapping, void *netfs_priv);
}; };
...@@ -240,11 +240,11 @@ extern void netfs_readahead(struct readahead_control *, ...@@ -240,11 +240,11 @@ extern void netfs_readahead(struct readahead_control *,
const struct netfs_read_request_ops *, const struct netfs_read_request_ops *,
void *); void *);
extern int netfs_readpage(struct file *, extern int netfs_readpage(struct file *,
struct page *, struct folio *,
const struct netfs_read_request_ops *, const struct netfs_read_request_ops *,
void *); void *);
extern int netfs_write_begin(struct file *, struct address_space *, extern int netfs_write_begin(struct file *, struct address_space *,
loff_t, unsigned int, unsigned int, struct page **, loff_t, unsigned int, unsigned int, struct folio **,
void **, void **,
const struct netfs_read_request_ops *, const struct netfs_read_request_ops *,
void *); void *);
......
...@@ -253,6 +253,20 @@ static inline struct address_space *page_mapping_file(struct page *page) ...@@ -253,6 +253,20 @@ static inline struct address_space *page_mapping_file(struct page *page)
return folio_mapping(folio); return folio_mapping(folio);
} }
/**
* folio_inode - Get the host inode for this folio.
* @folio: The folio.
*
* For folios which are in the page cache, return the inode that this folio
* belongs to.
*
* Do not call this for folios which aren't in the page cache.
*/
static inline struct inode *folio_inode(struct folio *folio)
{
return folio->mapping->host;
}
static inline bool page_cache_add_speculative(struct page *page, int count) static inline bool page_cache_add_speculative(struct page *page, int count)
{ {
VM_BUG_ON_PAGE(PageTail(page), page); VM_BUG_ON_PAGE(PageTail(page), page);
...@@ -279,6 +293,25 @@ static inline void folio_attach_private(struct folio *folio, void *data) ...@@ -279,6 +293,25 @@ static inline void folio_attach_private(struct folio *folio, void *data)
folio_set_private(folio); folio_set_private(folio);
} }
/**
* folio_change_private - Change private data on a folio.
* @folio: Folio to change the data on.
* @data: Data to set on the folio.
*
* Change the private data attached to a folio and return the old
* data. The page must previously have had data attached and the data
* must be detached before the folio will be freed.
*
* Return: Data that was previously attached to the folio.
*/
static inline void *folio_change_private(struct folio *folio, void *data)
{
void *old = folio_get_private(folio);
folio->private = data;
return old;
}
/** /**
* folio_detach_private - Detach private data from a folio. * folio_detach_private - Detach private data from a folio.
* @folio: Folio to detach data from. * @folio: Folio to detach data from.
......
...@@ -1016,31 +1016,32 @@ TRACE_EVENT(afs_dir_check_failed, ...@@ -1016,31 +1016,32 @@ TRACE_EVENT(afs_dir_check_failed,
__entry->vnode, __entry->off, __entry->i_size) __entry->vnode, __entry->off, __entry->i_size)
); );
TRACE_EVENT(afs_page_dirty, TRACE_EVENT(afs_folio_dirty,
TP_PROTO(struct afs_vnode *vnode, const char *where, struct page *page), TP_PROTO(struct afs_vnode *vnode, const char *where, struct folio *folio),
TP_ARGS(vnode, where, page), TP_ARGS(vnode, where, folio),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(struct afs_vnode *, vnode ) __field(struct afs_vnode *, vnode )
__field(const char *, where ) __field(const char *, where )
__field(pgoff_t, page ) __field(pgoff_t, index )
__field(unsigned long, from ) __field(unsigned long, from )
__field(unsigned long, to ) __field(unsigned long, to )
), ),
TP_fast_assign( TP_fast_assign(
unsigned long priv = (unsigned long)folio_get_private(folio);
__entry->vnode = vnode; __entry->vnode = vnode;
__entry->where = where; __entry->where = where;
__entry->page = page->index; __entry->index = folio_index(folio);
__entry->from = afs_page_dirty_from(page, page->private); __entry->from = afs_folio_dirty_from(folio, priv);
__entry->to = afs_page_dirty_to(page, page->private); __entry->to = afs_folio_dirty_to(folio, priv);
__entry->to |= (afs_is_page_dirty_mmapped(page->private) ? __entry->to |= (afs_is_folio_dirty_mmapped(priv) ?
(1UL << (BITS_PER_LONG - 1)) : 0); (1UL << (BITS_PER_LONG - 1)) : 0);
), ),
TP_printk("vn=%p %lx %s %lx-%lx%s", TP_printk("vn=%p %lx %s %lx-%lx%s",
__entry->vnode, __entry->page, __entry->where, __entry->vnode, __entry->index, __entry->where,
__entry->from, __entry->from,
__entry->to & ~(1UL << (BITS_PER_LONG - 1)), __entry->to & ~(1UL << (BITS_PER_LONG - 1)),
__entry->to & (1UL << (BITS_PER_LONG - 1)) ? " M" : "") __entry->to & (1UL << (BITS_PER_LONG - 1)) ? " M" : "")
......
...@@ -2967,7 +2967,7 @@ EXPORT_SYMBOL_GPL(folio_wait_writeback_killable); ...@@ -2967,7 +2967,7 @@ EXPORT_SYMBOL_GPL(folio_wait_writeback_killable);
*/ */
void folio_wait_stable(struct folio *folio) void folio_wait_stable(struct folio *folio)
{ {
if (folio->mapping->host->i_sb->s_iflags & SB_I_STABLE_WRITES) if (folio_inode(folio)->i_sb->s_iflags & SB_I_STABLE_WRITES)
folio_wait_writeback(folio); folio_wait_writeback(folio);
} }
EXPORT_SYMBOL_GPL(folio_wait_stable); EXPORT_SYMBOL_GPL(folio_wait_stable);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment