scsi/sata write barrier support
Subsystems (2)
PATCH 1/1 scsi/sata write barrier support
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata. It prepares to support barriers with 'real' SCSI hardware that can do ordered tags as well, but it isn't done. The remaining work is to check error handling for reordering on requeue (probably fine), and add the few lines of support to each hba lld to set ->ordered_tag in the host template and be able to set the ordered tag bit on commands that are blk_barrier_rq().
A note on this patch. For write barriers, the PATA drivers issued a pre and post flush when seeing a barrier write. This ensures that dirty data in cache is on platter before the barrier, and that later writers don't go to platter before the barrier. The handling of this was done in drivers/ide core, which was a little nasty because some of it is a bit tricky block layer code. This patch moves the handling of this into the block layer, the only real change needed in drivers (scsi mid layer and drivers/ide) is to delay completion of the real barrier write until the post flush has completed. See scsi_io_completion() and ide_end_request().
So the patch removes a lot of drivers/ide cruft and special casing, which is always good. It relies on a seperate patch that adds an end_io function to struct request, it's folded into this one right now. bsg needs this as well, and the multipath folks need it too. I might submit that seperately first.
Please test! Patch is against current BK.
drivers/block/cfq-iosched.c renamed from opt/kernel/linux-2.6.10/drivers/block/cfq-iosched.c +4 -4
@@ -1285,19 +1285,19 @@ static int cfq_queue_empty(request_queuestatic void cfq_completed_request (request_queue_t *q,struct request *rq) {struct cfq_rq *crq =RQ_DATA (rq); +struct cfq_queue *cfqq;if (unlikely (!blk_fs_request (rq)))return ; -if (crq->in_flight) { -struct cfq_queue *cfqq = crq->cfq_queue; + cfqq = crq->cfq_queue; +if (crq->in_flight) {WARN_ON (!cfqq->in_flight); cfqq->in_flight--; - -cfq_account_completion (cfqq, crq); } +cfq_account_completion (cfqq, crq); } static struct request *
drivers/block/elevator.c renamed from opt/kernel/linux-2.6.10/drivers/block/elevator.c +15 -1
@@ -320,7 +320,21 @@ void elv_add_request(request_queue_t *q,static inline struct request *__elv_next_request (request_queue_t *q) { -return q->elevator->ops->elevator_next_req_fn (q); +struct request *rq = q->elevator->ops->elevator_next_req_fn (q); + +/* +* if this is a barrier write and the device has to issue a +* flush sequence to support it, check how far we are +*/ +if (rq &&blk_fs_request (rq) &&blk_barrier_rq (rq)) { +BUG_ON (q->ordered ==QUEUE_ORDERED_NONE ); + +if (q->ordered ==QUEUE_ORDERED_FLUSH && + !blk_barrier_preflush (rq)) + rq =blk_start_pre_flush (q, rq); + } + +return rq; }struct request *elv_next_request (request_queue_t *q)
drivers/block/ll_rw_blk.c renamed from opt/kernel/linux-2.6.10/drivers/block/ll_rw_blk.c +170 -27
264 lines not on this page · raw message
drivers/block/paride/pd.c renamed from opt/kernel/linux-2.6.10/drivers/block/paride/pd.c +1 -0
@@ -743,6 +743,7 @@ static int pd_special_command(struct pd_ rq.rq_disk = disk->gd; rq.ref_count =1 ; rq.waiting = &wait; + rq.end_io = blk_end_sync_rq;blk_insert_request (disk->gd->queue, &rq,0 , func,0 );wait_for_completion (&wait); rq.waiting =NULL ;
drivers/ide/ide-disk.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-disk.c +65 -8
99 lines not on this page · raw message
drivers/ide/ide-io.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-io.c +23 -151
224 lines not on this page · raw message
drivers/ide/ide-tape.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-tape.c +1 -0
@@ -2720,6 +2720,7 @@ static void idetape_wait_for_request (id }#endif /* IDETAPE_DEBUG_BUGS */ rq->waiting = &wait; + rq->end_io = blk_end_sync_rq;spin_unlock_irq (&tape->spinlock);wait_for_completion (&wait);/* The stage and its struct request have been deallocated */
drivers/scsi/ahci.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/ahci.c +1 -0
@@ -198,6 +198,7 @@ static Scsi_Host_Template ahci_sht = { .dma_boundary = AHCI_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations ahci_ops = {
drivers/scsi/ata_piix.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/ata_piix.c +1 -0
@@ -121,6 +121,7 @@ static Scsi_Host_Template piix_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations piix_pata_ops = {
drivers/scsi/hosts.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/hosts.c +10 -0
@@ -258,6 +258,16 @@ struct Scsi_Host *scsi_host_alloc(struct shost->cmd_per_lun = sht->cmd_per_lun; shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; + shost->ordered_flush = sht->ordered_flush; + shost->ordered_tag = sht->ordered_tag; + +/* +* hosts/devices that do queueing must support ordered tags +*/ +if (shost->can_queue >1 && shost->ordered_flush) { +printk (KERN_ERR "scsi: ordered flushes don't support queueing\n" ); + shost->ordered_flush =0 ; + }if (sht->max_host_blocked) shost->max_host_blocked = sht->max_host_blocked;
drivers/scsi/sata_nv.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_nv.c +1 -0
@@ -194,6 +194,7 @@ static Scsi_Host_Template nv_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations nv_ops = {
drivers/scsi/sata_promise.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_promise.c +1 -0
@@ -102,6 +102,7 @@ static Scsi_Host_Template pdc_ata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations pdc_ata_ops = {
drivers/scsi/sata_sil.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sil.c +1 -0
@@ -123,6 +123,7 @@ static Scsi_Host_Template sil_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations sil_ops = {
drivers/scsi/sata_sis.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sis.c +1 -0
@@ -90,6 +90,7 @@ static Scsi_Host_Template sis_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations sis_ops = {
drivers/scsi/sata_svw.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_svw.c +1 -0
@@ -288,6 +288,7 @@ static Scsi_Host_Template k2_sata_sht = .proc_info = k2_sata_proc_info, #endif .bios_param = ata_std_bios_param, + .ordered_flush = 1, };
drivers/scsi/sata_sx4.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sx4.c +1 -0
@@ -188,6 +188,7 @@ static Scsi_Host_Template pdc_sata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations pdc_20621_ops = {
drivers/scsi/sata_uli.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_uli.c +1 -0
@@ -82,6 +82,7 @@ static Scsi_Host_Template uli_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations uli_ops = {
drivers/scsi/sata_via.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_via.c +1 -0
@@ -95,6 +95,7 @@ static Scsi_Host_Template svia_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations svia_sata_ops = {
drivers/scsi/sata_vsc.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_vsc.c +1 -0
@@ -204,6 +204,7 @@ static Scsi_Host_Template vsc_sata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };
drivers/scsi/scsi_lib.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/scsi_lib.c +69 -0
93 lines not on this page · raw message
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +31 -0
@@ -121,6 +121,8 @@ static void sd_shutdown(struct device *dstatic void sd_rescan (struct device *);static int sd_init_command (struct scsi_cmnd *);static int sd_issue_flush (struct device *,sector_t *); +static void sd_end_flush (request_queue_t *,struct request *); +static int sd_prepare_flush (request_queue_t *,struct request *);static void sd_read_capacity (struct scsi_disk *sdkp,char *diskname,struct scsi_request *SRpnt,unsigned char *buffer);
@@ -135,6 +137,8 @@ static struct scsi_driver sd_template = .rescan = sd_rescan, .init_command = sd_init_command, .issue_flush = sd_issue_flush, + .prepare_flush = sd_prepare_flush, + .end_flush = sd_end_flush, };/*
@@ -734,6 +738,33 @@ static int sd_issue_flush(struct devicereturn sd_sync_cache (sdp); } +static void sd_end_flush (request_queue_t *q,struct request *flush_rq) +{ +struct request *rq = flush_rq->end_io_data; +struct scsi_cmnd *cmd = rq->special; +unsigned int bytes = rq->hard_nr_sectors <<9 ; + +if (!flush_rq->errors) +scsi_io_completion (cmd, bytes,0 ); +else +scsi_io_completion (cmd,0 , bytes); +} + +static int sd_prepare_flush (request_queue_t *q,struct request *rq) +{ +struct scsi_device *sdev = q->queuedata; +struct scsi_disk *sdkp =dev_get_drvdata (&sdev->sdev_gendev); + +if (sdkp->WCE) { +memset (rq->cmd,0 ,sizeof (rq->cmd)); + rq->flags =REQ_BLOCK_PC |REQ_SOFTBARRIER ; + rq->cmd[0 ] =SYNCHRONIZE_CACHE ; +return 1 ; + } + +return 0 ; +} +static void sd_rescan (struct device *dev) {struct scsi_disk *sdkp =dev_get_drvdata (dev);
include/linux/blkdev.h renamed from opt/kernel/linux-2.6.10/include/linux/blkdev.h +32 -3
@@ -93,6 +93,9 @@ struct io_context *get_io_context(int gfvoid copy_io_context (struct io_context **pdst,struct io_context **psrc);void swap_io_context (struct io_context **ioc1,struct io_context **ioc2); +struct request ; +typedef void (rq_end_io_fn )(struct request *); +struct request_list {int count[2 ];int starved[2 ];
@@ -176,6 +179,12 @@ struct request {* For Power Management requests */ struct request_pm_state *pm; + +/* +* completion callback. end_io_data should be folded in with waiting +*/ +rq_end_io_fn *end_io; +void *end_io_data; };/*
@@ -266,6 +275,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 int (issue_flush_fn ) (request_queue_t *,struct gendisk *,sector_t *); +typedef int (prepare_flush_fn ) (request_queue_t *,struct request *); +typedef void (end_flush_fn ) (request_queue_t *,struct request *);enum blk_queue_state { Queue_down,
@@ -309,6 +320,8 @@ struct request_queuemerge_bvec_fn *merge_bvec_fn;activity_fn *activity_fn;issue_flush_fn *issue_flush_fn; +prepare_flush_fn *prepare_flush_fn; +end_flush_fn *end_flush_fn;/* * Auto-unplugging state
@@ -380,6 +393,18 @@ struct request_queueunsigned int sg_reserved_size;struct list_head drain_list; + +/* +* reserved for flush operations +*/ +struct request *flush_rq; +unsigned char ordered; +}; + +enum { +QUEUE_ORDERED_NONE , +QUEUE_ORDERED_TAG , +QUEUE_ORDERED_FLUSH , };#define RQ_INACTIVE (-1)
@@ -396,12 +421,13 @@ struct request_queue#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 QUEUE_FLAG_DRAIN 9/* draining queue for sched switch */ +#define QUEUE_FLAG_DRAIN 8/* draining queue for sched switch */ +#define QUEUE_FLAG_FLUSH 9/* doing barrier flush sequence */ #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)#define blk_queue_stopped (q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) +#define blk_queue_flush (q) test_bit(QUEUE_FLAG_FLUSH, &(q)->queue_flags)#define blk_fs_request (rq) ((rq)->flags & REQ_CMD)#define blk_pc_request (rq) ((rq)->flags & REQ_BLOCK_PC)
@@ -509,10 +535,10 @@ extern void blk_unregister_queue(structextern void register_disk (struct gendisk *dev);extern void generic_make_request (struct bio *bio);extern void blk_put_request (struct request *); +extern void blk_end_sync_rq (struct request *rq);extern void blk_attempt_remerge (request_queue_t *,struct request *);extern void __blk_attempt_remerge (request_queue_t *,struct request *);extern struct request *blk_get_request (request_queue_t *,int ,int ); -extern void blk_put_request (struct request *);extern void blk_insert_request (request_queue_t *,struct request *,int ,void *,int );extern void blk_requeue_request (request_queue_t *,struct request *);extern void blk_plug_device (request_queue_t *);
@@ -602,6 +628,9 @@ extern struct backing_dev_info *blk_get_extern void blk_queue_ordered (request_queue_t *,int );extern void blk_queue_issue_flush_fn (request_queue_t *,issue_flush_fn *);extern int blkdev_scsi_issue_flush_fn (request_queue_t *,struct gendisk *,sector_t *); +extern void blk_start_post_flush (request_queue_t *,struct request *); +extern struct request *blk_start_pre_flush (request_queue_t *,struct request *); +extern int blk_check_end_barrier (request_queue_t *,struct request *,int );extern int blk_rq_map_sg (request_queue_t *,struct request *,struct scatterlist *);extern void blk_dump_rq_flags (struct request *,char *);
include/linux/ide.h renamed from opt/kernel/linux-2.6.10/include/linux/ide.h +1 -1
@@ -743,7 +743,6 @@ typedef struct ide_drive_s {u8 sect;/* "real" sectors per track */ u8 bios_head;/* BIOS/fdisk/LILO number of heads */ u8 bios_sect;/* BIOS/fdisk/LILO sectors per track */ -u8 doing_barrier;/* state, 1=currently doing flush */ unsigned int bios_cyl;/* BIOS/fdisk/LILO number of cyls */ unsigned int cyl;/* "real" number of cyls */
@@ -1131,6 +1130,7 @@ extern ide_hwif_t ide_hwifs[]; /* masteextern int noautodma;extern int ide_end_request (ide_drive_t *drive,int uptodate,int nrsecs); +extern int __ide_end_request (ide_drive_t *drive,struct request *rq,int uptodate,int nrsecs);/* * This is used on exit from the driver to designate the next irq handler
include/scsi/scsi_driver.h renamed from opt/kernel/linux-2.6.10/include/scsi/scsi_driver.h +2 -0
@@ -14,6 +14,8 @@ struct scsi_driver {int (*init_command)(struct scsi_cmnd *);void (*rescan)(struct device *);int (*issue_flush)(struct device *,sector_t *); +int (*prepare_flush)(struct request_queue *,struct request *); +void (*end_flush)(struct request_queue *,struct request *); };#define to_scsi_driver (drv) \ container_of((drv), struct scsi_driver, gendrv)
include/scsi/scsi_host.h renamed from opt/kernel/linux-2.6.10/include/scsi/scsi_host.h +12 -0
@@ -352,6 +352,12 @@ struct scsi_host_template { unsigned skip_settle_delay:1;/* +* ordered write support +*/ + unsigned ordered_flush:1; + unsigned ordered_tag:1; + +/* * Countdown for host blocking with no commands outstanding */ unsigned int max_host_blocked;
@@ -491,6 +497,12 @@ struct Scsi_Host { unsigned reverse_ordering:1;/* +* ordered write support +*/ + unsigned ordered_flush:1; + unsigned ordered_tag:1; + +/* * Host has rejected a command because it was busy. */ unsigned int host_blocked;
Signature · 1 line
Jens Axboe
PATCH 1/1 scsi/sata write barrier support #2
Hi,
A few changes:
- Cleanup up the driver additions even more, blk_complete_barrier_rq() does all the work now.
- Fixed up the exports
- Comment functions
- Fixed a bug with SCSI and write back caching disabled
- Rename blk_queue_flush() to blk_queue_flushing() to indicate it's a state
drivers/block/cfq-iosched.c renamed from opt/kernel/linux-2.6.10/drivers/block/cfq-iosched.c +4 -4
@@ -1285,19 +1285,19 @@ static int cfq_queue_empty(request_queuestatic void cfq_completed_request (request_queue_t *q,struct request *rq) {struct cfq_rq *crq =RQ_DATA (rq); +struct cfq_queue *cfqq;if (unlikely (!blk_fs_request (rq)))return ; -if (crq->in_flight) { -struct cfq_queue *cfqq = crq->cfq_queue; + cfqq = crq->cfq_queue; +if (crq->in_flight) {WARN_ON (!cfqq->in_flight); cfqq->in_flight--; - -cfq_account_completion (cfqq, crq); } +cfq_account_completion (cfqq, crq); } static struct request *
drivers/block/elevator.c renamed from opt/kernel/linux-2.6.10/drivers/block/elevator.c +15 -1
@@ -320,7 +320,21 @@ void elv_add_request(request_queue_t *q,static inline struct request *__elv_next_request (request_queue_t *q) { -return q->elevator->ops->elevator_next_req_fn (q); +struct request *rq = q->elevator->ops->elevator_next_req_fn (q); + +/* +* if this is a barrier write and the device has to issue a +* flush sequence to support it, check how far we are +*/ +if (rq &&blk_fs_request (rq) &&blk_barrier_rq (rq)) { +BUG_ON (q->ordered ==QUEUE_ORDERED_NONE ); + +if (q->ordered ==QUEUE_ORDERED_FLUSH && + !blk_barrier_preflush (rq)) + rq =blk_start_pre_flush (q, rq); + } + +return rq; }struct request *elv_next_request (request_queue_t *q)
drivers/block/ll_rw_blk.c renamed from opt/kernel/linux-2.6.10/drivers/block/ll_rw_blk.c +231 -27
325 lines not on this page · raw message
drivers/block/paride/pd.c renamed from opt/kernel/linux-2.6.10/drivers/block/paride/pd.c +1 -0
@@ -743,6 +743,7 @@ static int pd_special_command(struct pd_ rq.rq_disk = disk->gd; rq.ref_count =1 ; rq.waiting = &wait; + rq.end_io = blk_end_sync_rq;blk_insert_request (disk->gd->queue, &rq,0 , func,0 );wait_for_completion (&wait); rq.waiting =NULL ;
drivers/ide/ide-disk.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-disk.c +65 -8
99 lines not on this page · raw message
drivers/ide/ide-io.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-io.c +9 -151
210 lines not on this page · raw message
drivers/ide/ide-tape.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-tape.c +1 -0
@@ -2720,6 +2720,7 @@ static void idetape_wait_for_request (id }#endif /* IDETAPE_DEBUG_BUGS */ rq->waiting = &wait; + rq->end_io = blk_end_sync_rq;spin_unlock_irq (&tape->spinlock);wait_for_completion (&wait);/* The stage and its struct request have been deallocated */
drivers/scsi/ahci.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/ahci.c +1 -0
@@ -198,6 +198,7 @@ static Scsi_Host_Template ahci_sht = { .dma_boundary = AHCI_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations ahci_ops = {
drivers/scsi/ata_piix.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/ata_piix.c +1 -0
@@ -121,6 +121,7 @@ static Scsi_Host_Template piix_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations piix_pata_ops = {
drivers/scsi/hosts.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/hosts.c +10 -0
@@ -258,6 +258,16 @@ struct Scsi_Host *scsi_host_alloc(struct shost->cmd_per_lun = sht->cmd_per_lun; shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; + shost->ordered_flush = sht->ordered_flush; + shost->ordered_tag = sht->ordered_tag; + +/* +* hosts/devices that do queueing must support ordered tags +*/ +if (shost->can_queue >1 && shost->ordered_flush) { +printk (KERN_ERR "scsi: ordered flushes don't support queueing\n" ); + shost->ordered_flush =0 ; + }if (sht->max_host_blocked) shost->max_host_blocked = sht->max_host_blocked;
drivers/scsi/sata_nv.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_nv.c +1 -0
@@ -194,6 +194,7 @@ static Scsi_Host_Template nv_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations nv_ops = {
drivers/scsi/sata_promise.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_promise.c +1 -0
@@ -102,6 +102,7 @@ static Scsi_Host_Template pdc_ata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations pdc_ata_ops = {
drivers/scsi/sata_sil.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sil.c +1 -0
@@ -123,6 +123,7 @@ static Scsi_Host_Template sil_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations sil_ops = {
drivers/scsi/sata_sis.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sis.c +1 -0
@@ -90,6 +90,7 @@ static Scsi_Host_Template sis_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations sis_ops = {
drivers/scsi/sata_svw.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_svw.c +1 -0
@@ -288,6 +288,7 @@ static Scsi_Host_Template k2_sata_sht = .proc_info = k2_sata_proc_info, #endif .bios_param = ata_std_bios_param, + .ordered_flush = 1, };
drivers/scsi/sata_sx4.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sx4.c +1 -0
@@ -188,6 +188,7 @@ static Scsi_Host_Template pdc_sata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations pdc_20621_ops = {
drivers/scsi/sata_uli.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_uli.c +1 -0
@@ -82,6 +82,7 @@ static Scsi_Host_Template uli_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations uli_ops = {
drivers/scsi/sata_via.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_via.c +1 -0
@@ -95,6 +95,7 @@ static Scsi_Host_Template svia_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations svia_sata_ops = {
drivers/scsi/sata_vsc.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_vsc.c +1 -0
@@ -204,6 +204,7 @@ static Scsi_Host_Template vsc_sata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };
drivers/scsi/scsi_lib.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/scsi_lib.c +46 -0
64 lines not on this page · raw message
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +31 -0
@@ -121,6 +121,8 @@ static void sd_shutdown(struct device *dstatic void sd_rescan (struct device *);static int sd_init_command (struct scsi_cmnd *);static int sd_issue_flush (struct device *,sector_t *); +static void sd_end_flush (request_queue_t *,struct request *); +static int sd_prepare_flush (request_queue_t *,struct request *);static void sd_read_capacity (struct scsi_disk *sdkp,char *diskname,struct scsi_request *SRpnt,unsigned char *buffer);
@@ -135,6 +137,8 @@ static struct scsi_driver sd_template = .rescan = sd_rescan, .init_command = sd_init_command, .issue_flush = sd_issue_flush, + .prepare_flush = sd_prepare_flush, + .end_flush = sd_end_flush, };/*
@@ -734,6 +738,33 @@ static int sd_issue_flush(struct devicereturn sd_sync_cache (sdp); } +static void sd_end_flush (request_queue_t *q,struct request *flush_rq) +{ +struct request *rq = flush_rq->end_io_data; +struct scsi_cmnd *cmd = rq->special; +unsigned int bytes = rq->hard_nr_sectors <<9 ; + +if (!flush_rq->errors) +scsi_io_completion (cmd, bytes,0 ); +else +scsi_io_completion (cmd,0 , bytes); +} + +static int sd_prepare_flush (request_queue_t *q,struct request *rq) +{ +struct scsi_device *sdev = q->queuedata; +struct scsi_disk *sdkp =dev_get_drvdata (&sdev->sdev_gendev); + +if (sdkp->WCE) { +memset (rq->cmd,0 ,sizeof (rq->cmd)); + rq->flags =REQ_BLOCK_PC |REQ_SOFTBARRIER ; + rq->cmd[0 ] =SYNCHRONIZE_CACHE ; +return 1 ; + } + +return 0 ; +} +static void sd_rescan (struct device *dev) {struct scsi_disk *sdkp =dev_get_drvdata (dev);
include/linux/blkdev.h renamed from opt/kernel/linux-2.6.10/include/linux/blkdev.h +32 -3
@@ -93,6 +93,9 @@ struct io_context *get_io_context(int gfvoid copy_io_context (struct io_context **pdst,struct io_context **psrc);void swap_io_context (struct io_context **ioc1,struct io_context **ioc2); +struct request ; +typedef void (rq_end_io_fn )(struct request *); +struct request_list {int count[2 ];int starved[2 ];
@@ -176,6 +179,12 @@ struct request {* For Power Management requests */ struct request_pm_state *pm; + +/* +* completion callback. end_io_data should be folded in with waiting +*/ +rq_end_io_fn *end_io; +void *end_io_data; };/*
@@ -266,6 +275,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 int (issue_flush_fn ) (request_queue_t *,struct gendisk *,sector_t *); +typedef int (prepare_flush_fn ) (request_queue_t *,struct request *); +typedef void (end_flush_fn ) (request_queue_t *,struct request *);enum blk_queue_state { Queue_down,
@@ -309,6 +320,8 @@ struct request_queuemerge_bvec_fn *merge_bvec_fn;activity_fn *activity_fn;issue_flush_fn *issue_flush_fn; +prepare_flush_fn *prepare_flush_fn; +end_flush_fn *end_flush_fn;/* * Auto-unplugging state
@@ -380,6 +393,18 @@ struct request_queueunsigned int sg_reserved_size;struct list_head drain_list; + +/* +* reserved for flush operations +*/ +struct request *flush_rq; +unsigned char ordered; +}; + +enum { +QUEUE_ORDERED_NONE , +QUEUE_ORDERED_TAG , +QUEUE_ORDERED_FLUSH , };#define RQ_INACTIVE (-1)
@@ -396,12 +421,13 @@ struct request_queue#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 QUEUE_FLAG_DRAIN 9/* draining queue for sched switch */ +#define QUEUE_FLAG_DRAIN 8/* draining queue for sched switch */ +#define QUEUE_FLAG_FLUSH 9/* doing barrier flush sequence */ #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)#define blk_queue_stopped (q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) +#define blk_queue_flushing (q) test_bit(QUEUE_FLAG_FLUSH, &(q)->queue_flags)#define blk_fs_request (rq) ((rq)->flags & REQ_CMD)#define blk_pc_request (rq) ((rq)->flags & REQ_BLOCK_PC)
@@ -509,10 +535,10 @@ extern void blk_unregister_queue(structextern void register_disk (struct gendisk *dev);extern void generic_make_request (struct bio *bio);extern void blk_put_request (struct request *); +extern void blk_end_sync_rq (struct request *rq);extern void blk_attempt_remerge (request_queue_t *,struct request *);extern void __blk_attempt_remerge (request_queue_t *,struct request *);extern struct request *blk_get_request (request_queue_t *,int ,int ); -extern void blk_put_request (struct request *);extern void blk_insert_request (request_queue_t *,struct request *,int ,void *,int );extern void blk_requeue_request (request_queue_t *,struct request *);extern void blk_plug_device (request_queue_t *);
@@ -602,6 +628,9 @@ extern struct backing_dev_info *blk_get_extern void blk_queue_ordered (request_queue_t *,int );extern void blk_queue_issue_flush_fn (request_queue_t *,issue_flush_fn *);extern int blkdev_scsi_issue_flush_fn (request_queue_t *,struct gendisk *,sector_t *); +extern struct request *blk_start_pre_flush (request_queue_t *,struct request *); +extern int blk_complete_barrier_rq (request_queue_t *,struct request *,int ); +extern int blk_complete_barrier_rq_locked (request_queue_t *,struct request *,int );extern int blk_rq_map_sg (request_queue_t *,struct request *,struct scatterlist *);extern void blk_dump_rq_flags (struct request *,char *);
include/linux/ide.h renamed from opt/kernel/linux-2.6.10/include/linux/ide.h +1 -1
@@ -743,7 +743,6 @@ typedef struct ide_drive_s {u8 sect;/* "real" sectors per track */ u8 bios_head;/* BIOS/fdisk/LILO number of heads */ u8 bios_sect;/* BIOS/fdisk/LILO sectors per track */ -u8 doing_barrier;/* state, 1=currently doing flush */ unsigned int bios_cyl;/* BIOS/fdisk/LILO number of cyls */ unsigned int cyl;/* "real" number of cyls */
@@ -1131,6 +1130,7 @@ extern ide_hwif_t ide_hwifs[]; /* masteextern int noautodma;extern int ide_end_request (ide_drive_t *drive,int uptodate,int nrsecs); +extern int __ide_end_request (ide_drive_t *drive,struct request *rq,int uptodate,int nrsecs);/* * This is used on exit from the driver to designate the next irq handler
include/scsi/scsi_driver.h renamed from opt/kernel/linux-2.6.10/include/scsi/scsi_driver.h +2 -0
@@ -14,6 +14,8 @@ struct scsi_driver {int (*init_command)(struct scsi_cmnd *);void (*rescan)(struct device *);int (*issue_flush)(struct device *,sector_t *); +int (*prepare_flush)(struct request_queue *,struct request *); +void (*end_flush)(struct request_queue *,struct request *); };#define to_scsi_driver (drv) \ container_of((drv), struct scsi_driver, gendrv)
include/scsi/scsi_host.h renamed from opt/kernel/linux-2.6.10/include/scsi/scsi_host.h +12 -0
@@ -352,6 +352,12 @@ struct scsi_host_template { unsigned skip_settle_delay:1;/* +* ordered write support +*/ + unsigned ordered_flush:1; + unsigned ordered_tag:1; + +/* * Countdown for host blocking with no commands outstanding */ unsigned int max_host_blocked;
@@ -491,6 +497,12 @@ struct Scsi_Host { unsigned reverse_ordering:1;/* +* ordered write support +*/ + unsigned ordered_flush:1; + unsigned ordered_tag:1; + +/* * Host has rejected a command because it was busy. */ unsigned int host_blocked;
Signature · 1 line
Jens Axboe
Re: [PATCH] scsi/sata write barrier support #2
Quoted 7 lines · Jens Axboe
Hi,
A few changes:
- Cleanup up the driver additions even more,
blk_complete_barrier_rq()does all the work now.
Quoted 8 lines
- Fixed up the exports
- Comment functions
- Fixed a bug with SCSI and write back caching disabled
- Rename
blk_queue_flush()toblk_queue_flushing()to indicate it's a state
Tiny nit for SATA drivers:
Define a ATA_ORDERED_IO constant in libata.h, rather than hardcoding the 1 in each driver.
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
++doug
Quoted 10 lines · Doug Maxey
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
Quoted 3 lines
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
[ignoring your question, but it made me think...]
I am thinking the barrier support should know if the write cache is disabled (some datacenters do this), and avoid flushing if so?
Jeff
Quoted 17 lines · Jeff Garzik
Quoted 10 lines · Doug Maxey
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
Quoted 5 lines
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
Quoted 5 lines
[ignoring your question, but it made me think...]
I am thinking the barrier support should know if the write cache is disabled (some datacenters do this), and avoid flushing if so?
Ehm it does, read the code :)
Signature · 1 line
Jens Axboe
Quoted 19 lines · Jens Axboe
Quoted 17 lines · Jeff Garzik
Quoted 14 lines · Doug Maxey
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
Quoted 7 lines
Quoted 4 lines
[ignoring your question, but it made me think...]
I am thinking the barrier support should know if the write cache is disabled (some datacenters do this), and avoid flushing if so?
Ehm it does, read the code :)
I did. I see nowhere that handles the case where the user uses a util (hdparm or blktool) to switch off write cache after sd.c has probed the disk. sd only sets its WCE bit at probe time, and doesn't appear to notice state changes.
Since nobody snoops the MODE SELECT on the caching page, nobody knows past probe the state of write caching.
Thus my comment... I think barrier support should know about that sort of thing :)
Jeff
Quoted 29 lines · Jeff Garzik
Quoted 28 lines · Jens Axboe
Quoted 24 lines · Jeff Garzik
Quoted 11 lines · Doug Maxey
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
Quoted 5 lines
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
[ignoring your question, but it made me think...]
I am thinking the barrier support should know if the write cache is disabled (some datacenters do this), and avoid flushing if so?
Quoted 7 lines
Quoted 1 line
Ehm it does, read the code :)
I did. I see nowhere that handles the case where the user uses a util (hdparm or blktool) to switch off write cache after
sd.chas probed the disk. sd only sets its WCE bit at probe time, and doesn't appear to notice state changes.
WCE bit should change then, like ->wcache does for ide. It's handled inside sd, there's nothing more it can do. sd_shutdown() and sd_issue_flush() have the same issue, they all rely on ->WCE being correct.
Can't say I'm too fond of command snooping, but I guess it's the only solution.
Quoted 5 lines
Since nobody snoops the MODE SELECT on the caching page, nobody knows past probe the state of write caching.
Thus my comment... I think barrier support should know about that sort
of thing :)
So this would mainly be a problem if you boot with write caching disabled, but later turn it on. The other way around will still work safely, at the cost of two noop commands on each write barrier (which I doubt you would notice).
Signature · 1 line
Jens Axboe
Quoted 38 lines · Jens Axboe
Quoted 29 lines · Jeff Garzik
Quoted 28 lines · Jens Axboe
Quoted 24 lines · Jeff Garzik
Quoted 11 lines · Doug Maxey
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
Quoted 5 lines
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
[ignoring your question, but it made me think...]
I am thinking the barrier support should know if the write cache is disabled (some datacenters do this), and avoid flushing if so?
Quoted 7 lines
Quoted 1 line
Ehm it does, read the code :)
I did. I see nowhere that handles the case where the user uses a util (hdparm or blktool) to switch off write cache after
sd.chas probed the disk. sd only sets its WCE bit at probe time, and doesn't appear to notice state changes.
Quoted 7 lines
WCE bit should change then, like ->wcache does for ide. It's handled inside sd, there's nothing more it can do.
sd_shutdown()andsd_issue_flush()have the same issue, they all rely on ->WCE being correct.Can't say I'm too fond of command snooping, but I guess it's the only solution.
Here's an update patch that attempts to snoop successful completion of a mode select that updates the caching page. Untested, what do you think?
drivers/block/cfq-iosched.c renamed from opt/kernel/linux-2.6.10/drivers/block/cfq-iosched.c +4 -4
@@ -1285,19 +1285,19 @@ static int cfq_queue_empty(request_queuestatic void cfq_completed_request (request_queue_t *q,struct request *rq) {struct cfq_rq *crq =RQ_DATA (rq); +struct cfq_queue *cfqq;if (unlikely (!blk_fs_request (rq)))return ; -if (crq->in_flight) { -struct cfq_queue *cfqq = crq->cfq_queue; + cfqq = crq->cfq_queue; +if (crq->in_flight) {WARN_ON (!cfqq->in_flight); cfqq->in_flight--; - -cfq_account_completion (cfqq, crq); } +cfq_account_completion (cfqq, crq); } static struct request *
drivers/block/elevator.c renamed from opt/kernel/linux-2.6.10/drivers/block/elevator.c +15 -1
@@ -320,7 +320,21 @@ void elv_add_request(request_queue_t *q,static inline struct request *__elv_next_request (request_queue_t *q) { -return q->elevator->ops->elevator_next_req_fn (q); +struct request *rq = q->elevator->ops->elevator_next_req_fn (q); + +/* +* if this is a barrier write and the device has to issue a +* flush sequence to support it, check how far we are +*/ +if (rq &&blk_fs_request (rq) &&blk_barrier_rq (rq)) { +BUG_ON (q->ordered ==QUEUE_ORDERED_NONE ); + +if (q->ordered ==QUEUE_ORDERED_FLUSH && + !blk_barrier_preflush (rq)) + rq =blk_start_pre_flush (q, rq); + } + +return rq; }struct request *elv_next_request (request_queue_t *q)
drivers/block/ll_rw_blk.c renamed from opt/kernel/linux-2.6.10/drivers/block/ll_rw_blk.c +235 -27
329 lines not on this page · raw message
drivers/block/paride/pd.c renamed from opt/kernel/linux-2.6.10/drivers/block/paride/pd.c +1 -0
@@ -743,6 +743,7 @@ static int pd_special_command(struct pd_ rq.rq_disk = disk->gd; rq.ref_count =1 ; rq.waiting = &wait; + rq.end_io = blk_end_sync_rq;blk_insert_request (disk->gd->queue, &rq,0 , func,0 );wait_for_completion (&wait); rq.waiting =NULL ;
drivers/ide/ide-disk.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-disk.c +65 -8
99 lines not on this page · raw message
drivers/ide/ide-io.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-io.c +9 -151
210 lines not on this page · raw message
drivers/ide/ide-tape.c renamed from opt/kernel/linux-2.6.10/drivers/ide/ide-tape.c +1 -0
@@ -2720,6 +2720,7 @@ static void idetape_wait_for_request (id }#endif /* IDETAPE_DEBUG_BUGS */ rq->waiting = &wait; + rq->end_io = blk_end_sync_rq;spin_unlock_irq (&tape->spinlock);wait_for_completion (&wait);/* The stage and its struct request have been deallocated */
drivers/scsi/ahci.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/ahci.c +1 -0
@@ -198,6 +198,7 @@ static Scsi_Host_Template ahci_sht = { .dma_boundary = AHCI_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations ahci_ops = {
drivers/scsi/ata_piix.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/ata_piix.c +1 -0
@@ -121,6 +121,7 @@ static Scsi_Host_Template piix_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations piix_pata_ops = {
drivers/scsi/hosts.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/hosts.c +10 -0
@@ -258,6 +258,16 @@ struct Scsi_Host *scsi_host_alloc(struct shost->cmd_per_lun = sht->cmd_per_lun; shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; + shost->ordered_flush = sht->ordered_flush; + shost->ordered_tag = sht->ordered_tag; + +/* +* hosts/devices that do queueing must support ordered tags +*/ +if (shost->can_queue >1 && shost->ordered_flush) { +printk (KERN_ERR "scsi: ordered flushes don't support queueing\n" ); + shost->ordered_flush =0 ; + }if (sht->max_host_blocked) shost->max_host_blocked = sht->max_host_blocked;
drivers/scsi/sata_nv.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_nv.c +1 -0
@@ -194,6 +194,7 @@ static Scsi_Host_Template nv_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations nv_ops = {
drivers/scsi/sata_promise.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_promise.c +1 -0
@@ -102,6 +102,7 @@ static Scsi_Host_Template pdc_ata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations pdc_ata_ops = {
drivers/scsi/sata_sil.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sil.c +1 -0
@@ -123,6 +123,7 @@ static Scsi_Host_Template sil_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations sil_ops = {
drivers/scsi/sata_sis.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sis.c +1 -0
@@ -90,6 +90,7 @@ static Scsi_Host_Template sis_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations sis_ops = {
drivers/scsi/sata_svw.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_svw.c +1 -0
@@ -288,6 +288,7 @@ static Scsi_Host_Template k2_sata_sht = .proc_info = k2_sata_proc_info, #endif .bios_param = ata_std_bios_param, + .ordered_flush = 1, };
drivers/scsi/sata_sx4.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_sx4.c +1 -0
@@ -188,6 +188,7 @@ static Scsi_Host_Template pdc_sata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations pdc_20621_ops = {
drivers/scsi/sata_uli.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_uli.c +1 -0
@@ -82,6 +82,7 @@ static Scsi_Host_Template uli_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations uli_ops = {
drivers/scsi/sata_via.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_via.c +1 -0
@@ -95,6 +95,7 @@ static Scsi_Host_Template svia_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };static struct ata_port_operations svia_sata_ops = {
drivers/scsi/sata_vsc.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sata_vsc.c +1 -0
@@ -204,6 +204,7 @@ static Scsi_Host_Template vsc_sata_sht = .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, + .ordered_flush = 1, };
drivers/scsi/scsi_lib.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/scsi_lib.c +46 -0
64 lines not on this page · raw message
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +61 -0
91 lines not on this page · raw message
include/linux/blkdev.h renamed from opt/kernel/linux-2.6.10/include/linux/blkdev.h +32 -3
@@ -93,6 +93,9 @@ struct io_context *get_io_context(int gfvoid copy_io_context (struct io_context **pdst,struct io_context **psrc);void swap_io_context (struct io_context **ioc1,struct io_context **ioc2); +struct request ; +typedef void (rq_end_io_fn )(struct request *); +struct request_list {int count[2 ];int starved[2 ];
@@ -176,6 +179,12 @@ struct request {* For Power Management requests */ struct request_pm_state *pm; + +/* +* completion callback. end_io_data should be folded in with waiting +*/ +rq_end_io_fn *end_io; +void *end_io_data; };/*
@@ -266,6 +275,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 int (issue_flush_fn ) (request_queue_t *,struct gendisk *,sector_t *); +typedef int (prepare_flush_fn ) (request_queue_t *,struct request *); +typedef void (end_flush_fn ) (request_queue_t *,struct request *);enum blk_queue_state { Queue_down,
@@ -309,6 +320,8 @@ struct request_queuemerge_bvec_fn *merge_bvec_fn;activity_fn *activity_fn;issue_flush_fn *issue_flush_fn; +prepare_flush_fn *prepare_flush_fn; +end_flush_fn *end_flush_fn;/* * Auto-unplugging state
@@ -380,6 +393,18 @@ struct request_queueunsigned int sg_reserved_size;struct list_head drain_list; + +/* +* reserved for flush operations +*/ +struct request *flush_rq; +unsigned char ordered; +}; + +enum { +QUEUE_ORDERED_NONE , +QUEUE_ORDERED_TAG , +QUEUE_ORDERED_FLUSH , };#define RQ_INACTIVE (-1)
@@ -396,12 +421,13 @@ struct request_queue#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 QUEUE_FLAG_DRAIN 9/* draining queue for sched switch */ +#define QUEUE_FLAG_DRAIN 8/* draining queue for sched switch */ +#define QUEUE_FLAG_FLUSH 9/* doing barrier flush sequence */ #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)#define blk_queue_stopped (q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) +#define blk_queue_flushing (q) test_bit(QUEUE_FLAG_FLUSH, &(q)->queue_flags)#define blk_fs_request (rq) ((rq)->flags & REQ_CMD)#define blk_pc_request (rq) ((rq)->flags & REQ_BLOCK_PC)
@@ -509,10 +535,10 @@ extern void blk_unregister_queue(structextern void register_disk (struct gendisk *dev);extern void generic_make_request (struct bio *bio);extern void blk_put_request (struct request *); +extern void blk_end_sync_rq (struct request *rq);extern void blk_attempt_remerge (request_queue_t *,struct request *);extern void __blk_attempt_remerge (request_queue_t *,struct request *);extern struct request *blk_get_request (request_queue_t *,int ,int ); -extern void blk_put_request (struct request *);extern void blk_insert_request (request_queue_t *,struct request *,int ,void *,int );extern void blk_requeue_request (request_queue_t *,struct request *);extern void blk_plug_device (request_queue_t *);
@@ -602,6 +628,9 @@ extern struct backing_dev_info *blk_get_extern void blk_queue_ordered (request_queue_t *,int );extern void blk_queue_issue_flush_fn (request_queue_t *,issue_flush_fn *);extern int blkdev_scsi_issue_flush_fn (request_queue_t *,struct gendisk *,sector_t *); +extern struct request *blk_start_pre_flush (request_queue_t *,struct request *); +extern int blk_complete_barrier_rq (request_queue_t *,struct request *,int ); +extern int blk_complete_barrier_rq_locked (request_queue_t *,struct request *,int );extern int blk_rq_map_sg (request_queue_t *,struct request *,struct scatterlist *);extern void blk_dump_rq_flags (struct request *,char *);
include/linux/ide.h renamed from opt/kernel/linux-2.6.10/include/linux/ide.h +1 -1
@@ -743,7 +743,6 @@ typedef struct ide_drive_s {u8 sect;/* "real" sectors per track */ u8 bios_head;/* BIOS/fdisk/LILO number of heads */ u8 bios_sect;/* BIOS/fdisk/LILO sectors per track */ -u8 doing_barrier;/* state, 1=currently doing flush */ unsigned int bios_cyl;/* BIOS/fdisk/LILO number of cyls */ unsigned int cyl;/* "real" number of cyls */
@@ -1131,6 +1130,7 @@ extern ide_hwif_t ide_hwifs[]; /* masteextern int noautodma;extern int ide_end_request (ide_drive_t *drive,int uptodate,int nrsecs); +extern int __ide_end_request (ide_drive_t *drive,struct request *rq,int uptodate,int nrsecs);/* * This is used on exit from the driver to designate the next irq handler
include/scsi/scsi_driver.h renamed from opt/kernel/linux-2.6.10/include/scsi/scsi_driver.h +2 -0
@@ -14,6 +14,8 @@ struct scsi_driver {int (*init_command)(struct scsi_cmnd *);void (*rescan)(struct device *);int (*issue_flush)(struct device *,sector_t *); +int (*prepare_flush)(struct request_queue *,struct request *); +void (*end_flush)(struct request_queue *,struct request *); };#define to_scsi_driver (drv) \ container_of((drv), struct scsi_driver, gendrv)
include/scsi/scsi_host.h renamed from opt/kernel/linux-2.6.10/include/scsi/scsi_host.h +12 -0
@@ -352,6 +352,12 @@ struct scsi_host_template { unsigned skip_settle_delay:1;/* +* ordered write support +*/ + unsigned ordered_flush:1; + unsigned ordered_tag:1; + +/* * Countdown for host blocking with no commands outstanding */ unsigned int max_host_blocked;
@@ -491,6 +497,12 @@ struct Scsi_Host { unsigned reverse_ordering:1;/* +* ordered write support +*/ + unsigned ordered_flush:1; + unsigned ordered_tag:1; + +/* * Host has rejected a command because it was busy. */ unsigned int host_blocked;
Signature · 1 line
Jens Axboe
Quoted 31 lines · Jens Axboe
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +27
-0+/* +* snoop succesfull completion of mode select commands that update the +* write back cache state +*/ +#define MS_CACHE_PAGE 0x08 +static void sd_snoop_cmd (struct scsi_cmnd *cmd) +{ +struct scsi_disk *sdpk; +char *page; + +if (cmd->result) +return ; + +switch (cmd->cmnd[0 ]) { +case MODE_SELECT : +case MODE_SELECT_10 : + page = cmd->request_buffer; +if (!page) +break ; +if ((page[0 ] &0x3f ) !=MS_CACHE_PAGE ) +break ; + sdpk =dev_get_drvdata (&cmd->device->sdev_gendev); + sdpk->WCE = (page[2 ] &0x04 ) !=0 ; +break ; + } +} +/** * sd_rw_intr - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command.
drivers/scsi/sd.c static void sd_rw_intr(struct scsi_cmnd · line 836
Quoted 6 lines
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +3
-0@@ -773,6 +831,9 @@ static void sd_rw_intr(struct scsi_cmnd SCpnt->sense_buffer[13])); }#endif + +sd_snoop_cmd (SCpnt); +
Good grief no!
If you're going to try something like this, it needs to be a separate patch over the scsi-list for one thing. And to save time:
1) The patch is actually wrong. There's more than one caching mode page and not all of them affect current behaviour.
2) We have a current interface to update the WCE bit: You twiddle all the disc parameters and then trigger a device rescan via sysfs (I'll check that this updates the cache bits, I think it does, but if it doesn't I'll make it).
3) If we think this is a quantity the users would like to see and alter, then reading and setting it should be exported via sysfs.
4) Snooping SCSI commands is really bad ... it can get you into all sorts of trouble which is why we prefer asking the device what state it's in to trying to guess ourselves.
James
Quoted 41 lines · James Bottomley
Quoted 31 lines · Jens Axboe
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +27
-0+/* +* snoop succesfull completion of mode select commands that update the +* write back cache state +*/ +#define MS_CACHE_PAGE 0x08 +static void sd_snoop_cmd (struct scsi_cmnd *cmd) +{ +struct scsi_disk *sdpk; +char *page; + +if (cmd->result) +return ; + +switch (cmd->cmnd[0 ]) { +case MODE_SELECT : +case MODE_SELECT_10 : + page = cmd->request_buffer; +if (!page) +break ; +if ((page[0 ] &0x3f ) !=MS_CACHE_PAGE ) +break ; + sdpk =dev_get_drvdata (&cmd->device->sdev_gendev); + sdpk->WCE = (page[2 ] &0x04 ) !=0 ; +break ; + } +} +/** * sd_rw_intr - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command. drivers/scsi/sd.c static void sd_rw_intr(struct scsi_cmnd · line 836
Quoted 6 lines
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +3
-0@@ -773,6 +831,9 @@ static void sd_rw_intr(struct scsi_cmnd SCpnt->sense_buffer[13])); }#endif + +sd_snoop_cmd (SCpnt); +Good grief no!
Quoted 5 lines
If you're going to try something like this, it needs to be a separate patch over the scsi-list for one thing. And to save time:
1) The patch is actually wrong. There's more than one caching mode page and not all of them affect current behaviour.
It also gets the offset wrong :)
Quoted 9 lines
2) We have a current interface to update the WCE bit: You twiddle all the disc parameters and then trigger a device rescan via sysfs (I'll check that this updates the cache bits, I think it does, but if it doesn't I'll make it).
3) If we think this is a quantity the users would like to see and alter, then reading and setting it should be exported via sysfs.
4) Snooping SCSI commands is really bad ... it can get you into all sorts of trouble which is why we prefer asking the device what state it's in to trying to guess ourselves.
I would _much_ prefer some sort of easily tweakable way to change the write back mode, if this is something we want to support. As I wrote in the original reply, I hate the concept of command snooping.
The barrier stuff works fine as-is, I'll just rely on scsi getting the WCE updating correct.
Signature · 1 line
Jens Axboe
Quoted 31 lines · Jens Axboe
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +27
-0+/* +* snoop succesfull completion of mode select commands that update the +* write back cache state +*/ +#define MS_CACHE_PAGE 0x08 +static void sd_snoop_cmd (struct scsi_cmnd *cmd) +{ +struct scsi_disk *sdpk; +char *page; + +if (cmd->result) +return ; + +switch (cmd->cmnd[0 ]) { +case MODE_SELECT : +case MODE_SELECT_10 : + page = cmd->request_buffer; +if (!page) +break ; +if ((page[0 ] &0x3f ) !=MS_CACHE_PAGE ) +break ; + sdpk =dev_get_drvdata (&cmd->device->sdev_gendev); + sdpk->WCE = (page[2 ] &0x04 ) !=0 ; +break ; + } +} +/** * sd_rw_intr - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command.
drivers/scsi/sd.c static void sd_rw_intr(struct scsi_cmnd · line 836
Quoted 6 lines
drivers/scsi/sd.c renamed from opt/kernel/linux-2.6.10/drivers/scsi/sd.c +3
-0@@ -773,6 +831,9 @@ static void sd_rw_intr(struct scsi_cmnd SCpnt->sense_buffer[13])); }#endif + +sd_snoop_cmd (SCpnt); +
Good grief no!
If you're going to try something like this, it needs to be a separate patch over the scsi-list for one thing. And to save time:
1) The patch is actually wrong. There's more than one caching mode page and not all of them affect current behaviour.
2) We have a current interface to update the WCE bit: You twiddle all the disc parameters and then trigger a device rescan via sysfs (I'll check that this updates the cache bits, I think it does, but if it doesn't I'll make it).
3) If we think this is a quantity the users would like to see and alter, then reading and setting it should be exported via sysfs.
4) Snooping SCSI commands is really bad ... it can get you into all sorts of trouble which is why we prefer asking the device what state it's in to trying to guess ourselves.
James
Quoted 9 lines · Doug Maxey
Quoted 6 lines · Jens Axboe
Hi,
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems. This patch adds support for the same type of cache flushing barriers that PATA uses for SCSI, to be utilized with libata.
Quoted 5 lines
What, if any mechanism supports changing the underlying write cache?
That is, assuming this is common across PATA and SCSI drives, and it is possible to turn the cache off on the IDE drives, would switching the cache underneath require completing the inflight IO?
Not sure what you mean, switching it off while the io is in flight? You cannot do that, either the cache state will change right before starting the io or right after. The cache state at the start of the barrier write will determine the action taken.
Signature · 1 line
Jens Axboe
Quoted 2 lines · Jens Axboe
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems.
What about for fsync(2)? One of the most frequent sources of data loss on the postgres mailing list has to do with users with IDE drives where fsync returns even though the data hasn't actually reached the disk. A power outage can cause lost data or a corrupted database.
Is there any progress getting fsync to use this new infrastructure so it can actually satisfy its contract?
Signature · 1 line
greg
Quoted 6 lines · Greg Stark
Quoted 2 lines · Jens Axboe
For the longest time, only the old PATA drivers supported barrier writes with journalled file systems.
Quoted 7 lines
What about for fsync(2)? One of the most frequent sources of data loss on the postgres mailing list has to do with users with IDE drives where fsync returns even though the data hasn't actually reached the disk. A power outage can cause lost data or a corrupted database.
Is there any progress getting fsync to use this new infrastructure so it can actually satisfy its contract?
fsync has been working all along, since the initial barrier support for ide. only ext3 and reiserfs support it.
Signature · 1 line
Jens Axboe
Quoted 2 lines · Jens Axboe
fsync has been working all along, since the initial barrier support for ide. only ext3 and reiserfs support it.
Really? That's huge news. Since what kernel version(s) is that?
What about a non-journaled fs, or at least a meta-data-only-journaled fs? Journaled FS's don't mix well with transaction based databases since they're basically doing their own journaling anyways.
Signature · 1 line
greg
Quoted 7 lines · Greg Stark
Quoted 2 lines · Jens Axboe
fsync has been working all along, since the initial barrier support for ide. only ext3 and reiserfs support it.
Really? That's huge news. Since what kernel version(s) is that?
Since 2.6.9.
Quoted 3 lines
What about a non-journaled fs, or at least a meta-data-only-journaled fs? Journaled FS's don't mix well with transaction based databases since they're basically doing their own journaling anyways.
Only works on ext3 and reiserfs currently.
Signature · 1 line
Jens Axboe
Quoted 5 lines · Jens Axboe
Quoted 3 lines
What about a non-journaled fs, or at least a meta-data-only-journaled fs? Journaled FS's don't mix well with transaction based databases since they're basically doing their own journaling anyways.
Only works on ext3 and reiserfs currently.
Does it work in resierfs with data=writeback or ext3 with tune2fs's journal_data_writeback?
What I'm wondering is whether it only kicks in when the journal gets synchronized or whether it kicks in whenever you call fsync even if no journaling is involved.
Writeback mode isn't really necessary, Postgres makes every effort to use fdatasync or equivalent so no metadata changes are really necessary. So the question is also, do the filesystems initiate a cache flush even if no metadata changes are being synchronized?
Signature · 1 line
greg