2.6 ide-cd DMA ripping
Subsystems (3)
PATCH 1/1 2.6 ide-cd DMA ripping
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
===== drivers/block/ll_rw_blk.c 1.228 vs edited =====
drivers/block/ll_rw_blk.c +137 -0
@@ -28,6 +28,11 @@#include <linux/slab.h> #include <linux/swap.h> +/* +* for max sense size +*/ +#include <scsi/scsi_cmnd.h> +static void blk_unplug_work (void *data);static void blk_unplug_timeout (unsigned long data);
@@ -1756,6 +1761,138 @@ }EXPORT_SYMBOL (blk_insert_request); + +/** +* blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage +* @q: request queue where request should be inserted +* @rw: READ or WRITE data +* @ubuf: the user buffer +* @len: length of user data +* +* Description: +* Data will be mapped directly for zero copy io, if possible. Otherwise +* a kernel bounce buffer is used. +* +* A matching blk_rq_unmap_user() must be issued at the end of io, while +* still in process context. +*/ +struct request *blk_rq_map_user (request_queue_t *q,int rw,void __user *ubuf, +unsigned int len) +{ +struct request *rq =NULL ; +char *buf =NULL ; +struct bio *bio; + + rq =blk_get_request (q, rw, __GFP_WAIT); +if (!rq) +return NULL ; + + bio =bio_map_user (q,NULL , (unsigned long ) ubuf, len, rw ==READ ); +if (!bio) { + buf =kmalloc (len, q->bounce_gfp |GFP_USER ); +if (!buf) + goto fault; + +if (rw ==WRITE ) { +if (copy_from_user (buf, ubuf, len)) + goto fault; + }else +memset (buf,0 , len); + } + + rq->bio = rq->biotail = bio; +if (rq->bio) +blk_rq_bio_prep (q, rq, bio); + + rq->buffer = rq->data = buf; + rq->data_len = len; +return rq; +fault: +if (buf) +kfree (buf); +if (bio) +bio_unmap_user (bio,1 ); +if (rq) +blk_put_request (rq); + +return NULL ; +} + +EXPORT_SYMBOL (blk_rq_map_user); + +/** +* blk_rq_unmap_user - unmap a request with user data +* @rq: request to be unmapped +* @ubuf: user buffer +* @ulen: length of user buffer +* @rw: operation was a READ or WRITE +* +* Description: +* Unmap a request previously mapped by blk_rq_map_user(). +*/ +int blk_rq_unmap_user (struct request *rq,void __user *ubuf,unsigned int ulen, +int rw) +{ +int ret =0 ; + +if (rq->biotail) +bio_unmap_user (rq->biotail, rw ==READ ); +if (rq->buffer) { +if (rw ==READ &©_to_user (ubuf, rq->buffer, ulen)) + ret = -EFAULT ; +kfree (rq->buffer); + } + +blk_put_request (rq); +return ret; +} + +EXPORT_SYMBOL (blk_rq_unmap_user); + +/** +* blk_execute_rq - insert a request into queue for execution +* @q: queue to insert the request in +* @bd_disk: matching gendisk +* @rq: request to insert +* +* Description: +* Insert a fully prepared request at the back of the io scheduler queue +* for execution. +*/ +int blk_execute_rq (request_queue_t *q,struct gendisk *bd_disk, +struct request *rq) +{ +DECLARE_COMPLETION (wait); +char sense[SCSI_SENSE_BUFFERSIZE ]; +int err =0 ; + + rq->rq_disk = bd_disk; + +/* +* we need an extra reference to the request, so we can look at +* it after io completion +*/ + rq->ref_count++; + +if (!rq->sense) { +memset (sense,0 ,sizeof (sense)); + rq->sense = sense; + rq->sense_len =0 ; + } + + rq->flags |=REQ_NOMERGE ; + rq->waiting = &wait; +elv_add_request (q, rq,ELEVATOR_INSERT_BACK ,1 ); +generic_unplug_device (q); +wait_for_completion (&wait); + +if (rq->errors) + err = -EIO ; + +return err; +} + +EXPORT_SYMBOL (blk_execute_rq);void drive_stat_acct (struct request *rq,int nr_sectors,int new_io) {
===== drivers/block/scsi_ioctl.c 1.40 vs edited =====
drivers/block/scsi_ioctl.c +4 -42
76 lines not on this page · raw message
===== drivers/cdrom/cdrom.c 1.48 vs edited =====
drivers/cdrom/cdrom.c +143 -35
202 lines not on this page · raw message
===== drivers/ide/ide-cd.c 1.72 vs edited =====
drivers/ide/ide-cd.c +1 -0
@@ -2931,6 +2931,7 @@if (!CDROM_CONFIG_FLAGS (drive)->mrw_w) devinfo->mask |=CDC_MRW_W ; + devinfo->disk = drive->disk;return register_cdrom (devinfo); }
===== drivers/scsi/sr.c 1.99 vs edited =====
drivers/scsi/sr.c +4 -1
@@ -566,13 +566,16 @@snprintf (disk->devfs_name,sizeof (disk->devfs_name),"%s/cd" , sdev->devfs_name); disk->driverfs_dev = &sdev->sdev_gendev; -register_cdrom (&cd->cdi);set_capacity (disk, cd->capacity); disk->private_data = &cd->driver; disk->queue = sdev->request_queue; + cd->cdi.disk = disk;dev_set_drvdata (dev, cd);add_disk (disk); + +if (register_cdrom (&cd->cdi)) + goto fail_put; printk(KERN_DEBUG "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
===== include/linux/blkdev.h 1.134 vs edited =====
include/linux/blkdev.h +3 -0
@@ -514,6 +514,9 @@extern void __blk_stop_queue (request_queue_t *q);extern void blk_run_queue (request_queue_t *q);extern void blk_queue_activity_fn (request_queue_t *,activity_fn *,void *); +extern struct request *blk_rq_map_user (request_queue_t *,int ,void __user *,unsigned int ); +extern int blk_rq_unmap_user (struct request *,void __user *,unsigned int ,int ); +extern int blk_execute_rq (request_queue_t *,struct gendisk *,struct request *);static inline request_queue_t *bdev_get_queue (struct block_device *bdev) {
===== include/linux/cdrom.h 1.16 vs edited =====
include/linux/cdrom.h +6 -0
@@ -877,10 +877,15 @@#include <linux/fs.h> /* not really needed, later.. */ #include <linux/device.h> +#define CDDA_OLD 0/* old style */ +#define CDDA_BPC_SINGLE 1/* block_pc, but single frame */ +#define CDDA_BPC_FULL 2/* full speed block pc */ +/* Uniform cdrom data structures for cdrom.c */ struct cdrom_device_info {struct cdrom_device_ops *ops;/* link to device_ops */ struct cdrom_device_info *next;/* next device_info for this major */ +struct gendisk *disk;/* matching block layer disk */ void *handle;/* driver-dependent data */ /* specifications */ int mask;/* mask of capability: disables them */
@@ -894,6 +899,7 @@/* per-device flags */ __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ __u8 reserved : 6; /* not used yet */ +int cdda_method;/* see flags */ int for_data;int (*exit)(struct cdrom_device_info *);int mrw_mode_page;
Signature · 1 line
Jens Axboe
Quoted 18 lines · Jens Axboe
drivers/cdrom/cdrom.c +18
-0+static int cdrom_read_cdda (struct cdrom_device_info *cdi,__u8 __user *ubuf, +int lba,int nframes) +{ +int ret; + +if (cdi->cdda_method ==CDDA_OLD ) +return cdrom_read_cdda_old (cdi, ubuf, lba, nframes); + + do { + ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes); + + if (!ret) + break; + + /* + * I've seen drives get sense 4/8/3 udma crc errors, so + * drop to single frame dma if we need to + */
drivers/cdrom/cdrom.c line 1927
Quoted 10 lines
drivers/cdrom/cdrom.c +10
-0+if (cdi->cdda_method ==CDDA_BPC_FULL && nframes >1 ) { +printk ("cdrom: dropping to single frame dma\n" ); + cdi->cdda_method =CDDA_BPC_SINGLE ; +continue ; + } + +printk ("cdrom: dropping to old style cdda\n" ); + cdi->cdda_method =CDDA_OLD ; + ret =cdrom_read_cdda_old (cdi, ubuf, lba, nframes); + }while (0 );
Irk, that should have been a while (1) of course, and a break after the last cdrom_read_cdda_old();
Signature · 1 line
Jens Axboe
Quoted 9 lines · you
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
[snip]
Is this a general optimisation, i.e. will the rip methods used by cdda2wav and cdparanoia, etc. be optimised, or do you need some specific userspace tools to utilise it?
Signature · 8 lines
Cheers,
Alistair.
personal: alistair()devzero!co!uk
university: s0348365()sms!ed!ac!uk
student: CS/AI Undergraduate
contact: 7/10 Darroch Court,
University of Edinburgh.Quoted 7 lines · Alistair John Strachan
Quoted 6 lines · you
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
Quoted 8 lines
Quoted 3 lines
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
[snip]
Is this a general optimisation, i.e. will the rip methods used by cdda2wav and cdparanoia, etc. be optimised, or do you need some specific userspace tools to utilise it?
The patch only affects CDROMREADAUDIO ioctl. cdda2wav (with recent libscg) will use SG_IO, which works equally well already. cdparanoia uses CDROMREADAUDIO as well iirc, if it can use /dev/sg* sg v2 interface. I'm not completely sure, if you send me an strace of the process in question I can tell you for sure :)
Signature · 1 line
Jens Axboe
Quoted 8 lines · Jens Axboe
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
Applied successfully to 2.6.4-rc1-mm2, and it works great. For some reason, on two different machines, ripping with cdparanoia used to somehow crowd out the serial port, but now everything just works.
Thanks a lot!
Quoted 8 lines · Sean Neakums
Quoted 6 lines · Jens Axboe
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
Quoted 6 lines
Quoted 2 lines
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
Applied successfully to 2.6.4-rc1-mm2, and it works great. For some reason, on two different machines, ripping with cdparanoia used to somehow crowd out the serial port, but now everything just works.
cd ripping was highly cpu intensive when it ran in pio, so it's very likely that this screwed up your serial port communication. It doesn't matter with the patch, but had you used hdparm -u1 on your cd device on an unpatched kernel, you would have had better luck.
Signature · 1 line
Jens Axboe
Quoted 12 lines · Jens Axboe
Quoted 11 lines · Sean Neakums
Quoted 8 lines · Jens Axboe
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
Quoted 8 lines
Quoted 3 lines
Applied successfully to 2.6.4-rc1-mm2, and it works great. For some reason, on two different machines, ripping with cdparanoia used to somehow crowd out the serial port, but now everything just works.
cd ripping was highly cpu intensive when it ran in pio, so it's very likely that this screwed up your serial port communication. It doesn't matter with the patch, but had you used hdparm -u1 on your cd device on an unpatched kernel, you would have had better luck.
I had a look, just for pig iron, and hdparm -u on one of the machines reports that it is already enabled. That machine is SMP with two 1.13GHz PIIIs. I can't check the other machine as the drive in question is no longer functional.
Quoted 23 lines · Sean Neakums
Quoted 12 lines · Jens Axboe
Quoted 11 lines · Sean Neakums
Quoted 8 lines · Jens Axboe
Hi,
2.6 still uses PIO for CDROMREADAUDIO cdda ripping, which is less than optimal of course... This patch uses the block layer infrastructure to enable zero copy DMA ripping through CDROMREADAUDIO.
I'd appreciate people giving this a test spin. Patch is against 2.6.4-rc1 (well current BK, actually).
Quoted 8 lines
Quoted 3 lines
Applied successfully to 2.6.4-rc1-mm2, and it works great. For some reason, on two different machines, ripping with cdparanoia used to somehow crowd out the serial port, but now everything just works.
cd ripping was highly cpu intensive when it ran in pio, so it's very likely that this screwed up your serial port communication. It doesn't matter with the patch, but had you used hdparm -u1 on your cd device on an unpatched kernel, you would have had better luck.
Quoted 4 lines
I had a look, just for pig iron, and hdparm -u on one of the machines reports that it is already enabled. That machine is SMP with two 1.13GHz PIIIs. I can't check the other machine as the drive in question is no longer functional.
Then isr runtime was likely too high, even with interrupt masking enabled. So just be glad that it works with dma :)
Signature · 1 line
Jens Axboe