diff options
author | Thomas Maier <balagi@justmail.de> | 2006-12-08 02:36:11 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 08:28:38 -0800 |
commit | 0a0fc9601dd1024ec7171993bf075a789246e1ed (patch) | |
tree | c606a35beb9c56ccfeff57cb594e6a7e5b12a80c | |
parent | 2d4eeec563a0472b68de3597c17f2d3b11c49c00 (diff) | |
download | blackbird-op-linux-0a0fc9601dd1024ec7171993bf075a789246e1ed.tar.gz blackbird-op-linux-0a0fc9601dd1024ec7171993bf075a789246e1ed.zip |
[PATCH] pktcdvd: bio write congestion using congestion_wait()
This adds a bio write queue congestion control to the pktcdvd driver with
fixed on/off marks. It prevents that the driver consumes a unlimited
amount of write requests.
[akpm@osdl.org: sync with congestion_wait() renaming]
Signed-off-by: Thomas Maier <balagi@justmail.de>
Cc: Peter Osterlund <petero2@telia.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/block/pktcdvd.c | 32 | ||||
-rw-r--r-- | include/linux/pktcdvd.h | 9 |
2 files changed, 41 insertions, 0 deletions
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7e7b892f621a..91fbe7fd6d0b 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -84,6 +84,8 @@ static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; static struct proc_dir_entry *pkt_proc; static int pktdev_major; +static int write_congestion_on = PKT_WRITE_CONGESTION_ON; +static int write_congestion_off = PKT_WRITE_CONGESTION_OFF; static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */ static mempool_t *psd_pool; @@ -894,6 +896,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) sector_t zone = 0; /* Suppress gcc warning */ struct pkt_rb_node *node, *first_node; struct rb_node *n; + int wakeup; VPRINTK("handle_queue\n"); @@ -966,7 +969,13 @@ try_next_bio: pkt->write_size += bio->bi_size / CD_FRAMESIZE; spin_unlock(&pkt->lock); } + /* check write congestion marks, and if bio_queue_size is + below, wake up any waiters */ + wakeup = (pd->write_congestion_on > 0 + && pd->bio_queue_size <= pd->write_congestion_off); spin_unlock(&pd->lock); + if (wakeup) + blk_clear_queue_congested(pd->disk->queue, WRITE); pkt->sleep_time = max(PACKET_WAIT_TIME, 1); pkt_set_state(pkt, PACKET_WAITING_STATE); @@ -2179,6 +2188,23 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio) } spin_unlock(&pd->cdrw.active_list_lock); + /* + * Test if there is enough room left in the bio work queue + * (queue size >= congestion on mark). + * If not, wait till the work queue size is below the congestion off mark. + */ + spin_lock(&pd->lock); + if (pd->write_congestion_on > 0 + && pd->bio_queue_size >= pd->write_congestion_on) { + blk_set_queue_congested(q, WRITE); + do { + spin_unlock(&pd->lock); + congestion_wait(WRITE, HZ); + spin_lock(&pd->lock); + } while(pd->bio_queue_size > pd->write_congestion_off); + } + spin_unlock(&pd->lock); + /* * No matching packet found. Store the bio in the work queue. */ @@ -2298,6 +2324,9 @@ static int pkt_seq_show(struct seq_file *m, void *p) seq_printf(m, "\tstate:\t\t\ti:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n", states[0], states[1], states[2], states[3], states[4], states[5]); + seq_printf(m, "\twrite congestion marks:\toff=%d on=%d\n", + pd->write_congestion_off, + pd->write_congestion_on); return 0; } @@ -2474,6 +2503,9 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) init_waitqueue_head(&pd->wqueue); pd->bio_queue = RB_ROOT; + pd->write_congestion_on = write_congestion_on; + pd->write_congestion_off = write_congestion_off; + disk = alloc_disk(1); if (!disk) goto out_mem; diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index 8a94c717c266..9b1a185fb1e5 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h @@ -112,6 +112,12 @@ struct pkt_ctrl_command { #include <linux/completion.h> #include <linux/cdrom.h> + +/* default bio write queue congestion marks */ +#define PKT_WRITE_CONGESTION_ON 10000 +#define PKT_WRITE_CONGESTION_OFF 9000 + + struct packet_settings { __u32 size; /* packet size in (512 byte) sectors */ @@ -271,6 +277,9 @@ struct pktcdvd_device struct packet_iosched iosched; struct gendisk *disk; + + int write_congestion_off; + int write_congestion_on; }; #endif /* __KERNEL__ */ |