net/rds/ib_ring.c

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

File Facts

System
Linux kernel
Corpus path
net/rds/ib_ring.c
Extension
.c
Size
4915 bytes
Lines
169
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source 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

#include <linux/kernel.h>

#include "rds.h"
#include "ib.h"

/*
 * Locking for IB rings.
 * We assume that allocation is always protected by a mutex
 * in the caller (this is a valid assumption for the current
 * implementation).
 *
 * Freeing always happens in an interrupt, and hence only
 * races with allocations, but not with other free()s.
 *
 * The interaction between allocation and freeing is that
 * the alloc code has to determine the number of free entries.
 * To this end, we maintain two counters; an allocation counter
 * and a free counter. Both are allowed to run freely, and wrap
 * around.
 * The number of used entries is always (alloc_ctr - free_ctr) % NR.
 *
 * The current implementation makes free_ctr atomic. When the
 * caller finds an allocation fails, it should set an "alloc fail"
 * bit and retry the allocation. The "alloc fail" bit essentially tells
 * the CQ completion handlers to wake it up after freeing some
 * more entries.
 */

/*
 * This only happens on shutdown.
 */
DECLARE_WAIT_QUEUE_HEAD(rds_ib_ring_empty_wait);

void rds_ib_ring_init(struct rds_ib_work_ring *ring, u32 nr)
{
	memset(ring, 0, sizeof(*ring));
	ring->w_nr = nr;
	rdsdebug("ring %p nr %u\n", ring, ring->w_nr);
}

static inline u32 __rds_ib_ring_used(struct rds_ib_work_ring *ring)
{
	u32 diff;

	/* This assumes that atomic_t has at least as many bits as u32 */
	diff = ring->w_alloc_ctr - (u32) atomic_read(&ring->w_free_ctr);
	BUG_ON(diff > ring->w_nr);

	return diff;
}

void rds_ib_ring_resize(struct rds_ib_work_ring *ring, u32 nr)
{
	/* We only ever get called from the connection setup code,
	 * prior to creating the QP. */
	BUG_ON(__rds_ib_ring_used(ring));
	ring->w_nr = nr;
}

static int __rds_ib_ring_empty(struct rds_ib_work_ring *ring)
{
	return __rds_ib_ring_used(ring) == 0;
}

u32 rds_ib_ring_alloc(struct rds_ib_work_ring *ring, u32 val, u32 *pos)
{
	u32 ret = 0, avail;

	avail = ring->w_nr - __rds_ib_ring_used(ring);

	rdsdebug("ring %p val %u next %u free %u\n", ring, val,
		 ring->w_alloc_ptr, avail);

	if (val && avail) {
		ret = min(val, avail);
		*pos = ring->w_alloc_ptr;

		ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr;
		ring->w_alloc_ctr += ret;
	}

	return ret;
}

void rds_ib_ring_free(struct rds_ib_work_ring *ring, u32 val)
{
	ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr;
	atomic_add(val, &ring->w_free_ctr);

	if (__rds_ib_ring_empty(ring) &&

Annotation

Implementation Notes