mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 03:09:34 +03:00
Modify vdev_elevator_switch() to use elevator_change()
As of Linux 2.6.36 an elevator_change() interface was added. This commit updates vdev_elevator_switch() to use this interface when available, otherwise it falls back to the usermodehelper method. Original-patch-by: foobarz <sysop@xeon.(none)> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #906
This commit is contained in:
parent
2f342404c1
commit
6d1d976b2c
25
config/kernel-elevator-change.m4
Normal file
25
config/kernel-elevator-change.m4
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # 2.6.36 API change
|
||||||
|
dnl # Verify the elevator_change() symbol is available.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_ELEVATOR_CHANGE], [
|
||||||
|
AC_MSG_CHECKING([whether elevator_change() is available])
|
||||||
|
tmp_flags="$EXTRA_KCFLAGS"
|
||||||
|
EXTRA_KCFLAGS="-Wno-unused-but-set-variable"
|
||||||
|
ZFS_LINUX_TRY_COMPILE([
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/elevator.h>
|
||||||
|
],[
|
||||||
|
int ret;
|
||||||
|
struct request_queue *q = NULL;
|
||||||
|
char *elevator = NULL;
|
||||||
|
ret = elevator_change(q, elevator);
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_ELEVATOR_CHANGE, 1,
|
||||||
|
[elevator_change() is available])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
EXTRA_KCFLAGS="$tmp_flags"
|
||||||
|
])
|
@ -67,6 +67,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
|
|||||||
ZFS_AC_KERNEL_BDI
|
ZFS_AC_KERNEL_BDI
|
||||||
ZFS_AC_KERNEL_BDI_SETUP_AND_REGISTER
|
ZFS_AC_KERNEL_BDI_SETUP_AND_REGISTER
|
||||||
ZFS_AC_KERNEL_SET_NLINK
|
ZFS_AC_KERNEL_SET_NLINK
|
||||||
|
ZFS_AC_KERNEL_ELEVATOR_CHANGE
|
||||||
|
|
||||||
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
|
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
|
||||||
KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
|
KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
|
||||||
|
@ -111,19 +111,7 @@ vdev_disk_error(zio_t *zio)
|
|||||||
* elevator to do the maximum front/back merging allowed by the
|
* elevator to do the maximum front/back merging allowed by the
|
||||||
* physical device. This yields the largest possible requests for
|
* physical device. This yields the largest possible requests for
|
||||||
* the device with the lowest total overhead.
|
* the device with the lowest total overhead.
|
||||||
*
|
|
||||||
* Unfortunately we cannot directly call the elevator_switch() function
|
|
||||||
* because it is not exported from the block layer. This means we have
|
|
||||||
* to use the sysfs interface and a user space upcall. Pools will be
|
|
||||||
* 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
|
static int
|
||||||
vdev_elevator_switch(vdev_t *v, char *elevator)
|
vdev_elevator_switch(vdev_t *v, char *elevator)
|
||||||
{
|
{
|
||||||
@ -131,8 +119,6 @@ vdev_elevator_switch(vdev_t *v, char *elevator)
|
|||||||
struct block_device *bdev = vd->vd_bdev;
|
struct block_device *bdev = vd->vd_bdev;
|
||||||
struct request_queue *q = bdev_get_queue(bdev);
|
struct request_queue *q = bdev_get_queue(bdev);
|
||||||
char *device = bdev->bd_disk->disk_name;
|
char *device = bdev->bd_disk->disk_name;
|
||||||
char *argv[] = { "/bin/sh", "-c", NULL, NULL };
|
|
||||||
char *envp[] = { NULL };
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Skip devices which are not whole disks (partitions) */
|
/* Skip devices which are not whole disks (partitions) */
|
||||||
@ -147,14 +133,33 @@ vdev_elevator_switch(vdev_t *v, char *elevator)
|
|||||||
if (!strncmp(elevator, "none", 4) && (strlen(elevator) == 4))
|
if (!strncmp(elevator, "none", 4) && (strlen(elevator) == 4))
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
argv[2] = kmem_asprintf(SET_SCHEDULER_CMD, device, elevator);
|
#ifdef HAVE_ELEVATOR_CHANGE
|
||||||
error = call_usermodehelper(argv[0], argv, envp, 1);
|
error = elevator_change(q, elevator);
|
||||||
|
#else
|
||||||
|
/* For pre-2.6.36 kernels elevator_change() is not available.
|
||||||
|
* Therefore we fall back to using a usermodehelper to echo the
|
||||||
|
* elevator into sysfs; This requires /bin/echo and sysfs to be
|
||||||
|
* mounted which may not be true early in the boot process.
|
||||||
|
*/
|
||||||
|
# define SET_SCHEDULER_CMD \
|
||||||
|
"exec 0</dev/null " \
|
||||||
|
" 1>/sys/block/%s/queue/scheduler " \
|
||||||
|
" 2>/dev/null; " \
|
||||||
|
"echo %s"
|
||||||
|
|
||||||
|
{
|
||||||
|
char *argv[] = { "/bin/sh", "-c", NULL, NULL };
|
||||||
|
char *envp[] = { NULL };
|
||||||
|
|
||||||
|
argv[2] = kmem_asprintf(SET_SCHEDULER_CMD, device, elevator);
|
||||||
|
error = call_usermodehelper(argv[0], argv, envp, 1);
|
||||||
|
strfree(argv[2]);
|
||||||
|
}
|
||||||
|
#endif /* HAVE_ELEVATOR_CHANGE */
|
||||||
if (error)
|
if (error)
|
||||||
printk("ZFS: Unable to set \"%s\" scheduler for %s (%s): %d\n",
|
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user