diff options
Diffstat (limited to 'module/zfs/vdev_disk.c')
-rw-r--r-- | module/zfs/vdev_disk.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c index cdb8f78e2..9b51ecc1d 100644 --- a/module/zfs/vdev_disk.c +++ b/module/zfs/vdev_disk.c @@ -244,12 +244,12 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, { struct block_device *bdev = ERR_PTR(-ENXIO); vdev_disk_t *vd; - int mode, block_size; + int count = 0, mode, block_size; /* Must have a pathname and it must be absolute. */ if (v->vdev_path == NULL || v->vdev_path[0] != '/') { v->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; - return (EINVAL); + return (SET_ERROR(EINVAL)); } /* @@ -264,7 +264,7 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, vd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP); if (vd == NULL) - return (ENOMEM); + return (SET_ERROR(ENOMEM)); /* * Devices are always opened by the path provided at configuration @@ -279,16 +279,35 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, * /dev/[hd]d devices which may be reordered due to probing order. * Devices in the wrong locations will be detected by the higher * level vdev validation. + * + * The specified paths may be briefly removed and recreated in + * response to udev events. This should be exceptionally unlikely + * because the zpool command makes every effort to verify these paths + * have already settled prior to reaching this point. Therefore, + * a ENOENT failure at this point is highly likely to be transient + * and it is reasonable to sleep and retry before giving up. In + * practice delays have been observed to be on the order of 100ms. */ mode = spa_mode(v->vdev_spa); if (v->vdev_wholedisk && v->vdev_expanding) bdev = vdev_disk_rrpart(v->vdev_path, mode, vd); - if (IS_ERR(bdev)) + + while (IS_ERR(bdev) && count < 50) { bdev = vdev_bdev_open(v->vdev_path, vdev_bdev_mode(mode), zfs_vdev_holder); + if (unlikely(PTR_ERR(bdev) == -ENOENT)) { + msleep(10); + count++; + } else if (IS_ERR(bdev)) { + break; + } + } + if (IS_ERR(bdev)) { + dprintf("failed open v->vdev_path=%s, error=%d count=%d\n", + v->vdev_path, -PTR_ERR(bdev), count); kmem_free(vd, sizeof (vdev_disk_t)); - return (-PTR_ERR(bdev)); + return (SET_ERROR(-PTR_ERR(bdev))); } v->vdev_tsd = vd; |