Hi, something like this? A callback list in the queue. The struct congestion_notify could be added to the struct mapped_device. Two atomic_t read_congested and write_congested. When it changed from/to zero set/clear the corresponding bit in q->backing_dev_info? --- linux-2.6.4-rc1.orig/drivers/block/ll_rw_blk.c 2004-02-29 20:41:56.000000000 +0100 +++ linux/drivers/block/ll_rw_blk.c 2004-03-01 22:32:23.782708544 +0100 @@ -93,6 +93,8 @@ return ret; } +static SPIN_LOCK_UNLOCKED(congestion_notify_lock); + /* * A queue has just exitted congestion. Note this in the global counter of * congested queues, and wake up anyone who was waiting for requests to be @@ -102,6 +104,13 @@ { enum bdi_state bit; wait_queue_head_t *wqh = &congestion_wqh[rw]; + struct congested_notify *notify; + unsigned long flags; + + spin_lock_irqsave(&congestion_notify_lock, flags); + list_for_each_entry(notify, &q->congested_notify, list) + notify->callback(q, notify->private, 1, rw); + spin_unlock_irqrestore(&congestion_notify_lock, flags); bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; clear_bit(bit, &q->backing_dev_info.state); @@ -116,6 +125,13 @@ static void set_queue_congested(request_queue_t *q, int rw) { enum bdi_state bit; + struct congested_notify *notify; + unsigned long flags; + + spin_lock_irqsave(&congestion_notify_lock, flags); + list_for_each_entry(notify, &q->congested_notify, list) + notify->callback(q, notify->private, 0, rw); + spin_unlock_irqrestore(&congestion_notify_lock, flags); bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; set_bit(bit, &q->backing_dev_info.state); @@ -140,6 +156,22 @@ return ret; } +void blk_queue_add_congestion_notify(request_queue_t *q, + struct congestion_notify *notify) +{ + spin_lock_irq(&congestion_notify_lock); + list_add(&q->congestion_notify, ¬ify->list); + spin_unlock_irq(&congestion_notify_lock); +} + +void blk_queue_remove_congestion_notify(request_queue_t *q, + struct congestion_notify *notify) +{ + spin_lock_irq(&congestion_notify_lock); + list_del(¬ify->list); + spin_unlock_irq(&congestion_notify_lock); +} + void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data) { q->activity_fn = fn; @@ -243,6 +275,7 @@ blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); INIT_LIST_HEAD(&q->plug_list); + INIT_LIST_HEAD(&q->congestion_notify); blk_queue_activity_fn(q, NULL, NULL); } --- linux-2.6.4-rc1.orig/include/linux/blkdev.h 2004-02-29 20:41:58.000000000 +0100 +++ linux/include/linux/blkdev.h 2004-03-01 22:11:29.101449088 +0100 @@ -248,6 +248,8 @@ struct bio_vec; typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *); typedef void (activity_fn) (void *data, int rw); +typedef void (congestion_callback_fn) (struct request_queue *q, void *data, + int clear, int rw); enum blk_queue_state { Queue_down, @@ -267,6 +269,12 @@ atomic_t refcnt; /* map can be shared */ }; +struct congestion_notify { + struct list_head list; + congestion_callback_fn callback; + void *private; +}; + struct request_queue { /* @@ -301,6 +309,8 @@ struct backing_dev_info backing_dev_info; + list_head congestion_notify; + /* * The queue owner gets to use this for whatever they like. * ll_rw_blk doesn't touch it. @@ -563,6 +573,8 @@ extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *); extern void blk_queue_dma_alignment(request_queue_t *, int); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); +extern void blk_queue_add_congestion_notify(request_queue_t *, struct congestion_notify *); +extern void blk_queue_remove_congestion_notify(request_queue_t *, struct congestion_notify *); extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *); extern void blk_dump_rq_flags(struct request *, char *);