[DRBD-cvs] svn commit by phil - r2286 - trunk/drbd - This finally fixes the send_from_worker's context patch

drbd-cvs at lists.linbit.com drbd-cvs at lists.linbit.com
Wed Jul 19 10:40:04 CEST 2006


Author: phil
Date: 2006-07-19 10:40:02 +0200 (Wed, 19 Jul 2006)
New Revision: 2286

Modified:
   trunk/drbd/drbd_main.c
   trunk/drbd/drbd_req.c
   trunk/drbd/drbd_worker.c
Log:
This finally fixes the send_from_worker's context patch. 
We had memory corruption ( access after free() )


Modified: trunk/drbd/drbd_main.c
===================================================================
--- trunk/drbd/drbd_main.c	2006-07-18 14:32:20 UTC (rev 2285)
+++ trunk/drbd/drbd_main.c	2006-07-19 08:40:02 UTC (rev 2286)
@@ -230,22 +230,6 @@
 	spin_unlock_irq(&mdev->tl_lock);
 }
 
-STATIC void tl_cancel(drbd_dev *mdev, drbd_request_t *req)
-{
-	struct drbd_barrier *b;
-
-	spin_lock_irq(&mdev->tl_lock);
-
-	b=req->barrier;
-	b->n_req--;
-
-	list_del(&req->tl_requests);
-	hlist_del(&req->colision);
-	req->rq_status &= ~RQ_DRBD_IN_TL;
-
-	spin_unlock_irq(&mdev->tl_lock);
-}
-
 /**
  * tl_add_barrier: Creates a new barrier object and links it into the
  * transfer log. It returns the the newest (but not the just created 
@@ -294,15 +278,18 @@
 	spin_unlock_irq(&mdev->tl_lock);
 
 	D_ASSERT(b->br_number == barrier_nr);
+	D_ASSERT(b->n_req == set_size);
+
+#ifdef DBG_ASSERTS
 	if(b->br_number != barrier_nr) {
 		DUMPI(b->br_number);
 		DUMPI(barrier_nr);
 	}
-	D_ASSERT(b->n_req == set_size);
 	if(b->n_req != set_size) {
 		DUMPI(b->n_req);
 		DUMPI(set_size);
 	}
+#endif
 
 	kfree(b);
 }
@@ -348,6 +335,7 @@
 	r = ( req->barrier == mdev->newest_barrier );
 	list_del(&req->tl_requests);
 	hlist_del(&req->colision);
+	// req->barrier->n_req--; // Barrier migh be free'ed already!
 
 	if( req->rq_status & RQ_DRBD_RECVW ) wake_up(&mdev->cstate_wait);
 
@@ -358,35 +346,20 @@
 void tl_clear(drbd_dev *mdev)
 {
 	struct list_head *le,*tle;
-	struct drbd_barrier *b,*f,*new_first;
+	struct drbd_barrier *b,*f;
 	struct drbd_request *r;
 	sector_t sector;
 	unsigned int size;
 
-	new_first=kmalloc(sizeof(struct drbd_barrier),GFP_NOIO);
-	if(!new_first) {
-		ERR("could not kmalloc() barrier\n");
-	}
-
-	/* FIXME if indeed we could not kmalloc, this will Oops!
-	 * can we somehow just recycle one of the existing barriers?
-	 */
-	INIT_LIST_HEAD(&new_first->requests);
-	new_first->next=0;
-	new_first->br_number=4711;
-	new_first->n_req=0;
-
 	spin_lock_irq(&mdev->tl_lock);
 
 	b=mdev->oldest_barrier;
-	mdev->oldest_barrier = new_first;
-	mdev->newest_barrier = new_first;
+	mdev->oldest_barrier = NULL;
+	mdev->newest_barrier = NULL; 
 
 	spin_unlock_irq(&mdev->tl_lock);
 
-	inc_ap_pending(mdev); // Since we count the old first as well...
-
-	while ( b ) {
+	while ( 1 ) {
 		list_for_each_safe(le, tle, &b->requests) {
 			r = list_entry(le, struct drbd_request,tl_requests);
 			// bi_size and bi_sector are modified in bio_endio!
@@ -406,9 +379,24 @@
 		f=b;
 		b=b->next;
 		list_del(&f->requests);
+		if (!b) break;
 		kfree(f);
 		dec_ap_pending(mdev); // for the barrier
 	}
+
+	// f is now the last barrier, we use it as new first barrier.
+
+	INIT_LIST_HEAD(&f->requests);
+	f->next=NULL;
+	f->br_number=4711;
+	f->n_req=0;
+
+	spin_lock_irq(&mdev->tl_lock);
+
+	mdev->oldest_barrier = f;
+	mdev->newest_barrier = f;
+
+	spin_unlock_irq(&mdev->tl_lock);
 }
 
 STATIC unsigned int ee_hash_fn(drbd_dev *mdev, sector_t sector)

Modified: trunk/drbd/drbd_req.c
===================================================================
--- trunk/drbd/drbd_req.c	2006-07-18 14:32:20 UTC (rev 2285)
+++ trunk/drbd/drbd_req.c	2006-07-19 08:40:02 UTC (rev 2286)
@@ -77,8 +77,9 @@
 			if(tl_dependence(mdev,req))
 				set_bit(ISSUE_BARRIER,&mdev->flags);
 		} else {
-			list_del(&req->w.list); // we have the tl_lock...
+			list_del(&req->tl_requests); // we have the tl_lock...
 			hlist_del(&req->colision);
+			// req->barrier->n_req--; // Barrier migh be free'ed !
 		}
 	}
 

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-07-18 14:32:20 UTC (rev 2285)
+++ trunk/drbd/drbd_worker.c	2006-07-19 08:40:02 UTC (rev 2286)
@@ -562,12 +562,13 @@
 	drbd_request_t *req = (drbd_request_t *)w;
 	int ok;
 
+	inc_ap_pending(mdev); // Right here, since tl_clear() will decrease it
+
 	if (unlikely(cancel)) { 
 		/* Nothing to do, here. tl_clear() does the work. */
 		return 1;
 	}
 
-	inc_ap_pending(mdev);
 	ok = drbd_send_dblock(mdev,req);
 	if (!ok) {
 		if (mdev->state.conn >= Connected) 



More information about the drbd-cvs mailing list