[DRBD-cvs] svn commit by phil - r2105 - trunk/drbd - * Fixed an SMP/preemption lockup. We need to take the d

drbd-cvs at lists.linbit.com drbd-cvs at lists.linbit.com
Wed Mar 8 11:40:25 CET 2006


Author: phil
Date: 2006-03-08 11:40:24 +0100 (Wed, 08 Mar 2006)
New Revision: 2105

Modified:
   trunk/drbd/drbd_receiver.c
   trunk/drbd/drbd_worker.c
Log:
* Fixed an SMP/preemption lockup. We need to take the drbd_pp_lock IRQ
  save in drbd_pp_alloc(), becuase we call drbd_pp_free() from IRQ 
  context later on.
    
* Fixed the counting of the epoch_size on the receiver, grumbl. Lars!



Modified: trunk/drbd/drbd_receiver.c
===================================================================
--- trunk/drbd/drbd_receiver.c	2006-03-07 13:26:14 UTC (rev 2104)
+++ trunk/drbd/drbd_receiver.c	2006-03-08 10:40:24 UTC (rev 2105)
@@ -125,6 +125,7 @@
  */
 STATIC struct page * drbd_pp_alloc(drbd_dev *mdev, unsigned int gfp_mask)
 {
+	unsigned long flags=0;
 	struct page *page;
 	DEFINE_WAIT(wait);
 
@@ -133,13 +134,14 @@
 	 * not make sense.
 	 */
 
-	/* first, use our pool. */
-	spin_lock(&drbd_pp_lock);
+	spin_lock_irqsave(&drbd_pp_lock,flags);
+	/* This lock needs to be IRQ save because we might call drdb_pp_free()
+	   from IRQ context. */
 	if ( (page = drbd_pp_pool) ) {
 		drbd_pp_pool = (struct page*)page->U_PRIVATE;
 		drbd_pp_vacant--;
 	}
-	spin_unlock(&drbd_pp_lock);
+	spin_unlock_irqrestore(&drbd_pp_lock,flags);
 	if (page) goto got_page;
 
 	drbd_kick_lo(mdev);
@@ -148,12 +150,12 @@
 		prepare_to_wait(&drbd_pp_wait, &wait, TASK_INTERRUPTIBLE);
 
 		/* try the pool again, maybe the drbd_kick_log set some free */
-		spin_lock(&drbd_pp_lock);
+		spin_lock_irqsave(&drbd_pp_lock,flags);
 		if ( (page = drbd_pp_pool) ) {
 			drbd_pp_pool = (struct page*)page->U_PRIVATE;
 			drbd_pp_vacant--;
 		}
-		spin_unlock(&drbd_pp_lock);
+		spin_unlock_irqrestore(&drbd_pp_lock,flags);
 
 		if (page) break;
 
@@ -188,18 +190,24 @@
 
 STATIC void drbd_pp_free(drbd_dev *mdev,struct page *page)
 {
-	spin_lock(&drbd_pp_lock);
+	unsigned long flags=0;
+	int free_it;
+
+	spin_lock_irqsave(&drbd_pp_lock,flags);
 	if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) {
-		__free_page(page);
+		free_it = 1;
 	} else {
 		page->U_PRIVATE = (unsigned long)drbd_pp_pool;
 		drbd_pp_pool = page;
 		drbd_pp_vacant++;
+		free_it = 0;
 	}
-	spin_unlock(&drbd_pp_lock);
+	spin_unlock_irqrestore(&drbd_pp_lock,flags);
 
 	atomic_dec(&mdev->pp_in_use);
 
+	if(free_it) __free_page(page);
+
 	/*
 	 * FIXME
 	 * typically there are no waiters.

Modified: trunk/drbd/drbd_worker.c
===================================================================
--- trunk/drbd/drbd_worker.c	2006-03-07 13:26:14 UTC (rev 2104)
+++ trunk/drbd/drbd_worker.c	2006-03-08 10:40:24 UTC (rev 2105)
@@ -102,6 +102,7 @@
 	struct Tl_epoch_entry *e=NULL;
 	struct Drbd_Conf* mdev;
 	int do_wake;
+	int is_syncer_req;
 
 	e = bio->bi_private;
 	mdev = e->mdev;
@@ -113,11 +114,13 @@
 	D_ASSERT(e->block_id != ID_VACANT);
 
 	spin_lock_irqsave(&mdev->ee_lock,flags);
-	mdev->epoch_size++;
+	is_syncer_req = is_syncer_block_id(e->block_id);
 	list_del(&e->w.list);
 	list_add_tail(&e->w.list,&mdev->done_ee);
 
-	do_wake = is_syncer_block_id(e->block_id)
+	if(!is_syncer_req) mdev->epoch_size++;
+
+	do_wake = is_syncer_req
 		? list_empty(&mdev->sync_ee)
 		: list_empty(&mdev->active_ee);
 
@@ -371,7 +374,7 @@
 		inc_rs_pending(mdev);
 		if(!drbd_send_drequest(mdev,RSDataRequest,
 				       sector,size,ID_SYNCER)) {
-			ERR("drbd_send_drequest() failed, aborting...");
+			ERR("drbd_send_drequest() failed, aborting...\n");
 			dec_rs_pending(mdev);
 			return 0; // FAILED. worker will abort!
 		}



More information about the drbd-cvs mailing list