summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2011-04-22 13:50:17 -0700
committerBrian Behlendorf <[email protected]>2011-04-22 14:55:35 -0700
commite2448b0e62f73f8b9574d74c5b327707b67b703a (patch)
tree3d92b1959de3a26dbd1118c95ea7c692c8ad7d0d
parent6a8f9b6bf0de3e3d09fcfa32e129c978e7641a8f (diff)
Fix spurious -EFAULT when setting I/O scheduler
Occasionally we would see an -EFAULT returned when setting the I/O scheduler on a vdev. This was caused an improperly formatted user mode helper command. This commit restructures the command to something simpler, allocates space for it dynamically to save stack, and removes the retry logic which is no longer needed. Closes #169
-rw-r--r--module/zfs/vdev_disk.c29
1 files changed, 12 insertions, 17 deletions
diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c
index ec627a9c4..5cb3fe279 100644
--- a/module/zfs/vdev_disk.c
+++ b/module/zfs/vdev_disk.c
@@ -118,6 +118,12 @@ vdev_disk_error(zio_t *zio)
* automatically imported on module load so we must do this at device
* open time from the kernel.
*/
+#define SET_SCHEDULER_CMD \
+ "exec 0</dev/null " \
+ " 1>/sys/block/%s/queue/scheduler " \
+ " 2>/dev/null; " \
+ "echo %s"
+
static int
vdev_elevator_switch(vdev_t *v, char *elevator)
{
@@ -125,11 +131,9 @@ vdev_elevator_switch(vdev_t *v, char *elevator)
struct block_device *bdev = vd->vd_bdev;
struct request_queue *q = bdev_get_queue(bdev);
char *device = bdev->bd_disk->disk_name;
- char sh_path[] = "/bin/sh";
- char sh_cmd[128];
- char *argv[] = { sh_path, "-c", sh_cmd };
+ char *argv[] = { "/bin/sh", "-c", NULL, NULL };
char *envp[] = { NULL };
- int count = 0, error;
+ int error;
/* Skip devices which are not whole disks (partitions) */
if (!v->vdev_wholedisk)
@@ -143,23 +147,14 @@ vdev_elevator_switch(vdev_t *v, char *elevator)
if (!strncmp(elevator, "none", 4) && (strlen(elevator) == 4))
return (0);
- /*
- * Set the desired scheduler with a three attempt retry for
- * -EFAULT which has been observed to occur spuriously.
- */
- sprintf(sh_cmd, "%s \"%s\" >/sys/block/%s/queue/scheduler",
- "/bin/echo", elevator, device);
-
- while (++count <= 3) {
- error = call_usermodehelper(sh_path, argv, envp, 1);
- if ((error == 0) || (error != -EFAULT))
- break;
- }
-
+ argv[2] = kmem_asprintf(SET_SCHEDULER_CMD, device, elevator);
+ error = call_usermodehelper(argv[0], argv, envp, 1);
if (error)
printk("ZFS: Unable to set \"%s\" scheduler for %s (%s): %d\n",
elevator, v->vdev_path, device, error);
+ strfree(argv[2]);
+
return (error);
}