patch: ll_rw_blk fixes

Jens Axboe axboe en suse.de
Mie Ene 26 15:24:16 CST 2000


Hi,

The attached patch continues the work that Eric Youngdale has
done with the queueing code.

The request merging code has been changed to include default
functions for request merges. Drivers that wish to apply different
rules to request merging, can now do so by filling in merge_fn
and merge_requests_fn after calling blk_init_queue(). The
ll_rw_blk default functions provide the same functionality
as before.

The new queueing code has a member indicating whether the
current_request is active or not. Low do not have an active
request head, should call blk_init_headactive(q, 0) and
they already do. This means that we can get rid of the
massive switch statement in __make_request.

-- 
*  Jens Axboe <axboe en suse.de>
*  Linux CD-ROM Maintainer
*  http://www.kernel.dk
------------ próxima parte ------------
--- linux-2.3.41-3-clean/drivers/block/DAC960.c	Wed Jan 26 02:34:28 2000
+++ linux/drivers/block/DAC960.c	Wed Jan 26 16:33:45 2000
@@ -1009,6 +1009,45 @@
 }
 
 
+static int DAC_merge_fn(request_queue_t *q, struct request *req, 
+			struct buffer_head *bh) 
+{
+	int max_segments;
+	DAC960_Controller_T * Controller = q->queuedata;
+
+	max_segments = Controller->MaxSegmentsPerRequest[MINOR(req->rq_dev)];
+
+	if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) {
+		if (req->nr_segments < max_segments) {
+			req->nr_segments++;
+			return 1;
+		}
+		return 0;
+	}
+
+	return 1;
+}
+
+static int DAC_merge_requests_fn(request_queue_t *q,
+				 struct request *req,
+				 struct request *next)
+{
+	int max_segments;
+	DAC960_Controller_T * Controller = q->queuedata;
+	int total_segments = req->nr_segments + next->nr_segments;
+
+	max_segments = Controller->MaxSegmentsPerRequest[MINOR(req->rq_dev)];
+
+	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+		total_segments--;
+    
+	if (total_segments > max_segments)
+		return 0;
+
+	req->nr_segments = total_segments;
+	return 1;
+}
+
 /*
   DAC960_RegisterBlockDevice registers the Block Device structures
   associated with Controller.
@@ -1016,6 +1055,8 @@
 
 static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
 {
+  request_queue_t * q;
+
   static void (*RequestFunctions[DAC960_MaxControllers])(request_queue_t *) =
     { DAC960_RequestFunction0, DAC960_RequestFunction1,
       DAC960_RequestFunction2, DAC960_RequestFunction3,
@@ -1036,8 +1077,13 @@
   /*
     Initialize the I/O Request Function.
   */
-  blk_init_queue(BLK_DEFAULT_QUEUE(MajorNumber), 
-		 RequestFunctions[Controller->ControllerNumber]);
+  q = BLK_DEFAULT_QUEUE(MajorNumber);
+  blk_init_queue(q, RequestFunctions[Controller->ControllerNumber]);
+  blk_queue_headactive(q, 0);
+  q->merge_fn = DAC_merge_fn;
+  q->merge_requests_fn = DAC_merge_requests_fn;
+  q->queuedata = (void *) Controller;
+
   /*
     Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
     array, Max Sectors per Request array, and Max Segments per Request array.
@@ -1054,7 +1100,6 @@
   Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
   blksize_size[MajorNumber] = Controller->BlockSizes;
   max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
-  max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest;
   /*
     Initialize Read Ahead to 128 sectors.
   */
diff -ur --exclude-from /home/axboe/cdrom/exclude-from linux-2.3.41-3-clean/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.3.41-3-clean/drivers/block/ll_rw_blk.c	Mon Dec 13 06:55:54 1999
+++ linux/drivers/block/ll_rw_blk.c	Wed Jan 26 16:22:50 2000
@@ -118,11 +118,6 @@
  */
 int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
 
-/*
- * Max number of segments per request
- */
-int * max_segments[MAX_BLKDEV] = { NULL, NULL, };
-
 static inline int get_max_sectors(kdev_t dev)
 {
 	if (!max_sectors[MAJOR(dev)])
@@ -130,13 +125,6 @@
 	return max_sectors[MAJOR(dev)][MINOR(dev)];
 }
 
-static inline int get_max_segments(kdev_t dev)
-{
-	if (!max_segments[MAJOR(dev)])
-		return MAX_SEGMENTS;
-	return max_segments[MAJOR(dev)][MINOR(dev)];
-}
-
 /*
  * Is called with the request spinlock aquired.
  * NOTE: the device-specific queue() functions
@@ -167,24 +155,52 @@
 	q->use_plug        = use_plug;
 }
 
+static int ll_merge_fn(request_queue_t *q, struct request *req, 
+		       struct buffer_head *bh) 
+{
+	if (req->bhtail->b_data + req->bhtail->b_size != bh->b_data) {
+		if (req->nr_segments < MAX_SEGMENTS) {
+			req->nr_segments++;
+			return 1;
+		}
+		return 0;
+	}
+	return 1;
+}
+
+static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
+				struct request *next)
+{
+	int total_segments = req->nr_segments + next->nr_segments;
+
+	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
+		total_segments--;
+    
+	if (total_segments > MAX_SEGMENTS)
+		return 0;
+
+	req->nr_segments = total_segments;
+	return 1;
+}
+
 void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
 {
-	q->request_fn      = rfn;
-	q->current_request = NULL;
-	q->merge_fn        = NULL;
-	q->merge_requests_fn = NULL;
-	q->plug_tq.sync    = 0;
-	q->plug_tq.routine = &unplug_device;
-	q->plug_tq.data    = q;
-	q->plugged         = 0;
+	q->request_fn		= rfn;
+	q->current_request	= NULL;
+	q->merge_fn		= ll_merge_fn;
+	q->merge_requests_fn	= ll_merge_requests_fn;
+	q->plug_tq.sync		= 0;
+	q->plug_tq.routine	= unplug_device;
+	q->plug_tq.data		= q;
+	q->plugged		= 0;
 	/*
 	 * These booleans describe the queue properties.  We set the
 	 * default (and most common) values here.  Other drivers can
 	 * use the appropriate functions to alter the queue properties.
 	 * as appropriate.
 	 */
-	q->use_plug        = 1;
-	q->head_active     = 1;
+	q->use_plug		= 1;
+	q->head_active		= 1;
 }
 
 /*
@@ -427,11 +443,12 @@
  */
 static inline void attempt_merge (request_queue_t * q,
 				  struct request *req, 
-				  int max_sectors,
-				  int max_segments)
+				  int max_sectors)
 {
 	struct request *next = req->next;
-	int total_segments;
+
+	if (req->rq_dev == MKDEV(22, 64))
+		printk("attempt_merge at %lu %lu\n", req->sector, q->current_request->sector);
 
 	if (!next)
 		return;
@@ -439,29 +456,15 @@
 		return;
 	if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
 		return;
-	total_segments = req->nr_segments + next->nr_segments;
-	if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
-		total_segments--;
-	if (total_segments > max_segments)
-		return;
 
-	if( q->merge_requests_fn != NULL )
-	{
-		/*
-		 * If we are not allowed to merge these requests, then
-		 * return.  If we are allowed to merge, then the count
-		 * will have been updated to the appropriate number,
-		 * and we shouldn't do it here too.
-		 */
-		if( !(q->merge_requests_fn)(q, req, next) )
-		{
-			return;
-		}
-	}
-	else
-	{
-		req->nr_segments = total_segments;
-	}
+	/*
+	 * If we are not allowed to merge these requests, then
+	 * return.  If we are allowed to merge, then the count
+	 * will have been updated to the appropriate number,
+	 * and we shouldn't do it here too.
+	 */
+	if(!(q->merge_requests_fn)(q, req, next))
+		return;
 
 	req->bhtail->b_reqnext = next->bh;
 	req->bhtail = next->bhtail;
@@ -478,7 +481,7 @@
 {
 	unsigned int sector, count;
 	struct request * req;
-	int rw_ahead, max_req, max_sectors, max_segments;
+	int rw_ahead, max_req, max_sectors;
 	unsigned long flags;
 
 	count = bh->b_size >> 9;
@@ -570,7 +573,6 @@
 	 * Try to coalesce the new request with old requests
 	 */
 	max_sectors = get_max_sectors(bh->b_rdev);
-	max_segments = get_max_segments(bh->b_rdev);
 
 	/*
 	 * Now we acquire the request spinlock, we have to be mega careful
@@ -584,162 +586,88 @@
 		    major != DDV_MAJOR && major != NBD_MAJOR
 		    && q->use_plug)
 			plug_device(q); /* is atomic */
-	} else switch (major) {
-	     /*
-	      * FIXME(eric) - this entire switch statement is going away
-	      * soon, and we will instead key off of q->head_active to decide
-	      * whether the top request in the queue is active on the device
-	      * or not.
-	      */
-	     case IDE0_MAJOR:	/* same as HD_MAJOR */
-	     case IDE1_MAJOR:
-	     case FLOPPY_MAJOR:
-	     case IDE2_MAJOR:
-	     case IDE3_MAJOR:
-	     case IDE4_MAJOR:
-	     case IDE5_MAJOR:
-	     case IDE6_MAJOR:
-	     case IDE7_MAJOR:
-	     case IDE8_MAJOR:
-	     case IDE9_MAJOR:
-	     case ACSI_MAJOR:
-	     case MFM_ACORN_MAJOR:
+		goto get_rq;
+	}
+
+	if (q->head_active) {
 		/*
 		 * The scsi disk and cdrom drivers completely remove the request
 		 * from the queue when they start processing an entry.  For this
-		 * reason it is safe to continue to add links to the top entry for
-		 * those devices.
+		 * reason it is safe to continue to add links to the top entry
+		 * for those devices.
 		 *
 		 * All other drivers need to jump over the first entry, as that
-		 * entry may be busy being processed and we thus can't change it.
+		 * entry may be busy being processed and we thus can't change
+		 * it.
 		 */
-		if (req == q->current_request)
-	        	req = req->next;
-		if (!req)
-			break;
-		/* fall through */
-
-	     case SCSI_DISK0_MAJOR:
-	     case SCSI_DISK1_MAJOR:
-	     case SCSI_DISK2_MAJOR:
-	     case SCSI_DISK3_MAJOR:
-	     case SCSI_DISK4_MAJOR:
-	     case SCSI_DISK5_MAJOR:
-	     case SCSI_DISK6_MAJOR:
-	     case SCSI_DISK7_MAJOR:
-	     case SCSI_CDROM_MAJOR:
-	     case DAC960_MAJOR+0:
-	     case DAC960_MAJOR+1:
-	     case DAC960_MAJOR+2:
-	     case DAC960_MAJOR+3:
-	     case DAC960_MAJOR+4:
-	     case DAC960_MAJOR+5:
-	     case DAC960_MAJOR+6:
-	     case DAC960_MAJOR+7:
-	     case I2O_MAJOR:
-	     case COMPAQ_SMART2_MAJOR+0:
-	     case COMPAQ_SMART2_MAJOR+1:
-	     case COMPAQ_SMART2_MAJOR+2:
-	     case COMPAQ_SMART2_MAJOR+3:
-	     case COMPAQ_SMART2_MAJOR+4:
-	     case COMPAQ_SMART2_MAJOR+5:
-	     case COMPAQ_SMART2_MAJOR+6:
-	     case COMPAQ_SMART2_MAJOR+7:
+		if ((req = req->next) == NULL)
+			goto get_rq;
+	}
 
-		do {
-			if (req->sem)
-				continue;
-			if (req->cmd != rw)
-				continue;
-			if (req->nr_sectors + count > max_sectors)
-				continue;
-			if (req->rq_dev != bh->b_rdev)
+	do {
+		if (req->sem)
+			continue;
+		if (req->cmd != rw)
+			continue;
+		if (req->nr_sectors + count > max_sectors)
+			continue;
+		if (req->rq_dev != bh->b_rdev)
+			continue;
+		/* Can we add it to the end of this request? */
+		if (req->sector + req->nr_sectors == sector) {
+			/*
+			 * The merge_fn is a more advanced way
+			 * of accomplishing the same task.  Instead
+			 * of applying a fixed limit of some sort
+			 * we instead define a function which can
+			 * determine whether or not it is safe to
+			 * merge the request or not.
+			 *
+			 * See if this queue has rules that
+			 * may suggest that we shouldn't merge
+			 * this 
+			 */
+			if(!(q->merge_fn)(q, req, bh))
 				continue;
-			/* Can we add it to the end of this request? */
-			if (req->sector + req->nr_sectors == sector) {
-				/*
-				 * The merge_fn is a more advanced way
-				 * of accomplishing the same task.  Instead
-				 * of applying a fixed limit of some sort
-				 * we instead define a function which can
-				 * determine whether or not it is safe to
-				 * merge the request or not.
-				 */
-				if( q->merge_fn == NULL )
-				{
-					if (req->bhtail->b_data + req->bhtail->b_size
-					    != bh->b_data) {
-						if (req->nr_segments < max_segments)
-							req->nr_segments++;
-						else continue;
-					}
-				}
-				else
-				{
-					/*
-					 * See if this queue has rules that
-					 * may suggest that we shouldn't merge
-					 * this 
-					 */
-					if( !(q->merge_fn)(q, req, bh) )
-					{
-						continue;
-					}
-				}
-				req->bhtail->b_reqnext = bh;
-				req->bhtail = bh;
-			    	req->nr_sectors += count;
-				drive_stat_acct(req, count, 0);
-				/* Can we now merge this req with the next? */
-				attempt_merge(q, req, max_sectors, max_segments);
-			/* or to the beginning? */
-			} else if (req->sector - count == sector) {
-				/*
-				 * The merge_fn is a more advanced way
-				 * of accomplishing the same task.  Instead
-				 * of applying a fixed limit of some sort
-				 * we instead define a function which can
-				 * determine whether or not it is safe to
-				 * merge the request or not.
-				 */
-				if( q->merge_fn == NULL )
-				{
-					if (bh->b_data + bh->b_size
-					    != req->bh->b_data) {
-						if (req->nr_segments < max_segments)
-							req->nr_segments++;
-						else continue;
-					}
-				}
-				else
-				{
-					/*
-					 * See if this queue has rules that
-					 * may suggest that we shouldn't merge
-					 * this 
-					 */
-					if( !(q->merge_fn)(q, req, bh) )
-					{
-						continue;
-					}
-				}
-			    	bh->b_reqnext = req->bh;
-			    	req->bh = bh;
-			    	req->buffer = bh->b_data;
-			    	req->current_nr_sectors = count;
-			    	req->sector = sector;
-			    	req->nr_sectors += count;
-				drive_stat_acct(req, count, 0);
-			} else
+			req->bhtail->b_reqnext = bh;
+			req->bhtail = bh;
+		    	req->nr_sectors += count;
+			drive_stat_acct(req, count, 0);
+			/* Can we now merge this req with the next? */
+			attempt_merge(q, req, max_sectors);
+		/* or to the beginning? */
+		} else if (req->sector - count == sector) {
+			/*
+			 * The merge_fn is a more advanced way
+			 * of accomplishing the same task.  Instead
+			 * of applying a fixed limit of some sort
+			 * we instead define a function which can
+			 * determine whether or not it is safe to
+			 * merge the request or not.
+			 *
+			 * See if this queue has rules that
+			 * may suggest that we shouldn't merge
+			 * this 
+			 */
+			if(!(q->merge_fn)(q, req, bh))
 				continue;
+		    	bh->b_reqnext = req->bh;
+		    	req->bh = bh;
+		    	req->buffer = bh->b_data;
+		    	req->current_nr_sectors = count;
+		    	req->sector = sector;
+		    	req->nr_sectors += count;
+			drive_stat_acct(req, count, 0);
+		} else
+			continue;
 
-			spin_unlock_irqrestore(&io_request_lock,flags);
-		    	return;
+		spin_unlock_irqrestore(&io_request_lock,flags);
+	    	return;
 
-		} while ((req = req->next) != NULL);
-	}
+	} while ((req = req->next) != NULL);
 
 /* find an unused request. */
+get_rq:
 	req = get_request(max_req, bh->b_rdev);
 
 	spin_unlock_irqrestore(&io_request_lock,flags);
diff -ur --exclude-from /home/axboe/cdrom/exclude-from linux-2.3.41-3-clean/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.3.41-3-clean/kernel/ksyms.c	Wed Jan 26 02:34:30 2000
+++ linux/kernel/ksyms.c	Wed Jan 26 02:30:44 2000
@@ -270,7 +270,6 @@
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(max_sectors);
-EXPORT_SYMBOL(max_segments);
 EXPORT_SYMBOL(max_readahead);
 EXPORT_SYMBOL(file_moveto);
 


Más información sobre la lista de distribución Ayuda