* 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, char *device)
+vdev_elevator_switch(vdev_t *v, char *elevator)
{
- char sh_path[] = "/bin/sh";
- char sh_cmd[128];
- char *argv[] = { sh_path, "-c", sh_cmd };
+ 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 *argv[] = { "/bin/sh", "-c", NULL, NULL };
char *envp[] = { NULL };
int error;
- if (!strncmp(elevator, "none", 4) && (strlen(elevator) == 4))
+ /* Skip devices which are not whole disks (partitions) */
+ if (!v->vdev_wholedisk)
+ return (0);
+
+ /* Skip devices without schedulers (loop, ram, dm, etc) */
+ if (!q->elevator || !blk_queue_stackable(q))
return (0);
- sprintf(sh_cmd, "%s \"%s\" >/sys/block/%s/queue/scheduler",
- "/bin/echo", elevator, device);
+ /* Leave existing scheduler when set to "none" */
+ if (!strncmp(elevator, "none", 4) && (strlen(elevator) == 4))
+ return (0);
- error = call_usermodehelper(sh_path, argv, envp, 1);
+ 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);
+ elevator, v->vdev_path, device, error);
+
+ strfree(argv[2]);
return (error);
}
*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;
}