drivers/block/drbd/drbd_receiver.c

Source file repositories/reference/linux-study-clean/drivers/block/drbd/drbd_receiver.c

File Facts

System
Linux kernel
Corpus path
drivers/block/drbd/drbd_receiver.c
Extension
.c
Size
175905 bytes
Lines
5933
Domain
Driver Families
Bucket
drivers/block
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct packet_info {
	enum drbd_packet cmd;
	unsigned int size;
	unsigned int vnr;
	void *data;
};

enum finish_epoch {
	FE_STILL_LIVE,
	FE_DESTROYED,
	FE_RECYCLED,
};

static int drbd_do_features(struct drbd_connection *connection);
static int drbd_do_auth(struct drbd_connection *connection);
static int drbd_disconnected(struct drbd_peer_device *);
static void conn_wait_active_ee_empty(struct drbd_connection *connection);
static enum finish_epoch drbd_may_finish_epoch(struct drbd_connection *, struct drbd_epoch *, enum epoch_event);
static int e_end_block(struct drbd_work *, int);


#define GFP_TRY	(__GFP_HIGHMEM | __GFP_NOWARN)

static struct page *__drbd_alloc_pages(unsigned int number)
{
	struct page *page = NULL;
	struct page *tmp = NULL;
	unsigned int i = 0;

	/* GFP_TRY, because we must not cause arbitrary write-out: in a DRBD
	 * "criss-cross" setup, that might cause write-out on some other DRBD,
	 * which in turn might block on the other node at this very place.  */
	for (i = 0; i < number; i++) {
		tmp = mempool_alloc(&drbd_buffer_page_pool, GFP_TRY);
		if (!tmp)
			goto fail;
		set_page_private(tmp, (unsigned long)page);
		page = tmp;
	}
	return page;
fail:
	page_chain_for_each_safe(page, tmp) {
		set_page_private(page, 0);
		mempool_free(page, &drbd_buffer_page_pool);
	}
	return NULL;
}

/**
 * drbd_alloc_pages() - Returns @number pages, retries forever (or until signalled)
 * @peer_device:	DRBD device.
 * @number:		number of pages requested
 * @retry:		whether to retry, if not enough pages are available right now
 *
 * Tries to allocate number pages, first from our own page pool, then from
 * the kernel.
 * Possibly retry until DRBD frees sufficient pages somewhere else.
 *
 * If this allocation would exceed the max_buffers setting, we throttle
 * allocation (schedule_timeout) to give the system some room to breathe.
 *
 * We do not use max-buffers as hard limit, because it could lead to
 * congestion and further to a distributed deadlock during online-verify or
 * (checksum based) resync, if the max-buffers, socket buffer sizes and
 * resync-rate settings are mis-configured.
 *
 * Returns a page chain linked via page->private.
 */
struct page *drbd_alloc_pages(struct drbd_peer_device *peer_device, unsigned int number,
			      bool retry)
{
	struct drbd_device *device = peer_device->device;
	struct page *page;
	struct net_conf *nc;
	unsigned int mxb;

	rcu_read_lock();
	nc = rcu_dereference(peer_device->connection->net_conf);
	mxb = nc ? nc->max_buffers : 1000000;
	rcu_read_unlock();

	if (atomic_read(&device->pp_in_use) >= mxb)
		schedule_timeout_interruptible(HZ / 10);
	page = __drbd_alloc_pages(number);

	if (page)
		atomic_add(number, &device->pp_in_use);
	return page;
}

Annotation

Implementation Notes