Commit 7d828a06 authored by David Howells's avatar David Howells
Browse files

netfs: Provide tools to create a buffer in an xarray



Provide tools to create a buffer in an xarray, with a function to add new
folios with a mark.  This will be used to create bounce buffer and can be
used more easily to create a list of folios the span of which would require
more than a page's worth of bio_vec structs.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
cc: linux-fsdevel@vger.kernel.org
cc: linux-mm@kvack.org
parent 21d706d5
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -56,6 +56,19 @@ static inline void netfs_proc_add_rreq(struct netfs_io_request *rreq) {}
static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {}
#endif

/*
 * misc.c
 */
#define NETFS_FLAG_PUT_MARK		BIT(0)
#define NETFS_FLAG_PAGECACHE_MARK	BIT(1)
int netfs_xa_store_and_mark(struct xarray *xa, unsigned long index,
			    struct folio *folio, unsigned int flags,
			    gfp_t gfp_mask);
int netfs_add_folios_to_buffer(struct xarray *buffer,
			       struct address_space *mapping,
			       pgoff_t index, pgoff_t to, gfp_t gfp_mask);
void netfs_clear_buffer(struct xarray *buffer);

/*
 * objects.c
 */
+81 −0
Original line number Diff line number Diff line
@@ -8,6 +8,87 @@
#include <linux/swap.h>
#include "internal.h"

/*
 * Attach a folio to the buffer and maybe set marks on it to say that we need
 * to put the folio later and twiddle the pagecache flags.
 */
int netfs_xa_store_and_mark(struct xarray *xa, unsigned long index,
			    struct folio *folio, unsigned int flags,
			    gfp_t gfp_mask)
{
	XA_STATE_ORDER(xas, xa, index, folio_order(folio));

retry:
	xas_lock(&xas);
	for (;;) {
		xas_store(&xas, folio);
		if (!xas_error(&xas))
			break;
		xas_unlock(&xas);
		if (!xas_nomem(&xas, gfp_mask))
			return xas_error(&xas);
		goto retry;
	}

	if (flags & NETFS_FLAG_PUT_MARK)
		xas_set_mark(&xas, NETFS_BUF_PUT_MARK);
	if (flags & NETFS_FLAG_PAGECACHE_MARK)
		xas_set_mark(&xas, NETFS_BUF_PAGECACHE_MARK);
	xas_unlock(&xas);
	return xas_error(&xas);
}

/*
 * Create the specified range of folios in the buffer attached to the read
 * request.  The folios are marked with NETFS_BUF_PUT_MARK so that we know that
 * these need freeing later.
 */
int netfs_add_folios_to_buffer(struct xarray *buffer,
			       struct address_space *mapping,
			       pgoff_t index, pgoff_t to, gfp_t gfp_mask)
{
	struct folio *folio;
	int ret;

	if (to + 1 == index) /* Page range is inclusive */
		return 0;

	do {
		/* TODO: Figure out what order folio can be allocated here */
		folio = filemap_alloc_folio(readahead_gfp_mask(mapping), 0);
		if (!folio)
			return -ENOMEM;
		folio->index = index;
		ret = netfs_xa_store_and_mark(buffer, index, folio,
					      NETFS_FLAG_PUT_MARK, gfp_mask);
		if (ret < 0) {
			folio_put(folio);
			return ret;
		}

		index += folio_nr_pages(folio);
	} while (index <= to && index != 0);

	return 0;
}

/*
 * Clear an xarray buffer, putting a ref on the folios that have
 * NETFS_BUF_PUT_MARK set.
 */
void netfs_clear_buffer(struct xarray *buffer)
{
	struct folio *folio;
	XA_STATE(xas, buffer, 0);

	rcu_read_lock();
	xas_for_each_marked(&xas, folio, ULONG_MAX, NETFS_BUF_PUT_MARK) {
		folio_put(folio);
	}
	rcu_read_unlock();
	xa_destroy(buffer);
}

/**
 * netfs_dirty_folio - Mark folio dirty and pin a cache object for writeback
 * @mapping: The mapping the folio belongs to.
+4 −0
Original line number Diff line number Diff line
@@ -109,6 +109,10 @@ static inline int wait_on_page_fscache_killable(struct page *page)
	return folio_wait_private_2_killable(page_folio(page));
}

/* Marks used on xarray-based buffers */
#define NETFS_BUF_PUT_MARK	XA_MARK_0	/* - Page needs putting  */
#define NETFS_BUF_PAGECACHE_MARK XA_MARK_1	/* - Page needs wb/dirty flag wrangling */

enum netfs_io_source {
	NETFS_FILL_WITH_ZEROES,
	NETFS_DOWNLOAD_FROM_SERVER,