X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fvdev_disk.c;h=cbf0a4d4fb0896c74f34ceeb4899d2f91675eea5;hb=36f86f73f68548f46eb3229c8adf583d59fa9988;hp=eee03d08055d46291ac011b4118213b9c32446f9;hpb=b5a28807cdec3c05aa69cbe4689cd914dc94783a;p=zfs.git diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c index eee03d0..cbf0a4d 100644 --- a/module/zfs/vdev_disk.c +++ b/module/zfs/vdev_disk.c @@ -111,19 +111,7 @@ vdev_disk_error(zio_t *zio) * elevator to do the maximum front/back merging allowed by the * physical device. This yields the largest possible requests for * 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/sys/block/%s/queue/scheduler " \ - " 2>/dev/null; " \ - "echo %s" - static int vdev_elevator_switch(vdev_t *v, char *elevator) { @@ -131,12 +119,17 @@ 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 *argv[] = { "/bin/sh", "-c", NULL, NULL }; - char *envp[] = { NULL }; int error; - /* Skip devices which are not whole disks (partitions) */ - if (!v->vdev_wholedisk) + /* + * Skip devices which are not whole disks (partitions). + * Device-mapper devices are excepted since they may be whole + * disks despite the vdev_wholedisk flag, in which case we can + * and should switch the elevator. If the device-mapper device + * does not have an elevator (i.e. dm-raid, dm-crypt, etc.) the + * "Skip devices without schedulers" check below will fail. + */ + if (!v->vdev_wholedisk && strncmp(device, "dm-", 3) != 0) return (0); /* Skip devices without schedulers (loop, ram, dm, etc) */ @@ -147,14 +140,33 @@ vdev_elevator_switch(vdev_t *v, char *elevator) if (!strncmp(elevator, "none", 4) && (strlen(elevator) == 4)) return (0); - argv[2] = kmem_asprintf(SET_SCHEDULER_CMD, device, elevator); - error = call_usermodehelper(argv[0], argv, envp, 1); +#ifdef HAVE_ELEVATOR_CHANGE + 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/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, UMH_WAIT_PROC); + strfree(argv[2]); + } +#endif /* HAVE_ELEVATOR_CHANGE */ 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); } @@ -224,7 +236,8 @@ vdev_disk_rrpart(const char *path, int mode, vdev_disk_t *vd) } static int -vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *ashift) +vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, + uint64_t *ashift) { struct block_device *bdev = ERR_PTR(-ENXIO); vdev_disk_t *vd; @@ -236,7 +249,7 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *ashift) return EINVAL; } - vd = kmem_zalloc(sizeof(vdev_disk_t), KM_SLEEP); + vd = kmem_zalloc(sizeof(vdev_disk_t), KM_PUSHPAGE); if (vd == NULL) return ENOMEM; @@ -288,6 +301,9 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *ashift) /* Physical volume size in bytes */ *psize = bdev_capacity(bdev); + /* TODO: report possible expansion size */ + *max_psize = *psize; + /* Based on the minimum sector size set the block size */ *ashift = highbit(MAX(block_size, SPA_MINBLOCKSIZE)) - 1; @@ -320,7 +336,7 @@ vdev_disk_dio_alloc(int bio_count) int i; dr = kmem_zalloc(sizeof(dio_request_t) + - sizeof(struct bio *) * bio_count, KM_SLEEP); + sizeof(struct bio *) * bio_count, KM_PUSHPAGE); if (dr) { init_completion(&dr->dr_comp); atomic_set(&dr->dr_ref, 0); @@ -524,7 +540,6 @@ retry: if (dr->dr_bio_count == i) { vdev_disk_dio_free(dr); bio_count *= 2; - printk("WARNING: Resized bio's/dio to %d\n",bio_count); goto retry; } @@ -789,7 +804,7 @@ vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config) } size = P2ALIGN_TYPED(s, sizeof(vdev_label_t), uint64_t); - label = vmem_alloc(sizeof(vdev_label_t), KM_SLEEP); + label = vmem_alloc(sizeof(vdev_label_t), KM_PUSHPAGE); for (i = 0; i < VDEV_LABELS; i++) { uint64_t offset, state, txg = 0;