Commit 5e472264 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Philipp Reisner
Browse files

drbd: _req_conflicts(): Get rid of the epoch_entries tree



Instead of keeping a separate tree for local and remote write requests
for finding requests and for conflict detection, use the same tree for
both purposes.  Introduce a flag to allow distinguishing the two
possible types of entries in this tree.

Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 53840641
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -1045,9 +1045,6 @@ struct drbd_conf {
	struct list_head read_ee;   /* IO in progress (any read) */
	struct list_head net_ee;    /* zero-copy network send in progress */

	/* Interval tree of pending remote write requests (struct drbd_epoch_entry) */
	struct rb_root epoch_entries;

	/* this one is protected by ee_lock, single thread */
	struct drbd_epoch_entry *last_write_w_barrier;

+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ struct drbd_interval {
	sector_t sector;	/* start sector of the interval */
	unsigned int size;	/* size in bytes */
	sector_t end;		/* highest interval end in subtree */
	int local:1		/* local or remote request? */;
	int waiting:1;
};

+0 −1
Original line number Diff line number Diff line
@@ -3450,7 +3450,6 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
		goto out_no_tl;
	mdev->read_requests = RB_ROOT;
	mdev->write_requests = RB_ROOT;
	mdev->epoch_entries = RB_ROOT;

	mdev->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
	if (!mdev->current_epoch)
+16 −17
Original line number Diff line number Diff line
@@ -336,6 +336,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
	drbd_clear_interval(&e->i);
	e->i.size = data_size;
	e->i.sector = sector;
	e->i.local = false;
	e->i.waiting = false;

	e->epoch = NULL;
@@ -1508,7 +1509,7 @@ find_request(struct drbd_conf *mdev, struct rb_root *root, u64 id,

	/* Request object according to our peer */
	req = (struct drbd_request *)(unsigned long)id;
	if (drbd_contains_interval(root, sector, &req->i))
	if (drbd_contains_interval(root, sector, &req->i) && req->i.local)
		return req;
	if (!missing_ok) {
		dev_err(DEV, "%s: failed to find request %lu, sector %llus\n", func,
@@ -1788,17 +1789,12 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
		/* conflict detection and handling:
		 * 1. wait on the sequence number,
		 *    in case this data packet overtook ACK packets.
		 * 2. check our interval trees for conflicting requests:
		 *    we only need to check the write_requests tree; the
		 *    epoch_entries tree cannot contain any overlaps because
		 *    they were already eliminated on the submitting node.
		 * 2. check for conflicting write requests.
		 *
		 * Note: for two_primaries, we are protocol C,
		 * so there cannot be any request that is DONE
		 * but still on the transfer log.
		 *
		 * unconditionally add to the epoch_entries tree.
		 *
		 * if no conflicting request is found:
		 *    submit.
		 *
@@ -1823,12 +1819,9 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,

		spin_lock_irq(&mdev->tconn->req_lock);

		drbd_insert_interval(&mdev->epoch_entries, &e->i);

		first = 1;
		for (;;) {
			struct drbd_interval *i;
			struct drbd_request *req2;
			int have_unacked = 0;
			int have_conflict = 0;
			prepare_to_wait(&mdev->misc_wait, &wait,
@@ -1836,18 +1829,23 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,

			i = drbd_find_overlap(&mdev->write_requests, sector, size);
			if (i) {
				req2 = container_of(i, struct drbd_request, i);

				/* only ALERT on first iteration,
				 * we may be woken up early... */
				if (first)
					dev_alert(DEV, "%s[%u] Concurrent local write detected!"
					dev_alert(DEV, "%s[%u] Concurrent %s write detected!"
					      "	new: %llus +%u; pending: %llus +%u\n",
					      current->comm, current->pid,
					      i->local ? "local" : "remote",
					      (unsigned long long)sector, size,
					      (unsigned long long)req2->i.sector, req2->i.size);
					      (unsigned long long)i->sector, i->size);

				if (i->local) {
					struct drbd_request *req2;

					req2 = container_of(i, struct drbd_request, i);
					if (req2->rq_state & RQ_NET_PENDING)
						++have_unacked;
				}
				++have_conflict;
			}
			if (!have_conflict)
@@ -1873,7 +1871,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
			}

			if (signal_pending(current)) {
				drbd_remove_epoch_entry_interval(mdev, e);
				spin_unlock_irq(&mdev->tconn->req_lock);
				finish_wait(&mdev->misc_wait, &wait);
				goto out_interrupted;
@@ -1896,6 +1893,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packet cmd,
			spin_lock_irq(&mdev->tconn->req_lock);
		}
		finish_wait(&mdev->misc_wait, &wait);

		drbd_insert_interval(&mdev->write_requests, &e->i);
	}

	list_add(&e->w.list, &mdev->active_ee);
+4 −24
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
	drbd_clear_interval(&req->i);
	req->i.sector     = bio_src->bi_sector;
	req->i.size      = bio_src->bi_size;
	req->i.local = true;
	req->i.waiting = false;

	INIT_LIST_HEAD(&req->tl_requests);
@@ -317,8 +318,6 @@ static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_e
 * to happen, but this is the rationale why we also have to check for
 * conflicting requests with local origin, and why we have to do so regardless
 * of whether we allowed multiple primaries.
 *
 * In case we only have one primary, the epoch_entries tree is empty.
 */
static int _req_conflicts(struct drbd_request *req)
{
@@ -334,34 +333,15 @@ static int _req_conflicts(struct drbd_request *req)

	i = drbd_find_overlap(&mdev->write_requests, sector, size);
	if (i) {
		struct drbd_request *req2 =
			container_of(i, struct drbd_request, i);

		dev_alert(DEV, "%s[%u] Concurrent local write detected! "
		      "[DISCARD L] new: %llus +%u; "
		      "pending: %llus +%u\n",
		      current->comm, current->pid,
		      (unsigned long long)sector, size,
		      (unsigned long long)req2->i.sector, req2->i.size);
		goto out_conflict;
	}

	if (!RB_EMPTY_ROOT(&mdev->epoch_entries)) {
		/* check for overlapping requests with remote origin */
		i = drbd_find_overlap(&mdev->epoch_entries, sector, size);
		if (i) {
			struct drbd_epoch_entry *e =
				container_of(i, struct drbd_epoch_entry, i);

			dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
		dev_alert(DEV, "%s[%u] Concurrent %s write detected! "
		      "[DISCARD L] new: %llus +%u; "
		      "pending: %llus +%u\n",
		      current->comm, current->pid,
		      i->local ? "local" : "remote",
		      (unsigned long long)sector, size,
			      (unsigned long long)e->i.sector, e->i.size);
		      (unsigned long long)i->sector, i->size);
		goto out_conflict;
	}
	}

	/* this is like it should be, and what we expected.
	 * our users do behave after all... */
Loading