From: Nick Piggin <piggin@cyberone.com.au>

This patch locks the as_io_context when non atomic fields are modified or
read->written, etc.

The two places this happens are in as_update_iohist (when a request is
inserted, process context), and as_completed_request (when a request is
completed, interrupt context).

Now the process context can't race with itself, but it can race with a
completion of a request from the same process on another queue, or two
completions on two queues from the same process can race.

The other place which is still vulnerable is can_break_antic This only
reads values, so they won't be corrupted, but may still be inaccurate.

I don't know how important this is: the major stuff is done in
as_update_iohist, which can't race against itself...



 drivers/block/as-iosched.c |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)

diff -puN drivers/block/as-iosched.c~as-locking drivers/block/as-iosched.c
--- 25/drivers/block/as-iosched.c~as-locking	2003-06-11 19:49:15.000000000 -0700
+++ 25-akpm/drivers/block/as-iosched.c	2003-06-11 19:49:15.000000000 -0700
@@ -89,6 +89,8 @@ struct as_io_context {
 	atomic_t nr_queued; /* queued reads & sync writes */
 	atomic_t nr_dispatched; /* number of requests gone to the drivers */
 
+	spinlock_t lock;
+	
 	/* IO History tracking */
 	/* Thinktime */
 	unsigned long last_end_request;
@@ -260,6 +262,7 @@ static struct as_io_context *get_as_io_c
 			ret->state = 1 << AS_TASK_RUNNING;
 			atomic_set(&ret->nr_queued, 0);
 			atomic_set(&ret->nr_dispatched, 0);
+			spin_lock_init(&ret->lock);
 			ret->ttime_total = 0;
 			ret->ttime_samples = 0;
 			ret->ttime_mean = 0;
@@ -841,8 +844,10 @@ static void as_update_iohist(struct as_i
 
 	if (aic == NULL)
 		return;
-
+	
 	if (data_dir == REQ_SYNC) {
+		spin_lock(&aic->lock);
+		
 		if (test_bit(AS_TASK_IORUNNING, &aic->state)
 				&& !atomic_read(&aic->nr_queued)
 				&& !atomic_read(&aic->nr_dispatched)) {
@@ -876,9 +881,11 @@ static void as_update_iohist(struct as_i
 		if (!aic->seek_samples)
 			seek_dist = 0;
 		else if (aic->seek_samples < 400) /* second&third seek */
-			seek_dist = min(seek_dist, (aic->seek_mean * 4) + 2*1024*1024);
+			seek_dist = min(seek_dist, (aic->seek_mean * 4)
+							+ 2*1024*1024);
 		else
-			seek_dist = min(seek_dist, (aic->seek_mean * 4) + 2*1024*64);
+			seek_dist = min(seek_dist, (aic->seek_mean * 4)
+							+ 2*1024*64);
 
 		aic->seek_samples += 256;
 		aic->seek_total += 256*seek_dist;
@@ -890,6 +897,8 @@ static void as_update_iohist(struct as_i
 					+ (aic->seek_samples>>2);
 		aic->seek_total = (aic->seek_total>>1)
 					+ (aic->seek_total>>2);
+
+		spin_unlock(&aic->lock);
 	}
 }
 
@@ -987,6 +996,7 @@ static void as_completed_request(request
 	if (!aic)
 		return;
 
+	spin_lock(&aic->lock);
 	if (arq->is_sync == REQ_SYNC) {
 		set_bit(AS_TASK_IORUNNING, &aic->state);
 		aic->last_end_request = jiffies;
@@ -1003,7 +1013,7 @@ static void as_completed_request(request
 			as_antic_waitnext(ad);
 		}
 	}
-
+	spin_unlock(&aic->lock);
 	put_as_io_context(&arq->as_io_context);
 }
 

_