[PATCH] 2.5.67-ac2 direct-IO for IDE taskfile ioctl (4/4)

From: Bartlomiej Zolnierkiewicz (B.Zolnierkiewicz@elka.pw.edu.pl)
Date: Wed Apr 23 2003 - 12:40:10 EST


# Use direct-IO in ide_taskfile_ioctl() and in ide_cmd_ioctl().
#
# Detailed changelog:
# - add ide_bio_taskfile() which is equivalent to ide_diag_taskfile()
# for non-fs rq->bio based requests
# - use direct-IO to user memory if possible in ide_taskfile_ioctl()
# and in taskfile version of ide_cmd_ioctl()
#
# NOTE: user memory out/in buffers have to be hardsector (=512) aligned
# to take advantage of direct-IO
#
# Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>

diff -uNr linux-2.5.67-ac2-dtf3/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.67-ac2-dtf3/drivers/ide/ide-taskfile.c Wed Apr 23 15:44:36 2003
+++ linux/drivers/ide/ide-taskfile.c Wed Apr 23 16:22:12 2003
@@ -1054,6 +1054,25 @@

 EXPORT_SYMBOL(ide_raw_taskfile);

+/*
+ * Comments to ide_diag_taskfile() apply here as well.
+ */
+static int ide_bio_taskfile (ide_drive_t *drive, ide_task_t *args,
+ request_queue_t *q, struct bio *bio)
+{
+ struct request rq;
+
+ ide_init_drive_taskfile(&rq);
+ blk_rq_bio_prep(q, &rq, bio);
+
+ if (args->tf_out_flags.all == 0)
+ args->posthandler = ide_post_handler_parser(
+ (struct hd_drive_task_hdr *) args->tfRegister,
+ (struct hd_drive_hob_hdr *) args->hobRegister);
+ rq.special = args;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
 #ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 char * ide_ioctl_verbose (unsigned int cmd)
 {
@@ -1081,10 +1100,19 @@
         int tasksize = sizeof(struct ide_task_request_s);
         int taskin = 0;
         int taskout = 0;
+
+ unsigned long outaddr, inaddr;
+ request_queue_t *q;
+ struct bio *outbio = NULL, *inbio = NULL;
+
         u8 io_32bit = drive->io_32bit;

 // printk("IDE Taskfile ...\n");

+ q = bdev_get_queue(bdev);
+ if (!q)
+ return -ENXIO;
+
         req_task = kmalloc(tasksize, GFP_KERNEL);
         if (req_task == NULL) return -ENOMEM;
         memset(req_task, 0, tasksize);
@@ -1097,7 +1125,21 @@
         taskin = (int) req_task->in_size;

         if (taskout) {
+ outaddr = arg + tasksize;
+ /* writing to device -> reading from vm */
+ if (!access_ok(VERIFY_READ, (void *)outaddr, taskout)) {
+ kfree(req_task);
+ return -EFAULT;
+ }
+ outbio = bio_map_user(bdev, outaddr, taskout, 0);
+ if (outbio)
+ outbio->bi_rw |= (1 << BIO_RW);
+ }
+
+ if (taskout && !outbio) {
                 int outtotal = tasksize;
+ printk(KERN_INFO "%s: %s: taking OUT slow-path\n",
+ drive->name, __FUNCTION__);
                 outbuf = kmalloc(taskout, GFP_KERNEL);
                 if (outbuf == NULL) {
                         err = -ENOMEM;
@@ -1111,7 +1153,19 @@
         }

         if (taskin) {
+ inaddr = arg + tasksize + taskout;
+ /* reading from device -> writing to vm */
+ if (!access_ok(VERIFY_WRITE, (void *)inaddr, taskin)) {
+ kfree(req_task);
+ return -EFAULT;
+ }
+ inbio = bio_map_user(bdev, inaddr, taskin, 1);
+ }
+
+ if (taskin && !inbio) {
                 int intotal = tasksize + taskout;
+ printk(KERN_INFO "%s: %s: taking IN slow-path\n",
+ drive->name, __FUNCTION__);
                 inbuf = kmalloc(taskin, GFP_KERNEL);
                 if (inbuf == NULL) {
                         err = -ENOMEM;
@@ -1144,22 +1198,34 @@
         switch(req_task->data_phase) {
                 case TASKFILE_OUT_DMAQ:
                 case TASKFILE_OUT_DMA:
- err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+ if (outbio)
+ err = ide_bio_taskfile(drive, &args, q, outbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskout, outbuf);
                         break;
                 case TASKFILE_IN_DMAQ:
                 case TASKFILE_IN_DMA:
- err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+ if (inbio)
+ err = ide_bio_taskfile(drive, &args, q, inbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskin, inbuf);
                         break;
                 case TASKFILE_IN_OUT:
 #if 0
                         args.prehandler = &pre_task_out_intr;
                         args.handler = &task_out_intr;
                         args.posthandler = NULL;
- err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+ if (outbio)
+ err = ide_bio_taskfile(drive, &args, q, outbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskout, outbuf);
                         args.prehandler = NULL;
                         args.handler = &task_in_intr;
                         args.posthandler = NULL;
- err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+ if (inbio)
+ err = ide_bio_taskfile(drive, &args, q, inbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskin, inbuf);
                         break;
 #else
                         err = -EFAULT;
@@ -1176,12 +1242,18 @@
                         }
                         args.prehandler = &pre_task_mulout_intr;
                         args.handler = &task_mulout_intr;
- err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+ if (outbio)
+ err = ide_bio_taskfile(drive, &args, q, outbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskout, outbuf);
                         break;
                 case TASKFILE_OUT:
                         args.prehandler = &pre_task_out_intr;
                         args.handler = &task_out_intr;
- err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+ if (outbio)
+ err = ide_bio_taskfile(drive, &args, q, outbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskout, outbuf);
                         break;
                 case TASKFILE_MULTI_IN:
                         if (!drive->mult_count) {
@@ -1193,11 +1265,17 @@
                                 goto abort;
                         }
                         args.handler = &task_mulin_intr;
- err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+ if (inbio)
+ err = ide_bio_taskfile(drive, &args, q, inbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskin, inbuf);
                         break;
                 case TASKFILE_IN:
                         args.handler = &task_in_intr;
- err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+ if (inbio)
+ err = ide_bio_taskfile(drive, &args, q, inbio);
+ else
+ err = ide_diag_taskfile(drive, &args, taskin, inbuf);
                         break;
                 case TASKFILE_NO_DATA:
                         args.handler = &task_no_data_intr;
@@ -1208,6 +1286,11 @@
                         goto abort;
         }

+ if (outbio)
+ bio_unmap_user(outbio, 0);
+ if (inbio)
+ bio_unmap_user(inbio, 1);
+
         memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
         memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
         req_task->in_flags = args.tf_in_flags;
@@ -1217,14 +1300,14 @@
                 err = -EFAULT;
                 goto abort;
         }
- if (taskout) {
+ if (outbuf) {
                 int outtotal = tasksize;
                 if (copy_to_user((void *)arg+outtotal, outbuf, taskout)) {
                         err = -EFAULT;
                         goto abort;
                 }
         }
- if (taskin) {
+ if (inbuf) {
                 int intotal = tasksize + taskout;
                 if (copy_to_user((void *)arg+intotal, inbuf, taskin)) {
                         err = -EFAULT;
@@ -1331,6 +1414,9 @@
         u8 xfer_rate = 0;
         int argsize = 0;
         ide_task_t tfargs;
+ int reading = 0, writing = 0;
+ request_queue_t *q;
+ struct bio *bio = NULL;

         if (NULL == (void *) arg) {
                 struct request rq;
@@ -1338,6 +1424,10 @@
                 return ide_do_drive_cmd(drive, &rq, ide_wait);
         }

+ q = bdev_get_queue(bdev);
+ if (!q)
+ return -ENXIO;
+
         if (copy_from_user(args, (void *)arg, 4))
                 return -EFAULT;

@@ -1357,21 +1447,51 @@
         if (drive->media != ide_disk && args[0] == WIN_IDENTIFY)
                 tfargs.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY;

+ if (set_transfer(drive, &tfargs)) {
+ xfer_rate = args[1];
+ if (ide_ata66_check(drive, &tfargs))
+ goto abort;
+ }
+
+ tfargs.command_type = ide_cmd_type_parser(&tfargs);
+
         if (args[3]) {
                 argsize = (SECTOR_WORDS * 4 * args[3]);
+
+ if (tfargs.command_type == IDE_DRIVE_TASK_OUT ||
+ tfargs.command_type == IDE_DRIVE_TASK_RAW_WRITE)
+ writing = 1;
+ else if (tfargs.command_type == IDE_DRIVE_TASK_IN)
+ reading = 1;
+ else
+ return -EPERM;
+
+ if (writing && !access_ok(VERIFY_READ, arg+4, argsize))
+ return -EFAULT;
+ else if (reading && !access_ok(VERIFY_WRITE, arg+4, argsize))
+ return -EFAULT;
+
+ bio = bio_map_user(bdev, arg+4, argsize, reading);
+ if (bio && writing)
+ bio->bi_rw |= (1 << BIO_RW);
+ }
+
+ if (args[3] && !bio) {
+ printk(KERN_INFO "%s: %s: taking slow-path\n",
+ drive->name, __FUNCTION__);
+ argsize = (SECTOR_WORDS * 4 * args[3]);
                 argbuf = kmalloc(argsize, GFP_KERNEL);
                 if (argbuf == NULL)
                         return -ENOMEM;
         }

- if (set_transfer(drive, &tfargs)) {
- xfer_rate = args[1];
- if (ide_ata66_check(drive, &tfargs))
- goto abort;
- }
+ if (bio)
+ err = ide_bio_taskfile(drive, &tfargs, q, bio);
+ else
+ err = ide_raw_taskfile(drive, &tfargs, argbuf);

- tfargs.command_type = ide_cmd_type_parser(&tfargs);
- err = ide_raw_taskfile(drive, &tfargs, argbuf);
+ if (bio)
+ bio_unmap_user(bio, reading);

         if (!err && xfer_rate) {
                 /* active-retuning-calls future */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Apr 23 2003 - 22:00:37 EST