summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2011-02-25 11:26:41 -0800
committerBrian Behlendorf <[email protected]>2011-02-25 11:37:11 -0800
commitfdcd952b4d93f9c9d9ec89a95ef6e2964c27da95 (patch)
treeca6af7fa72441aa1d2c08d0ebca6e83907593445 /module/zfs
parent4c0d8e50b99b4f3b4a9b7bc67ac7fc4e406f5755 (diff)
Fix set block scheduler warnings
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.
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/vdev_disk.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c
index aba3c4ab5..69bc53b4b 100644
--- a/module/zfs/vdev_disk.c
+++ b/module/zfs/vdev_disk.c
@@ -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;
}