Commit f3d85c9e authored by Byungchul Park's avatar Byungchul Park Committed by Jakub Kicinski
Browse files

netmem: introduce struct netmem_desc mirroring struct page



To simplify struct page, the page pool members of struct page should be
moved to other, allowing these members to be removed from struct page.

Introduce a network memory descriptor to store the members, struct
netmem_desc, and make it union'ed with the existing fields in struct
net_iov, allowing to organize the fields of struct net_iov.

Signed-off-by: default avatarByungchul Park <byungchul@sk.com>
Reviewed-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Reviewed-by: default avatarPavel Begunkov <asml.silence@gmail.com>
Reviewed-by: default avatarMina Almasry <almasrymina@google.com>
Reviewed-by: default avatarVlastimil Babka <vbabka@suse.cz>
Acked-by: default avatarHarry Yoo <harry.yoo@oracle.com>
Link: https://patch.msgid.link/20250721021835.63939-2-byungchul@sk.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 918c675b
Loading
Loading
Loading
Loading
+95 −21
Original line number Diff line number Diff line
@@ -12,6 +12,50 @@
#include <linux/mm.h>
#include <net/net_debug.h>

/* These fields in struct page are used by the page_pool and net stack:
 *
 *        struct {
 *                unsigned long pp_magic;
 *                struct page_pool *pp;
 *                unsigned long _pp_mapping_pad;
 *                unsigned long dma_addr;
 *                atomic_long_t pp_ref_count;
 *        };
 *
 * We mirror the page_pool fields here so the page_pool can access these
 * fields without worrying whether the underlying fields belong to a
 * page or netmem_desc.
 *
 * CAUTION: Do not update the fields in netmem_desc without also
 * updating the anonymous aliasing union in struct net_iov.
 */
struct netmem_desc {
	unsigned long _flags;
	unsigned long pp_magic;
	struct page_pool *pp;
	unsigned long _pp_mapping_pad;
	unsigned long dma_addr;
	atomic_long_t pp_ref_count;
};

#define NETMEM_DESC_ASSERT_OFFSET(pg, desc)        \
	static_assert(offsetof(struct page, pg) == \
		      offsetof(struct netmem_desc, desc))
NETMEM_DESC_ASSERT_OFFSET(flags, _flags);
NETMEM_DESC_ASSERT_OFFSET(pp_magic, pp_magic);
NETMEM_DESC_ASSERT_OFFSET(pp, pp);
NETMEM_DESC_ASSERT_OFFSET(_pp_mapping_pad, _pp_mapping_pad);
NETMEM_DESC_ASSERT_OFFSET(dma_addr, dma_addr);
NETMEM_DESC_ASSERT_OFFSET(pp_ref_count, pp_ref_count);
#undef NETMEM_DESC_ASSERT_OFFSET

/*
 * Since struct netmem_desc uses the space in struct page, the size
 * should be checked, until struct netmem_desc has its own instance from
 * slab, to avoid conflicting with other members within struct page.
 */
static_assert(sizeof(struct netmem_desc) <= offsetof(struct page, _refcount));

/* net_iov */

DECLARE_STATIC_KEY_FALSE(page_pool_mem_providers);
@@ -30,14 +74,49 @@ enum net_iov_type {
	NET_IOV_MAX = ULONG_MAX
};

/* A memory descriptor representing abstract networking I/O vectors,
 * generally for non-pages memory that doesn't have its corresponding
 * struct page and needs to be explicitly allocated through slab.
 *
 * net_iovs are allocated and used by networking code, and the size of
 * the chunk is PAGE_SIZE.
 *
 * This memory can be any form of non-struct paged memory.  Examples
 * include imported dmabuf memory and imported io_uring memory.  See
 * net_iov_type for all the supported types.
 *
 * @pp_magic:	pp field, similar to the one in struct page/struct
 *		netmem_desc.
 * @pp:		the pp this net_iov belongs to, if any.
 * @dma_addr:	the dma addrs of the net_iov. Needed for the network
 *		card to send/receive this net_iov.
 * @pp_ref_count: the pp ref count of this net_iov, exactly the same
 *		usage as struct page/struct netmem_desc.
 * @owner:	the net_iov_area this net_iov belongs to, if any.
 * @type:	the type of the memory.  Different types of net_iovs are
 *		supported.
 */
struct net_iov {
	enum net_iov_type type;
	union {
		struct netmem_desc desc;

		/* XXX: The following part should be removed once all
		 * the references to them are converted so as to be
		 * accessed via netmem_desc e.g. niov->desc.pp instead
		 * of niov->pp.
		 */
		struct {
			unsigned long _flags;
			unsigned long pp_magic;
			struct page_pool *pp;
	struct net_iov_area *owner;
			unsigned long _pp_mapping_pad;
			unsigned long dma_addr;
			atomic_long_t pp_ref_count;
		};
	};
	struct net_iov_area *owner;
	enum net_iov_type type;
};

struct net_iov_area {
	/* Array of net_iovs for this area. */
@@ -48,27 +127,22 @@ struct net_iov_area {
	unsigned long base_virtual;
};

/* These fields in struct page are used by the page_pool and net stack:
/* net_iov is union'ed with struct netmem_desc mirroring struct page, so
 * the page_pool can access these fields without worrying whether the
 * underlying fields are accessed via netmem_desc or directly via
 * net_iov, until all the references to them are converted so as to be
 * accessed via netmem_desc e.g. niov->desc.pp instead of niov->pp.
 *
 *        struct {
 *                unsigned long pp_magic;
 *                struct page_pool *pp;
 *                unsigned long _pp_mapping_pad;
 *                unsigned long dma_addr;
 *                atomic_long_t pp_ref_count;
 *        };
 *
 * We mirror the page_pool fields here so the page_pool can access these fields
 * without worrying whether the underlying fields belong to a page or net_iov.
 *
 * The non-net stack fields of struct page are private to the mm stack and must
 * never be mirrored to net_iov.
 * The non-net stack fields of struct page are private to the mm stack
 * and must never be mirrored to net_iov.
 */
#define NET_IOV_ASSERT_OFFSET(pg, iov)             \
	static_assert(offsetof(struct page, pg) == \
#define NET_IOV_ASSERT_OFFSET(desc, iov)                    \
	static_assert(offsetof(struct netmem_desc, desc) == \
		      offsetof(struct net_iov, iov))
NET_IOV_ASSERT_OFFSET(_flags, _flags);
NET_IOV_ASSERT_OFFSET(pp_magic, pp_magic);
NET_IOV_ASSERT_OFFSET(pp, pp);
NET_IOV_ASSERT_OFFSET(_pp_mapping_pad, _pp_mapping_pad);
NET_IOV_ASSERT_OFFSET(dma_addr, dma_addr);
NET_IOV_ASSERT_OFFSET(pp_ref_count, pp_ref_count);
#undef NET_IOV_ASSERT_OFFSET