diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/drivers/block/as-iosched.c linux-2.6.5-rc1-mm2/drivers/block/as-iosched.c --- /opt/kernel/linux-2.6.5-rc1-mm2/drivers/block/as-iosched.c 2004-03-11 03:55:20.000000000 +0100 +++ linux-2.6.5-rc1-mm2/drivers/block/as-iosched.c 2004-03-19 15:19:44.507716180 +0100 @@ -1498,20 +1498,13 @@ struct as_data *ad = q->elevator.elevator_data; struct as_rq *arq = RQ_DATA(rq); - if (arq) { - if (arq->state != AS_RQ_PRESCHED) { - printk("arq->state: %d\n", arq->state); - WARN_ON(1); - } + if (arq) arq->state = AS_RQ_NEW; - } /* barriers must flush the reorder queue */ if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) - && where == ELEVATOR_INSERT_SORT)) { - WARN_ON(1); + && where == ELEVATOR_INSERT_SORT)) where = ELEVATOR_INSERT_BACK; - } switch (where) { case ELEVATOR_INSERT_BACK: @@ -1526,6 +1519,8 @@ break; case ELEVATOR_INSERT_FRONT: list_add(&rq->queuelist, ad->dispatch); + if (blk_fs_request(rq)) + ad->nr_dispatched++; as_antic_stop(ad); break; case ELEVATOR_INSERT_SORT: diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/drivers/block/ll_rw_blk.c linux-2.6.5-rc1-mm2/drivers/block/ll_rw_blk.c --- /opt/kernel/linux-2.6.5-rc1-mm2/drivers/block/ll_rw_blk.c 2004-03-19 15:13:57.651040352 +0100 +++ linux-2.6.5-rc1-mm2/drivers/block/ll_rw_blk.c 2004-03-19 15:31:52.678980227 +0100 @@ -255,6 +255,28 @@ EXPORT_SYMBOL(blk_queue_make_request); /** + * blk_queue_ordered - does this queue support ordered writes + * @q: the request queue + * @flag: see below + * + * Description: + * For journalled file systems, doing ordered writes on a commit + * block instead of explicitly doing wait_on_buffer (which is bad + * for performance) can be a big win. Block drivers supporting this + * feature should call this function and indicate so. + * + **/ +void blk_queue_ordered(request_queue_t *q, int flag) +{ + if (flag) + set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); + else + clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags); +} + +EXPORT_SYMBOL(blk_queue_ordered); + +/** * blk_queue_bounce_limit - set bounce buffer limit for queue * @q: the request queue for the device * @dma_addr: bus address limit @@ -1895,6 +1917,43 @@ EXPORT_SYMBOL(blk_execute_rq); +/* + * the idea here is to insert a SYNC_CACHE scsi command, and let lower layers + * transform it if they have to. two possible ways to fix this to work on + * dm/md: turns the last part of this into a queue ->issue_flush_fn() so + * drivers can implement, or + */ +int blkdev_issue_flush(struct block_device *bdev) +{ + request_queue_t *q; + struct request *rq; + int ret; + + if (bdev->bd_disk == NULL) + return -ENXIO; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + if (!q->request_fn) + return -EOPNOTSUPP; + + rq = blk_get_request(q, WRITE, __GFP_WAIT); + + memset(rq->cmd, 0, sizeof(rq->cmd)); + rq->cmd[0] = 0x35; + rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; + rq->data = NULL; + rq->cmd_len = 12; + rq->timeout = 60 * HZ; + + ret = blk_execute_rq(q, bdev->bd_disk, rq); + blk_put_request(rq); + return ret; +} + +EXPORT_SYMBOL(blkdev_issue_flush); + void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); @@ -1973,6 +2032,8 @@ if (unlikely(!q)) return; + + WARN_ON(!req->ref_count); if (unlikely(--req->ref_count)) return; @@ -2148,7 +2209,7 @@ static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err; sector_t sector; sector = bio->bi_sector; @@ -2166,9 +2227,11 @@ spin_lock_prefetch(q->queue_lock); - barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); - - ra = bio->bi_rw & (1 << BIO_RW_AHEAD); + barrier = bio_barrier(bio); + if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) { + err = -EOPNOTSUPP; + goto end_io; + } again: spin_lock_irq(q->queue_lock); @@ -2248,7 +2311,8 @@ /* * READA bit set */ - if (ra) + err = -EWOULDBLOCK; + if (bio_rw_ahead(bio)) goto end_io; freereq = get_request_wait(q, rw); @@ -2259,10 +2323,9 @@ req->flags |= REQ_CMD; /* - * inherit FAILFAST from bio and don't stack up - * retries for read ahead + * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST) */ - if (ra || test_bit(BIO_RW_FAILFAST, &bio->bi_rw)) + if (bio_rw_ahead(bio) || bio_failfast(bio)) req->flags |= REQ_FAILFAST; /* @@ -2300,7 +2363,7 @@ return 0; end_io: - bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK); + bio_endio(bio, nr_sectors << 9, err); return 0; } diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/drivers/ide/ide-disk.c linux-2.6.5-rc1-mm2/drivers/ide/ide-disk.c --- /opt/kernel/linux-2.6.5-rc1-mm2/drivers/ide/ide-disk.c 2004-03-19 15:13:51.959652420 +0100 +++ linux-2.6.5-rc1-mm2/drivers/ide/ide-disk.c 2004-03-19 15:19:44.511715746 +0100 @@ -1361,6 +1361,7 @@ static int write_cache (ide_drive_t *drive, int arg) { ide_task_t args; + int err; if (!(drive->id->cfs_enable_2 & 0x3000)) return 1; @@ -1371,7 +1372,10 @@ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; args.command_type = IDE_DRIVE_TASK_NO_DATA; args.handler = &task_no_data_intr; - (void) ide_raw_taskfile(drive, &args, NULL); + + err = ide_raw_taskfile(drive, &args, NULL); + if (err) + return err; drive->wcache = arg; return 0; @@ -1680,6 +1684,8 @@ if (drive->id->cfs_enable_2 & 0x3000) write_cache(drive, (id->cfs_enable_2 & 0x3000)); + blk_queue_ordered(drive->queue, 1); + #ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT if (drive->using_dma) __ide_dma_queued_on(drive); @@ -1728,10 +1734,14 @@ static int idedisk_open(struct inode *inode, struct file *filp) { ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; + u8 cf; + drive->usage++; - if (drive->removable && drive->usage == 1) { + if (drive->usage != 1) + return 0; + + if (drive->removable) { ide_task_t args; - u8 cf; memset(&args, 0, sizeof(ide_task_t)); args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; args.command_type = IDE_DRIVE_TASK_NO_DATA; @@ -1744,18 +1754,19 @@ */ if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; - drive->wcache = 0; - /* Cache enabled ? */ - if (drive->id->csfo & 1) - drive->wcache = 1; - /* Cache command set available ? */ - if (drive->id->cfs_enable_1 & (1<<5)) - drive->wcache = 1; - /* ATA6 cache extended commands */ - cf = drive->id->command_set_2 >> 24; - if((cf & 0xC0) == 0x40 && (cf & 0x30) != 0) - drive->wcache = 1; } + + drive->wcache = 0; + /* Cache enabled ? */ + if (drive->id->csfo & 1) + drive->wcache = 1; + /* Cache command set available ? */ + if (drive->id->cfs_enable_1 & (1<<5)) + drive->wcache = 1; + /* ATA6 cache extended commands */ + cf = drive->id->command_set_2 >> 24; + if((cf & 0xC0) == 0x40 && (cf & 0x30) != 0) + drive->wcache = 1; return 0; } diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/drivers/ide/ide-io.c linux-2.6.5-rc1-mm2/drivers/ide/ide-io.c --- /opt/kernel/linux-2.6.5-rc1-mm2/drivers/ide/ide-io.c 2004-03-19 15:13:51.961652204 +0100 +++ linux-2.6.5-rc1-mm2/drivers/ide/ide-io.c 2004-03-19 15:21:56.575403406 +0100 @@ -54,30 +54,84 @@ #include #include -/** - * ide_end_request - complete an IDE I/O - * @drive: IDE device for the I/O - * @uptodate: - * @nr_sectors: number of sectors completed - * - * This is our end_request wrapper function. We complete the I/O - * update random number input and dequeue the request, which if - * it was tagged may be out of order. +static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq) +{ + memset(drive->special_buf, 0, sizeof(drive->special_buf)); + + rq->flags &= ~REQ_BLOCK_PC; + rq->flags |= REQ_DRIVE_TASK | REQ_STARTED; + rq->buffer = drive->special_buf; + rq->buffer[0] = WIN_FLUSH_CACHE; + + if (drive->id->cfs_enable_2 & 0x2400) + rq->buffer[0] = WIN_FLUSH_CACHE_EXT; +} + +static int ide_transform_pc_req(ide_drive_t *drive, struct request *rq) +{ + if (rq->cmd[0] != 0x35) { + ide_end_request(drive, 0, 0); + return 1; + } + + if (!drive->wcache) { + ide_end_request(drive, 1, 0); + return 1; + } + + ide_fill_flush_cmd(drive, rq); + return 0; +} + +/* + * preempt pending requests, and store this cache flush for immediate + * execution */ - -int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +static struct request *ide_queue_flush_cmd(ide_drive_t *drive, + struct request *rq, int post) { - struct request *rq; - unsigned long flags; - int ret = 1; + struct request *flush_rq = &HWGROUP(drive)->wrq; - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; + /* + * write cache disabled, just return barrier write immediately + */ + if (!drive->wcache) + return rq; - BUG_ON(!(rq->flags & REQ_STARTED)); + /* + * if last rq issued was the post-flush, we can skip the pre-flush + */ +#if 0 + if (drive->last_rq_flush) { + rq->flags |= REQ_BAR_PREFLUSH; + return rq; + } +#endif - if (!nr_sectors) - nr_sectors = rq->hard_cur_sectors; + ide_init_drive_cmd(flush_rq); + ide_fill_flush_cmd(drive, flush_rq); + + flush_rq->special = rq; + flush_rq->nr_sectors = rq->nr_sectors; + + if (!post) { + drive->doing_barrier = 1; + flush_rq->flags |= REQ_BAR_PREFLUSH; + blkdev_dequeue_request(rq); + } else + flush_rq->flags |= REQ_BAR_POSTFLUSH; + + __elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0); + HWGROUP(drive)->rq = NULL; + return flush_rq; +} + +static int __ide_end_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + int ret = 1; + + BUG_ON(!(rq->flags & REQ_STARTED)); /* * if failfast is set on a request, override number of sectors and @@ -86,6 +140,9 @@ if (blk_noretry_request(rq) && !uptodate) nr_sectors = rq->hard_nr_sectors; + if (!blk_fs_request(rq) && !uptodate && !rq->errors) + rq->errors = -EIO; + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO @@ -97,14 +154,54 @@ if (!end_that_request_first(rq, uptodate, nr_sectors)) { add_disk_randomness(rq->rq_disk); - if (!blk_rq_tagged(rq)) - blkdev_dequeue_request(rq); - else + + if (blk_rq_tagged(rq)) blk_queue_end_tag(drive->queue, rq); - HWGROUP(drive)->rq = NULL; + + blkdev_dequeue_request(rq); end_that_request_last(rq); + HWGROUP(drive)->rq = NULL; ret = 0; } + + return ret; +} + +/** + * ide_end_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * This is our end_request wrapper function. We complete the I/O + * update random number input and dequeue the request, which if + * it was tagged may be out of order. + */ + +int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + rq = HWGROUP(drive)->rq; + + if (!nr_sectors) + nr_sectors = rq->hard_cur_sectors; + + if (!blk_barrier_rq(rq)) + ret = __ide_end_request(drive, rq, uptodate, nr_sectors); + else { + struct request *flush_rq = &HWGROUP(drive)->wrq; + + flush_rq->nr_sectors -= nr_sectors; + if (!flush_rq->nr_sectors) { + ide_queue_flush_cmd(drive, rq, 1); + ret = 0; + } + } + spin_unlock_irqrestore(&ide_lock, flags); return ret; } @@ -140,6 +237,97 @@ spin_unlock_irqrestore(&ide_lock, flags); } +/* + * FIXME: probably move this somewhere else, name is bad too :) + */ +static sector_t ide_get_error_location(ide_drive_t *drive, char *args) +{ + u32 high, low; + u8 hcyl, lcyl, sect; + sector_t sector; + + high = 0; + hcyl = args[5]; + lcyl = args[4]; + sect = args[3]; + + if (drive->id->cfs_enable_2 & 0x2400) { + low = (hcyl << 16) | (lcyl << 8) | sect; + HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + } else { + u8 cur = HWIF(drive)->INB(IDE_SELECT_REG); + if (cur & 0x40) + low = (hcyl << 16) | (lcyl << 8) | sect; + else { + low = hcyl * drive->head * drive->sect; + low += lcyl * drive->sect; + low += sect - 1; + } + } + + sector = ((sector_t) high << 24) | low; + return sector; +} + +static void ide_complete_barrier(ide_drive_t *drive, struct request *rq, + int error) +{ + struct request *real_rq = rq->special; + int good_sectors, bad_sectors; + sector_t sector; + + if (!error) { + if (blk_barrier_postflush(rq)) { + /* + * this completes the barrier write + */ + __ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors); + drive->doing_barrier = 0; + drive->last_rq_flush = 1; + } else { + /* + * just indicate that we did the pre flush + */ + real_rq->flags |= REQ_BAR_PREFLUSH; + __elv_add_request(drive->queue, real_rq, ELEVATOR_INSERT_FRONT, 0); + } + +#ifdef IDE_DUMP_FLUSH_TIMINGS + printk("%s: %sflush took %lu jiffies\n", drive->name, blk_barrier_postflush(rq) ? "post" : "pre", jiffies - rq->timeout); +#endif + + /* + * all is fine, return + */ + return; + } + + /* + * bummer, flush failed. if it was the pre-flush, fail the barrier. + * if it was the post-flush, complete the succesful part of the request + * and fail the rest + */ + good_sectors = 0; + if (blk_barrier_postflush(rq)) { + sector = ide_get_error_location(drive, rq->buffer); + + if ((sector >= real_rq->hard_sector) && + (sector < real_rq->hard_sector + real_rq->hard_nr_sectors)) + good_sectors = sector - real_rq->hard_sector; + } else + sector = real_rq->hard_sector; + + bad_sectors = real_rq->hard_nr_sectors - good_sectors; + if (good_sectors) + __ide_end_request(drive, real_rq, 1, good_sectors); + if (bad_sectors) + __ide_end_request(drive, real_rq, 0, bad_sectors); + + printk(KERN_ERR "%s: failed barrier write: sector=%Lx(good=%d/bad=%d)\n", drive->name, sector, good_sectors, bad_sectors); + blk_queue_ordered(drive->queue, 0); +} + /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -229,6 +417,10 @@ spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); + + if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq)) + ide_complete_barrier(drive, rq, err); + HWGROUP(drive)->rq = NULL; end_that_request_last(rq); spin_unlock_irqrestore(&ide_lock, flags); @@ -610,6 +802,16 @@ if (drive->suspend_reset) goto kill_rq; + /* + * basic transformation support for scsi -> ata commands + */ + if (blk_pc_request(rq)) { + if (drive->media != ide_disk) + goto kill_rq; + if (ide_transform_pc_req(drive, rq)) + return ide_stopped; + } + block = rq->sector; if (blk_fs_request(rq) && (drive->media == ide_disk || drive->media == ide_floppy)) { @@ -715,6 +917,15 @@ repeat: best = NULL; drive = hwgroup->drive; + + /* + * drive is doing pre-flush, ordered write, post-flush sequence. even + * though that is 3 requests, it must be seen as a single transaction. + * we must not preempt this drive until that is complete + */ + if (drive->doing_barrier) + return drive; + do { if ((!drive->sleep || time_after_eq(jiffies, drive->sleep)) && !elv_queue_empty(drive->queue)) { @@ -882,6 +1093,15 @@ } /* + * if rq is a barrier write, issue pre cache flush if not + * already done + */ + if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq)) + rq = ide_queue_flush_cmd(drive, rq, 0); + + drive->last_rq_flush = 0; + + /* * Sanity: don't accept a request that isn't a PM request * if we are currently power managed. This is very important as * blk_stop_queue() doesn't prevent the elv_next_request() @@ -900,6 +1120,10 @@ break; } + /* + * we can only queue read-write requests, so let the drive + * queue drain before continuing with this command. + */ if (!rq->bio && ata_pending_commands(drive)) break; @@ -1305,6 +1529,7 @@ { memset(rq, 0, sizeof(*rq)); rq->flags = REQ_DRIVE_CMD; + rq->ref_count = 1; } EXPORT_SYMBOL(ide_init_drive_cmd); diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/fs/buffer.c linux-2.6.5-rc1-mm2/fs/buffer.c --- /opt/kernel/linux-2.6.5-rc1-mm2/fs/buffer.c 2004-03-19 15:13:58.206980564 +0100 +++ linux-2.6.5-rc1-mm2/fs/buffer.c 2004-03-19 15:23:27.195593603 +0100 @@ -2707,6 +2707,9 @@ if (rw == READ && buffer_dirty(bh)) buffer_error(); + if (buffer_ordered(bh) && (rw == WRITE)) + rw = WRITE_BARRIER; + /* Only clear out a write error when rewriting */ if (test_set_buffer_req(bh) && rw == WRITE) clear_buffer_write_io_error(bh); diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/bio.h linux-2.6.5-rc1-mm2/include/linux/bio.h --- /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/bio.h 2004-03-19 15:13:58.327967553 +0100 +++ linux-2.6.5-rc1-mm2/include/linux/bio.h 2004-03-19 15:18:09.358961566 +0100 @@ -140,6 +140,8 @@ #define bio_cur_sectors(bio) (bio_iovec(bio)->bv_len >> 9) #define bio_data(bio) (page_address(bio_page((bio))) + bio_offset((bio))) #define bio_barrier(bio) ((bio)->bi_rw & (1 << BIO_RW_BARRIER)) +#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST)) +#define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD)) #define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC)) /* diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/blkdev.h linux-2.6.5-rc1-mm2/include/linux/blkdev.h --- /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/blkdev.h 2004-03-19 15:13:58.328967445 +0100 +++ linux-2.6.5-rc1-mm2/include/linux/blkdev.h 2004-03-19 15:19:44.516715204 +0100 @@ -195,6 +195,8 @@ __REQ_PM_SUSPEND, /* suspend request */ __REQ_PM_RESUME, /* resume request */ __REQ_PM_SHUTDOWN, /* shutdown request */ + __REQ_BAR_PREFLUSH, /* barrier pre-flush done */ + __REQ_BAR_POSTFLUSH, /* barrier post-flush */ __REQ_NR_BITS, /* stops here */ }; @@ -220,6 +222,8 @@ #define REQ_PM_SUSPEND (1 << __REQ_PM_SUSPEND) #define REQ_PM_RESUME (1 << __REQ_PM_RESUME) #define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN) +#define REQ_BAR_PREFLUSH (1 << __REQ_BAR_PREFLUSH) +#define REQ_BAR_POSTFLUSH (1 << __REQ_BAR_POSTFLUSH) /* * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME @@ -371,6 +375,7 @@ #define QUEUE_FLAG_DEAD 5 /* queue being torn down */ #define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */ #define QUEUE_FLAG_PLUGGED 7 /* queue is plugged */ +#define QUEUE_FLAG_ORDERED 8 /* supports ordered writes */ #define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags) #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) @@ -386,6 +391,10 @@ #define blk_pm_request(rq) \ ((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME)) +#define blk_barrier_rq(rq) ((rq)->flags & REQ_HARDBARRIER) +#define blk_barrier_preflush(rq) ((rq)->flags & REQ_BAR_PREFLUSH) +#define blk_barrier_postflush(rq) ((rq)->flags & REQ_BAR_POSTFLUSH) + #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) #define rq_data_dir(rq) ((rq)->flags & 1) @@ -583,6 +592,7 @@ 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_ordered(request_queue_t *, int); extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *); extern void blk_dump_rq_flags(struct request *, char *); @@ -610,6 +620,7 @@ extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); extern void blk_rq_prep_restart(struct request *); +extern int blkdev_issue_flush(struct block_device *); #define MAX_PHYS_SEGMENTS 128 #define MAX_HW_SEGMENTS 128 diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/buffer_head.h linux-2.6.5-rc1-mm2/include/linux/buffer_head.h --- /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/buffer_head.h 2004-03-11 03:55:21.000000000 +0100 +++ linux-2.6.5-rc1-mm2/include/linux/buffer_head.h 2004-03-19 15:19:44.517715095 +0100 @@ -26,6 +26,7 @@ BH_Delay, /* Buffer is not yet allocated on disk */ BH_Boundary, /* Block is followed by a discontiguity */ BH_Write_EIO, /* I/O error on write */ + BH_Ordered, /* ordered write */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -117,7 +118,8 @@ BUFFER_FNS(Async_Write, async_write) BUFFER_FNS(Delay, delay) BUFFER_FNS(Boundary, boundary) -BUFFER_FNS(Write_EIO,write_io_error) +BUFFER_FNS(Write_EIO, write_io_error) +BUFFER_FNS(Ordered, ordered) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) #define touch_buffer(bh) mark_page_accessed(bh->b_page) diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/fs.h linux-2.6.5-rc1-mm2/include/linux/fs.h --- /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/fs.h 2004-03-19 15:13:58.337966477 +0100 +++ linux-2.6.5-rc1-mm2/include/linux/fs.h 2004-03-19 15:19:19.099456226 +0100 @@ -85,6 +85,7 @@ #define SPECIAL 4 /* For non-blockdevice requests in request queue */ #define READ_SYNC (READ | (1 << BIO_RW_SYNC)) #define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC)) +#define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER)) #define SEL_IN 1 #define SEL_OUT 2 diff -ur -X /home/axboe/cdrom/exclude /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/ide.h linux-2.6.5-rc1-mm2/include/linux/ide.h --- /opt/kernel/linux-2.6.5-rc1-mm2/include/linux/ide.h 2004-03-19 15:13:58.339966262 +0100 +++ linux-2.6.5-rc1-mm2/include/linux/ide.h 2004-03-19 15:19:44.518714987 +0100 @@ -732,6 +732,8 @@ u8 bios_head; /* BIOS/fdisk/LILO number of heads */ u8 bios_sect; /* BIOS/fdisk/LILO sectors per track */ u8 queue_depth; /* max queue depth */ + u8 doing_barrier; /* state, 1=currently doing flush */ + u8 last_rq_flush; /* last rq was a flush */ unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ @@ -744,6 +746,7 @@ int lun; /* logical unit */ int crc_count; /* crc counter to reduce drive speed */ + char special_buf[8]; /* private command buffer */ struct list_head list; struct device gendev; struct semaphore gendev_rel_sem; /* to deal with device release() */