[DRBD-cvs] svn commit by lars - r2691 - trunk/drbd - no functional change. restructured _req_may_be_done spl

drbd-cvs at lists.linbit.com drbd-cvs at lists.linbit.com
Mon Jan 15 10:40:19 CET 2007


Author: lars
Date: 2007-01-15 10:40:18 +0100 (Mon, 15 Jan 2007)
New Revision: 2691

Modified:
   trunk/drbd/drbd_req.c
Log:
no functional change.
restructured _req_may_be_done
 split parts out into
	_about_to_complete_local_write
	_complete_master_bio
	_req_is_done


Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2007-01-15 08:14:40 UTC (rev 2690)
+++ trunk/drbd/drbd_req.c	2007-01-15 09:40:18 UTC (rev 2691)
@@ -103,46 +103,85 @@
 #define print_req_mod(T,W)
 #endif
 
-void _req_may_be_done(drbd_request_t *req, int error)
+static void _req_is_done(drbd_dev *mdev, drbd_request_t *req, const int rw)
 {
 	const unsigned long s = req->rq_state;
-	drbd_dev *mdev = req->mdev;
-	int rw;
+	/* if it was a write, we may have to set the corresponding
+	 * bit(s) out-of-sync first. If it had a local part, we need to
+	 * release the reference to the activity log. */
+	if (rw == WRITE) {
+		/* remove it from the transfer log.
+		 * well, only if it had been there in the first
+		 * place... if it had not (local only or conflicting
+		 * and never sent), it should still be "empty" as
+		 * initialised in drbd_req_new(), so we can list_del() it
+		 * here unconditionally */
+		list_del(&req->tl_requests);
+		/* Set out-of-sync unless both OK flags are set
+		 * (local only or remote failed).
+		 * Other places where we set out-of-sync:
+		 * READ with local io-error */
+		if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK)) {
+			drbd_set_out_of_sync(mdev,req->sector,req->size);
+		}
 
-	print_rq_state(req, "_req_may_be_done");
-	MUST_HOLD(&mdev->req_lock)
+		if( (s & RQ_NET_OK) && (s & RQ_LOCAL_OK) &&
+		    (s & RQ_NET_SIS) ) {
+			drbd_set_in_sync(mdev,req->sector,req->size);
+		}
 
-	if (s & RQ_NET_PENDING) return;
-	if (s & RQ_LOCAL_PENDING) return;
-
-	if (req->master_bio) {
-		/* this is data_received (remote read)
-		 * or protocol C WriteAck
-		 * or protocol B RecvAck
-		 * or protocol A "handed_over_to_network" (SendAck)
-		 * or canceled or failed,
-		 * or killed from the transfer log due to connection loss.
+		/* one might be tempted to move the drbd_al_complete_io
+		 * to the local io completion callback drbd_endio_pri.
+		 * but, if this was a mirror write, we may only
+		 * drbd_al_complete_io after this is RQ_NET_DONE,
+		 * otherwise the extent could be dropped from the al
+		 * before it has actually been written on the peer.
+		 * if we crash before our peer knows about the request,
+		 * but after the extent has been dropped from the al,
+		 * we would forget to resync the corresponding extent.
 		 */
+		if (s & RQ_LOCAL_MASK) {
+			if (inc_local_if_state(mdev,Failed)) {
+				drbd_al_complete_io(mdev, req->sector);
+				dec_local(mdev);
+			} else {
+				WARN("Should have called drbd_al_complete_io(, %llu), "
+				     "but my Disk seems to have failed:(\n", req->sector);
+			}
+		}
+	}
 
-		/*
-		 * figure out whether to report success or failure.
-		 *
-		 * report success when at least one of the operations suceeded.
-		 * or, to put the other way,
-		 * only report failure, when both operations failed.
-		 *
-		 * what to do about the failures is handled elsewhere.
-		 * what we need to do here is just: complete the master_bio.
-		 */
-		int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK);
-		rw = bio_data_dir(req->master_bio);
+	/* if it was a local io error, we want to notify our
+	 * peer about that, and see if we need to
+	 * detach the disk and stuff.
+	 * to avoid allocating some special work
+	 * struct, reuse the request. */
 
-		/* remove the request from the conflict detection
-		 * respective block_id verification hash */
-		if (!hlist_unhashed(&req->colision)) hlist_del(&req->colision);
-		else D_ASSERT((s & RQ_NET_MASK) == 0);
+	/* THINK
+	 * why do we do this not when we detect the error,
+	 * but delay it until it is "done", i.e. possibly
+	 * until the next barrier ack? */
 
-		if (rw == WRITE) {
+	if (rw == WRITE &&
+	    (( s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) {
+		if (!(req->w.list.next == LIST_POISON1 ||
+		      list_empty(&req->w.list))) {
+			/* DEBUG ASSERT only; if this triggers, we
+			 * probably corrupt the worker list here */
+			DUMPP(req->w.list.next);
+			DUMPP(req->w.list.prev);
+		}
+		req->w.cb = w_io_error;
+		drbd_queue_work(&mdev->data.work, &req->w);
+		/* drbd_req_free() is done in w_io_error */
+	} else {
+		drbd_req_free(req);
+	}
+}
+
+static void _about_to_complete_local_write(drbd_dev *mdev, drbd_request_t *req)
+{
+	const unsigned long s = req->rq_state;
 			drbd_request_t *i;
 			struct Tl_epoch_entry *e;
 			struct hlist_node *n;
@@ -196,6 +235,58 @@
 				}
 			}
 #undef OVERLAPS
+}
+
+static void _complete_master_bio(drbd_dev *mdev, drbd_request_t *req, int error)
+{
+	dump_bio(mdev,req->master_bio,1);
+	bio_endio(req->master_bio, req->master_bio->bi_size, error);
+	req->master_bio = NULL;
+	dec_ap_bio(mdev);
+}
+
+void _req_may_be_done(drbd_request_t *req, int error)
+{
+	const unsigned long s = req->rq_state;
+	drbd_dev *mdev = req->mdev;
+	int rw;
+
+	print_rq_state(req, "_req_may_be_done");
+	MUST_HOLD(&mdev->req_lock)
+
+	if (s & RQ_NET_PENDING) return;
+	if (s & RQ_LOCAL_PENDING) return;
+
+	if (req->master_bio) {
+		/* this is data_received (remote read)
+		 * or protocol C WriteAck
+		 * or protocol B RecvAck
+		 * or protocol A "handed_over_to_network" (SendAck)
+		 * or canceled or failed,
+		 * or killed from the transfer log due to connection loss.
+		 */
+
+		/*
+		 * figure out whether to report success or failure.
+		 *
+		 * report success when at least one of the operations suceeded.
+		 * or, to put the other way,
+		 * only report failure, when both operations failed.
+		 *
+		 * what to do about the failures is handled elsewhere.
+		 * what we need to do here is just: complete the master_bio.
+		 */
+		int ok = (s & RQ_LOCAL_OK) || (s & RQ_NET_OK);
+		rw = bio_data_dir(req->master_bio);
+
+		/* remove the request from the conflict detection
+		 * respective block_id verification hash */
+		if (!hlist_unhashed(&req->colision)) hlist_del(&req->colision);
+		else D_ASSERT((s & RQ_NET_MASK) == 0);
+
+		if (rw == WRITE) {
+			/* for writes we need to do some extra housekeeping */
+			_about_to_complete_local_write(mdev,req);
 		}
 
 		/* FIXME not yet implemented...
@@ -206,11 +297,9 @@
 		 * up here anyways during the freeze ...
 		 * then again, if it is a READ, it is not in the TL at all.
 		 * is it still leagal to complete a READ during freeze? */
-		dump_bio(mdev,req->master_bio,1);
-		bio_endio(req->master_bio, req->master_bio->bi_size, 
+
+		_complete_master_bio(mdev,req,
 			  ok ? 0 : ( error ? error : -EIO ) );
-		req->master_bio = NULL;
-		dec_ap_bio(mdev);
 	} else {
 		/* only WRITE requests can end up here without a master_bio */
 		rw = WRITE;
@@ -221,72 +310,7 @@
 		 * or protocol C WriteAck,
 		 * or protocol A or B BarrierAck,
 		 * or killed from the transfer log due to connection loss. */
-
-		/* if it was a write, we may have to set the corresponding
-		 * bit(s) out-of-sync first. If it had a local part, we need to
-		 * release the reference to the activity log. */
-		if (rw == WRITE) {
-			/* remove it from the transfer log.
-			 * well, only if it had been there in the first
-			 * place... if it had not (local only or conflicting
-			 * and never sent), it should still be "empty" as
-			 * initialised in drbd_req_new(), so we can list_del() it
-			 * here unconditionally */
-			list_del(&req->tl_requests);
-			/* Set out-of-sync unless both OK flags are set 
-			 * (local only or remote failed).
-			 * Other places where we set out-of-sync:
-			 * READ with local io-error */
-			if (!(s & RQ_NET_OK) || !(s & RQ_LOCAL_OK)) {
-				drbd_set_out_of_sync(mdev,req->sector,req->size);
-			}
-
-			if( (s & RQ_NET_OK) && (s & RQ_LOCAL_OK) && 
-			    (s & RQ_NET_SIS) ) {
-				drbd_set_in_sync(mdev,req->sector,req->size);
-			}
-
-			/* one might be tempted to move the drbd_al_complete_io
-			 * to the local io completion callback drbd_endio_pri.
-			 * but, if this was a mirror write, we may only
-			 * drbd_al_complete_io after this is RQ_NET_DONE,
-			 * otherwise the extent could be dropped from the al
-			 * before it has actually been written on the peer.
-			 * if we crash before our peer knows about the request,
-			 * but after the extent has been dropped from the al,
-			 * we would forget to resync the corresponding extent.
-			 */
-			if (s & RQ_LOCAL_MASK) {
-				if (inc_local_if_state(mdev,Failed)) {
-					drbd_al_complete_io(mdev, req->sector);
-					dec_local(mdev);
-				} else {
-					WARN("Should have called drbd_al_complete_io(, %llu), "
-					     "but my Disk seems to have failed:(\n", req->sector);
-				}
-			}
-		}
-
-		/* if it was an io error, we want to notify our
-		 * peer about that, and see if we need to
-		 * detach the disk and stuff.
-		 * to avoid allocating some special work
-		 * struct, reuse the request. */
-		if (rw == WRITE &&
-		    (( s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) {
-			if (!(req->w.list.next == LIST_POISON1 ||
-			      list_empty(&req->w.list))) {
-				/* DEBUG ASSERT only; if this triggers, we
-				 * probably corrupt the worker list here */
-				DUMPP(req->w.list.next);
-				DUMPP(req->w.list.prev);
-			}
-			req->w.cb = w_io_error;
-			drbd_queue_work(&mdev->data.work, &req->w);
-			/* drbd_req_free() is done in w_io_error */
-		} else {
-			drbd_req_free(req);
-		}
+		_req_is_done(mdev,req,rw);
 	}
 	/* else: network part and not DONE yet. that is
 	 * protocol A or B, barrier ack still pending... */



More information about the drbd-cvs mailing list