From: Nick Piggin 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); } _