net/rds/info.c

Source file repositories/reference/linux-study-clean/net/rds/info.c

File Facts

System
Linux kernel
Corpus path
net/rds/info.c
Extension
.c
Size
7180 bytes
Lines
255
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct rds_info_iterator {
	struct page **pages;
	void *addr;
	unsigned long offset;
};

static DEFINE_SPINLOCK(rds_info_lock);
static rds_info_func rds_info_funcs[RDS_INFO_LAST - RDS_INFO_FIRST + 1];

void rds_info_register_func(int optname, rds_info_func func)
{
	int offset = optname - RDS_INFO_FIRST;

	BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);

	spin_lock(&rds_info_lock);
	BUG_ON(rds_info_funcs[offset]);
	rds_info_funcs[offset] = func;
	spin_unlock(&rds_info_lock);
}
EXPORT_SYMBOL_GPL(rds_info_register_func);

void rds_info_deregister_func(int optname, rds_info_func func)
{
	int offset = optname - RDS_INFO_FIRST;

	BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);

	spin_lock(&rds_info_lock);
	BUG_ON(rds_info_funcs[offset] != func);
	rds_info_funcs[offset] = NULL;
	spin_unlock(&rds_info_lock);
}
EXPORT_SYMBOL_GPL(rds_info_deregister_func);

/*
 * Typically we hold an atomic kmap across multiple rds_info_copy() calls
 * because the kmap is so expensive.  This must be called before using blocking
 * operations while holding the mapping and as the iterator is torn down.
 */
void rds_info_iter_unmap(struct rds_info_iterator *iter)
{
	if (iter->addr) {
		kunmap_atomic(iter->addr);
		iter->addr = NULL;
	}
}

/*
 * get_user_pages() called flush_dcache_page() on the pages for us.
 */
void rds_info_copy(struct rds_info_iterator *iter, void *data,
		   unsigned long bytes)
{
	unsigned long this;

	while (bytes) {
		if (!iter->addr)
			iter->addr = kmap_atomic(*iter->pages);

		this = min(bytes, PAGE_SIZE - iter->offset);

		rdsdebug("page %p addr %p offset %lu this %lu data %p "
			  "bytes %lu\n", *iter->pages, iter->addr,
			  iter->offset, this, data, bytes);

		memcpy(iter->addr + iter->offset, data, this);

		data += this;
		bytes -= this;
		iter->offset += this;

		if (iter->offset == PAGE_SIZE) {
			kunmap_atomic(iter->addr);
			iter->addr = NULL;
			iter->offset = 0;
			iter->pages++;
		}
	}
}
EXPORT_SYMBOL_GPL(rds_info_copy);

/*
 * @opt->iter_out describes the buffer that the information snapshot will be
 * copied into, and @opt->optlen is the size of that buffer on input.  On
 * output @opt->optlen is set to the size of the requested snapshot in bytes.
 *
 * This function returns -errno if there is a failure, particularly -ENOSPC
 * if the given buffer was not large enough to fit the snapshot.  On success
 * it returns the positive number of bytes of each array element in the

Annotation

Implementation Notes