Commit 0f7ddea6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+46 −37
Original line number Diff line number Diff line
@@ -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)
{
	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)

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;
#ifdef CONFIG_9P_FSCACHE
	if (PageFsCache(page)) {
	if (folio_test_fscache(folio)) {
		if (!(gfp & __GFP_DIRECT_RECLAIM) || !(gfp & __GFP_FS))
			return 0;
		wait_on_page_fscache(page);
		folio_wait_fscache(folio);
	}
#endif
	return 1;
@@ -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,
				 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);
	loff_t start = page_offset(page);
	loff_t size = i_size_read(inode);
	loff_t start = folio_pos(folio);
	loff_t i_size = i_size_read(inode);
	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 = size & ~PAGE_MASK;
	else
		len = PAGE_SIZE;
	len = min_t(loff_t, i_size - start, len);

	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 */
	BUG_ON(!v9inode->writeback_fid);

	set_page_writeback(page);
	folio_start_writeback(folio);

	p9_client_write(v9inode->writeback_fid, start, &from, &err);

	end_page_writeback(page);
	folio_end_writeback(folio);
	return err;
}

static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)
{
	struct folio *folio = page_folio(page);
	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 == -EAGAIN) {
			redirty_page_for_writepage(wbc, page);
			folio_redirty_for_writepage(wbc, folio);
			retval = 0;
		} else {
			SetPageError(page);
			mapping_set_error(page->mapping, retval);
			mapping_set_error(folio_mapping(folio), retval);
		}
	} else
		retval = 0;

	unlock_page(page);
	folio_unlock(folio);
	return retval;
}

@@ -213,14 +220,15 @@ static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc)

static int v9fs_launder_page(struct page *page)
{
	struct folio *folio = page_folio(page);
	int retval;

	if (clear_page_dirty_for_io(page)) {
		retval = v9fs_vfs_writepage_locked(page);
	if (folio_clear_dirty_for_io(folio)) {
		retval = v9fs_vfs_write_folio_locked(folio);
		if (retval)
			return retval;
	}
	wait_on_page_fscache(page);
	folio_wait_fscache(folio);
	return 0;
}

@@ -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,
			    loff_t pos, unsigned int len, unsigned int flags,
			    struct page **pagep, void **fsdata)
			    struct page **subpagep, void **fsdata)
{
	int retval;
	struct page *page;
	struct folio *folio;
	struct v9fs_inode *v9inode = V9FS_I(mapping->host);

	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,
	 * 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.
	 */
	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);
	if (retval < 0)
		return retval;

	*pagep = find_subpage(page, pos / PAGE_SIZE);
	*subpagep = &folio->page;
	return retval;
}

static int v9fs_write_end(struct file *filp, struct address_space *mapping,
			  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;
	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);

	if (!PageUptodate(page)) {
	if (!folio_test_uptodate(folio)) {
		if (unlikely(copied < len)) {
			copied = 0;
			goto out;
		}

		SetPageUptodate(page);
		folio_mark_uptodate(folio);
	}

	/*
@@ -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);
		i_size_write(inode, last_pos);
	}
	set_page_dirty(page);
	folio_mark_dirty(folio);
out:
	unlock_page(page);
	put_page(page);
	folio_unlock(folio);
	folio_put(folio);

	return copied;
}
+10 −10
Original line number Diff line number Diff line
@@ -528,13 +528,13 @@ static vm_fault_t
v9fs_vm_page_mkwrite(struct vm_fault *vmf)
{
	struct v9fs_inode *v9inode;
	struct page *page = vmf->page;
	struct folio *folio = page_folio(vmf->page);
	struct file *filp = vmf->vma->vm_file;
	struct inode *inode = file_inode(filp);


	p9_debug(P9_DEBUG_VFS, "page %p fid %lx\n",
		 page, (unsigned long)filp->private_data);
	p9_debug(P9_DEBUG_VFS, "folio %p fid %lx\n",
		 folio, (unsigned long)filp->private_data);

	v9inode = V9FS_I(inode);

@@ -542,24 +542,24 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf)
	 * be modified.  We then assume the entire page will need writing back.
	 */
#ifdef CONFIG_9P_FSCACHE
	if (PageFsCache(page) &&
	    wait_on_page_fscache_killable(page) < 0)
		return VM_FAULT_RETRY;
	if (folio_test_fscache(folio) &&
	    folio_wait_fscache_killable(folio) < 0)
		return VM_FAULT_NOPAGE;
#endif

	/* Update file times before taking page lock */
	file_update_time(filp);

	BUG_ON(!v9inode->writeback_fid);
	if (lock_page_killable(page) < 0)
	if (folio_lock_killable(folio) < 0)
		return VM_FAULT_RETRY;
	if (page->mapping != inode->i_mapping)
	if (folio_mapping(folio) != inode->i_mapping)
		goto out_unlock;
	wait_for_stable_page(page);
	folio_wait_stable(folio);

	return VM_FAULT_LOCKED;
out_unlock:
	unlock_page(page);
	folio_unlock(folio);
	return VM_FAULT_NOPAGE;
}

+95 −134
Original line number Diff line number Diff line
@@ -103,13 +103,13 @@ struct afs_lookup_cookie {
};

/*
 * Drop the refs that we're holding on the pages we were reading into.  We've
 * Drop the refs that we're holding on the folios we were reading into.  We've
 * got refs on the first nr_pages pages.
 */
static void afs_dir_read_cleanup(struct afs_read *req)
{
	struct address_space *mapping = req->vnode->vfs_inode.i_mapping;
	struct page *page;
	struct folio *folio;
	pgoff_t last = req->nr_pages - 1;

	XA_STATE(xas, &mapping->i_pages, 0);
@@ -118,65 +118,56 @@ static void afs_dir_read_cleanup(struct afs_read *req)
		return;

	rcu_read_lock();
	xas_for_each(&xas, page, last) {
		if (xas_retry(&xas, page))
	xas_for_each(&xas, folio, last) {
		if (xas_retry(&xas, folio))
			continue;
		BUG_ON(xa_is_value(page));
		BUG_ON(PageCompound(page));
		ASSERTCMP(page->mapping, ==, mapping);
		BUG_ON(xa_is_value(folio));
		ASSERTCMP(folio_file_mapping(folio), ==, mapping);

		put_page(page);
		folio_put(folio);
	}

	rcu_read_unlock();
}

/*
 * check that a directory page is valid
 * check that a directory folio is valid
 */
static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
static bool afs_dir_check_folio(struct afs_vnode *dvnode, struct folio *folio,
				loff_t i_size)
{
	struct afs_xdr_dir_page *dbuf;
	loff_t latter, off;
	int tmp, qty;
	union afs_xdr_dir_block *block;
	size_t offset, size;
	loff_t pos;

	/* Determine how many magic numbers there should be in this page, but
	/* Determine how many magic numbers there should be in this folio, but
	 * we must take care because the directory may change size under us.
	 */
	off = page_offset(page);
	if (i_size <= off)
	pos = folio_pos(folio);
	if (i_size <= pos)
		goto checked;

	latter = i_size - off;
	if (latter >= PAGE_SIZE)
		qty = PAGE_SIZE;
	else
		qty = latter;
	qty /= sizeof(union afs_xdr_dir_block);

	/* check them */
	dbuf = kmap_atomic(page);
	for (tmp = 0; tmp < qty; tmp++) {
		if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) {
			printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n",
			       __func__, dvnode->vfs_inode.i_ino, tmp, qty,
			       ntohs(dbuf->blocks[tmp].hdr.magic));
			trace_afs_dir_check_failed(dvnode, off, i_size);
			kunmap(page);
	size = min_t(loff_t, folio_size(folio), i_size - pos);
	for (offset = 0; offset < size; offset += sizeof(*block)) {
		block = kmap_local_folio(folio, offset);
		if (block->hdr.magic != AFS_DIR_MAGIC) {
			printk("kAFS: %s(%lx): [%llx] bad magic %zx/%zx is %04hx\n",
			       __func__, dvnode->vfs_inode.i_ino,
			       pos, offset, size, ntohs(block->hdr.magic));
			trace_afs_dir_check_failed(dvnode, pos + offset, i_size);
			kunmap_local(block);
			trace_afs_file_error(dvnode, -EIO, afs_file_error_dir_bad_magic);
			goto error;
		}

		/* Make sure each block is NUL terminated so we can reasonably
		 * use string functions on it.  The filenames in the page
		 * use string functions on it.  The filenames in the folio
		 * *should* be NUL-terminated anyway.
		 */
		((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0;
	}

	kunmap_atomic(dbuf);
		((u8 *)block)[AFS_DIR_BLOCK_SIZE - 1] = 0;

		kunmap_local(block);
	}
checked:
	afs_stat_v(dvnode, n_read_dir);
	return true;
@@ -190,11 +181,11 @@ static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
 */
static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req)
{
	struct afs_xdr_dir_page *dbuf;
	union afs_xdr_dir_block *block;
	struct address_space *mapping = dvnode->vfs_inode.i_mapping;
	struct page *page;
	unsigned int i, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block);
	struct folio *folio;
	pgoff_t last = req->nr_pages - 1;
	size_t offset, size;

	XA_STATE(xas, &mapping->i_pages, 0);

@@ -205,30 +196,28 @@ static void afs_dir_dump(struct afs_vnode *dvnode, struct afs_read *req)
		req->pos, req->nr_pages,
		req->iter->iov_offset,  iov_iter_count(req->iter));

	xas_for_each(&xas, page, last) {
		if (xas_retry(&xas, page))
	xas_for_each(&xas, folio, last) {
		if (xas_retry(&xas, folio))
			continue;

		BUG_ON(PageCompound(page));
		BUG_ON(page->mapping != mapping);

		dbuf = kmap_atomic(page);
		for (i = 0; i < qty; i++) {
			union afs_xdr_dir_block *block = &dbuf->blocks[i];
		BUG_ON(folio_file_mapping(folio) != mapping);

			pr_warn("[%02lx] %32phN\n", page->index * qty + i, block);
		size = min_t(loff_t, folio_size(folio), req->actual_len - folio_pos(folio));
		for (offset = 0; offset < size; offset += sizeof(*block)) {
			block = kmap_local_folio(folio, offset);
			pr_warn("[%02lx] %32phN\n", folio_index(folio) + offset, block);
			kunmap_local(block);
		}
		kunmap_atomic(dbuf);
	}
}

/*
 * Check all the pages in a directory.  All the pages are held pinned.
 * Check all the blocks in a directory.  All the folios are held pinned.
 */
static int afs_dir_check(struct afs_vnode *dvnode, struct afs_read *req)
{
	struct address_space *mapping = dvnode->vfs_inode.i_mapping;
	struct page *page;
	struct folio *folio;
	pgoff_t last = req->nr_pages - 1;
	int ret = 0;

@@ -238,14 +227,13 @@ static int afs_dir_check(struct afs_vnode *dvnode, struct afs_read *req)
		return 0;

	rcu_read_lock();
	xas_for_each(&xas, page, last) {
		if (xas_retry(&xas, page))
	xas_for_each(&xas, folio, last) {
		if (xas_retry(&xas, folio))
			continue;

		BUG_ON(PageCompound(page));
		BUG_ON(page->mapping != mapping);
		BUG_ON(folio_file_mapping(folio) != mapping);

		if (!afs_dir_check_page(dvnode, page, req->file_size)) {
		if (!afs_dir_check_folio(dvnode, folio, req->actual_len)) {
			afs_dir_dump(dvnode, req);
			ret = -EIO;
			break;
@@ -274,15 +262,16 @@ static int afs_dir_open(struct inode *inode, struct file *file)

/*
 * Read the directory into the pagecache in one go, scrubbing the previous
 * contents.  The list of pages is returned, pinning them so that they don't
 * contents.  The list of folios is returned, pinning them so that they don't
 * get reclaimed during the iteration.
 */
static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
	__acquires(&dvnode->validate_lock)
{
	struct address_space *mapping = dvnode->vfs_inode.i_mapping;
	struct afs_read *req;
	loff_t i_size;
	int nr_pages, i, n;
	int nr_pages, i;
	int ret;

	_enter("");
@@ -320,43 +309,30 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
	req->iter = &req->def_iter;

	/* Fill in any gaps that we might find where the memory reclaimer has
	 * been at work and pin all the pages.  If there are any gaps, we will
	 * been at work and pin all the folios.  If there are any gaps, we will
	 * need to reread the entire directory contents.
	 */
	i = req->nr_pages;
	while (i < nr_pages) {
		struct page *pages[8], *page;

		n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i,
					  min_t(unsigned int, nr_pages - i,
						ARRAY_SIZE(pages)),
					  pages);
		_debug("find %u at %u/%u", n, i, nr_pages);

		if (n == 0) {
			gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask;
		struct folio *folio;

		folio = filemap_get_folio(mapping, i);
		if (!folio) {
			if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
				afs_stat_v(dvnode, n_inval);

			ret = -ENOMEM;
			page = __page_cache_alloc(gfp);
			if (!page)
			folio = __filemap_get_folio(mapping,
						    i, FGP_LOCK | FGP_CREAT,
						    mapping->gfp_mask);
			if (!folio)
				goto error;
			ret = add_to_page_cache_lru(page,
						    dvnode->vfs_inode.i_mapping,
						    i, gfp);
			if (ret < 0)
				goto error;

			attach_page_private(page, (void *)1);
			unlock_page(page);
			req->nr_pages++;
			i++;
		} else {
			req->nr_pages += n;
			i += n;
			folio_attach_private(folio, (void *)1);
			folio_unlock(folio);
		}

		req->nr_pages += folio_nr_pages(folio);
		i += folio_nr_pages(folio);
	}

	/* If we're going to reload, we need to lock all the pages to prevent
@@ -424,7 +400,7 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode,
	size_t nlen;
	int tmp;

	_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);
	_enter("%llx,%x", ctx->pos, blkoff);

	curr = (ctx->pos - blkoff) / sizeof(union afs_xdr_dirent);

@@ -513,12 +489,10 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
			   struct key *key, afs_dataversion_t *_dir_version)
{
	struct afs_vnode *dvnode = AFS_FS_I(dir);
	struct afs_xdr_dir_page *dbuf;
	union afs_xdr_dir_block *dblock;
	struct afs_read *req;
	struct page *page;
	unsigned blkoff, limit;
	void __rcu **slot;
	struct folio *folio;
	unsigned offset, size;
	int ret;

	_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
@@ -540,43 +514,30 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
	/* walk through the blocks in sequence */
	ret = 0;
	while (ctx->pos < req->actual_len) {
		blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1);

		/* Fetch the appropriate page from the directory and re-add it
		/* Fetch the appropriate folio from the directory and re-add it
		 * to the LRU.  We have all the pages pinned with an extra ref.
		 */
		rcu_read_lock();
		page = NULL;
		slot = radix_tree_lookup_slot(&dvnode->vfs_inode.i_mapping->i_pages,
					      blkoff / PAGE_SIZE);
		if (slot)
			page = radix_tree_deref_slot(slot);
		rcu_read_unlock();
		if (!page) {
		folio = __filemap_get_folio(dir->i_mapping, ctx->pos / PAGE_SIZE,
					    FGP_ACCESSED, 0);
		if (!folio) {
			ret = afs_bad(dvnode, afs_file_error_dir_missing_page);
			break;
		}
		mark_page_accessed(page);

		limit = blkoff & ~(PAGE_SIZE - 1);

		dbuf = kmap(page);
		offset = round_down(ctx->pos, sizeof(*dblock)) - folio_file_pos(folio);
		size = min_t(loff_t, folio_size(folio),
			     req->actual_len - folio_file_pos(folio));

		/* deal with the individual blocks stashed on this page */
		do {
			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
					       sizeof(union afs_xdr_dir_block)];
			ret = afs_dir_iterate_block(dvnode, ctx, dblock, blkoff);
			if (ret != 1) {
				kunmap(page);
			dblock = kmap_local_folio(folio, offset);
			ret = afs_dir_iterate_block(dvnode, ctx, dblock,
						    folio_file_pos(folio) + offset);
			kunmap_local(dblock);
			if (ret != 1)
				goto out;
			}

			blkoff += sizeof(union afs_xdr_dir_block);

		} while (ctx->pos < dir->i_size && blkoff < limit);
		} while (offset += sizeof(*dblock), offset < size);

		kunmap(page);
		ret = 0;
	}

@@ -2037,42 +1998,42 @@ static int afs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
}

/*
 * Release a directory page and clean up its private state if it's not busy
 * - return true if the page can now be released, false if not
 * Release a directory folio and clean up its private state if it's not busy
 * - return true if the folio can now be released, false if not
 */
static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags)
static int afs_dir_releasepage(struct page *subpage, gfp_t gfp_flags)
{
	struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
	struct folio *folio = page_folio(subpage);
	struct afs_vnode *dvnode = AFS_FS_I(folio_inode(folio));

	_enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index);
	_enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, folio_index(folio));

	detach_page_private(page);
	folio_detach_private(folio);

	/* The directory will need reloading. */
	if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
		afs_stat_v(dvnode, n_relpg);
	return 1;
	return true;
}

/*
 * invalidate part or all of a page
 * - release a page and clean up its private data if offset is 0 (indicating
 *   the entire page)
 * Invalidate part or all of a folio.
 */
static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
static void afs_dir_invalidatepage(struct page *subpage, unsigned int offset,
				   unsigned int length)
{
	struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
	struct folio *folio = page_folio(subpage);
	struct afs_vnode *dvnode = AFS_FS_I(folio_inode(folio));

	_enter("{%lu},%u,%u", page->index, offset, length);
	_enter("{%lu},%u,%u", folio_index(folio), offset, length);

	BUG_ON(!PageLocked(page));
	BUG_ON(!folio_test_locked(folio));

	/* The directory will need reloading. */
	if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
		afs_stat_v(dvnode, n_inval);

	/* we clean up only if the entire page is being invalidated */
	if (offset == 0 && length == thp_size(page))
		detach_page_private(page);
	/* we clean up only if the entire folio is being invalidated */
	if (offset == 0 && length == folio_size(folio))
		folio_detach_private(folio);
}
+79 −75

File changed.

Preview size limit exceeded, changes collapsed.

+39 −31
Original line number Diff line number Diff line
@@ -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_read *fsreq;
	struct folio *folio = page_folio(page);
	int ret;

	fsreq = afs_alloc_read(GFP_NOFS);
	if (!fsreq)
		return -ENOMEM;

	fsreq->pos	= page->index * PAGE_SIZE;
	fsreq->len	= PAGE_SIZE;
	fsreq->pos	= folio_pos(folio);
	fsreq->len	= folio_size(folio);
	fsreq->vnode	= vnode;
	fsreq->iter	= &fsreq->def_iter;
	iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages,
			fsreq->pos, fsreq->len);

	ret = afs_fetch_data(fsreq->vnode, fsreq);
	page_endio(page, false, ret);
	if (ret == 0)
		SetPageUptodate(page);
	unlock_page(page);
	return ret;
}

@@ -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,
				 struct page *page, void **_fsdata)
				 struct folio *folio, void **_fsdata)
{
	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));

@@ -385,7 +388,9 @@ const struct netfs_read_request_ops afs_req_ops = {

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)
@@ -397,29 +402,29 @@ static void afs_readahead(struct readahead_control *ractl)
 * Adjust the dirty region of the page on truncation or full invalidation,
 * 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)
{
	struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
	struct afs_vnode *vnode = AFS_FS_I(folio_inode(folio));
	unsigned long priv;
	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 */
	if (offset == 0 && length == thp_size(page))
	if (offset == 0 && length == folio_size(folio))
		goto full_invalidate;

	 /* 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
	  * again.
	  */
	if (afs_is_page_dirty_mmapped(priv))
	if (afs_is_folio_dirty_mmapped(priv))
		return;

	/* We may need to shorten the dirty region */
	f = afs_page_dirty_from(page, priv);
	t = afs_page_dirty_to(page, priv);
	f = afs_folio_dirty_from(folio, priv);
	t = afs_folio_dirty_to(folio, priv);

	if (t <= offset || f >= end)
		return; /* Doesn't overlap */
@@ -437,17 +442,17 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset,
	if (f == t)
		goto undirty;

	priv = afs_page_dirty(page, f, t);
	set_page_private(page, priv);
	trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page);
	priv = afs_folio_dirty(folio, f, t);
	folio_change_private(folio, (void *)priv);
	trace_afs_folio_dirty(vnode, tracepoint_string("trunc"), folio);
	return;

undirty:
	trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page);
	clear_page_dirty_for_io(page);
	trace_afs_folio_dirty(vnode, tracepoint_string("undirty"), folio);
	folio_clear_dirty_for_io(folio);
full_invalidate:
	trace_afs_page_dirty(vnode, tracepoint_string("inval"), page);
	detach_page_private(page);
	trace_afs_folio_dirty(vnode, tracepoint_string("inval"), folio);
	folio_detach_private(folio);
}

/*
@@ -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,
			       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));

	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("");
}

@@ -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)
{
	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",
	       vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
	       vnode->fid.vid, vnode->fid.vnode, folio_index(folio), folio->flags,
	       gfp_flags);

	/* deny if page is being written to the cache and the caller hasn't
	 * elected to wait */
#ifdef CONFIG_AFS_FSCACHE
	if (PageFsCache(page)) {
	if (folio_test_fscache(folio)) {
		if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS))
			return false;
		wait_on_page_fscache(page);
		folio_wait_fscache(folio);
	}
#endif

	if (PagePrivate(page)) {
		trace_afs_page_dirty(vnode, tracepoint_string("rel"), page);
		detach_page_private(page);
	if (folio_test_private(folio)) {
		trace_afs_folio_dirty(vnode, tracepoint_string("rel"), folio);
		folio_detach_private(folio);
	}

	/* indicate that the page can be released */
	/* Indicate that the folio can be released */
	_leave(" = T");
	return 1;
	return true;
}

static void afs_add_open_mmap(struct afs_vnode *vnode)
Loading