Fix set block scheduler warnings
authorBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 25 Feb 2011 19:26:41 +0000 (11:26 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 25 Feb 2011 19:37:11 +0000 (11:37 -0800)
There were two cases when attempting to set the vdev block device
scheduler which would causes console warnings.

The first case was when the vdev used a loop, ram, dm, or other
such device which doesn't support a configurable scheduler.  In
these cases attempting to set a scheduler is pointless and can
be safely skipped.

The secord case is slightly more troubling.  We were seeing
transient cases where setting the elevator would return -EFAULT.
On retry everything is fine so there appears to be a small window
where this is possible.  To handle that case we silently retry
up to three times before reporting the warning.

In all of the above cases the warning is harmless and at worse you
may see slightly different performance characteristics from one
or more of your vdevs.

module/zfs/vdev_disk.c

index aba3c4a..69bc53b 100644 (file)
@@ -119,24 +119,42 @@ vdev_disk_error(zio_t *zio)
  * open time from the kernel.
  */
 static int
-vdev_elevator_switch(vdev_t *v, char *elevator, char *device)
+vdev_elevator_switch(vdev_t *v, char *elevator)
 {
+       vdev_disk_t *vd = v->vdev_tsd;
+       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 *envp[] = { NULL };
-       int error;
+       int count = 0, error;
+
+       /* Skip devices without schedulers (loop, ram, dm, etc) */
+       if (!q->elevator || !blk_queue_stackable(q))
+               return (0);
 
+       /* Leave existing scheduler when set to "none" */
        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);
 
-       error = call_usermodehelper(sh_path, argv, envp, 1);
+       while (++count <= 3) {
+               error = call_usermodehelper(sh_path, argv, envp, 1);
+               if ((error == 0) || (error != -EFAULT))
+                      break;
+       }
+
        if (error)
                printk("ZFS: Unable to set \"%s\" scheduler for %s (%s): %d\n",
-                   elevator, v->vdev_path, device, error);
+                      elevator, v->vdev_path, device, error);
 
        return (error);
 }
@@ -207,8 +225,7 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *ashift)
        *ashift = highbit(MAX(block_size, SPA_MINBLOCKSIZE)) - 1;
 
        /* Try to set the io scheduler elevator algorithm */
-       (void) vdev_elevator_switch(v, zfs_vdev_scheduler,
-           bdev->bd_disk->disk_name);
+       (void) vdev_elevator_switch(v, zfs_vdev_scheduler);
 
        return 0;
 }