Skip to content

Commit

Permalink
Re-scan for partitions on vdev expansion
Browse files Browse the repository at this point in the history
When expansion is requested rescan the partition tables to ensure
that the kernel is not operating with a stale version.  A little
care needs to be taken because as long as the disk has a open
partition the partition table cannot be updated.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
  • Loading branch information
behlendorf committed Jun 21, 2018
1 parent 4fb5d63 commit 79a648a
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 8 deletions.
20 changes: 20 additions & 0 deletions config/kernel-blkdev-get.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
dnl #
dnl # 2.6.38 API, holder argument added to blkdev_get().
dnl #
AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_GET], [
AC_MSG_CHECKING([whether blkdev_get() takes holder])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
], [
struct block_device *bdev = NULL;
int error;
error = blkdev_get(bdev, FMODE_READ, NULL);
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_3ARG_BLKDEV_GET, 1,
[blkdev_gett() takes holder])
], [
AC_MSG_RESULT(no)
])
])
21 changes: 21 additions & 0 deletions config/kernel-blkdev-reread-part.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dnl #
dnl # 4.1 API, exported blkdev_reread_part() symbol, backported to the
dnl # 3.10.0 CentOS 7.x enterprise kernels.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_REREAD_PART], [
AC_MSG_CHECKING([whether blkdev_reread_part() is available])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
], [
struct block_device *bdev = NULL;
int error;
error = blkdev_reread_part(bdev);
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_BLKDEV_REREAD_PART, 1,
[blkdev_reread_part() is available])
], [
AC_MSG_RESULT(no)
])
])
2 changes: 2 additions & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
ZFS_AC_KERNEL_TYPE_FMODE_T
ZFS_AC_KERNEL_BLKDEV_GET
ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH
ZFS_AC_KERNEL_BLKDEV_REREAD_PART
ZFS_AC_KERNEL_OPEN_BDEV_EXCLUSIVE
ZFS_AC_KERNEL_LOOKUP_BDEV
ZFS_AC_KERNEL_INVALIDATE_BDEV_ARGS
Expand Down
26 changes: 26 additions & 0 deletions include/linux/blkdev_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,32 @@ bio_set_bi_error(struct bio *bio, int error)
#define vdev_bdev_close(bdev, md) close_bdev_excl(bdev)
#endif /* HAVE_BLKDEV_GET_BY_PATH | HAVE_OPEN_BDEV_EXCLUSIVE */

/*
* 2.6.38 API change.
* The holder argument was added to blkdev_get()
*/
#ifdef HAVE_3ARG_BLKDEV_GET
#define vdev_bdev_get(bdev) blkdev_get(bdev, FMODE_READ, NULL)
#define vdev_bdev_put(bdev) blkdev_put(bdev, FMODE_READ)
#else
#define vdev_bdev_get(bdev) blkdev_get(bdev, FMODE_READ)
#define vdev_bdev_put(bdev) blkdev_put(bdev, FMODE_READ)
#endif

/*
* 4.1 - x.y.z API,
* 3.10.0 CentOS 7.x API,
* blkdev_reread_part()
*
* For older kernels trigger a re-reading of the partition table by calling
* check_disk_change() which calls flush_disk() to invalidate the device.
*/
#ifdef HAVE_BLKDEV_REREAD_PART
#define vdev_bdev_reread_part(bdev) blkdev_reread_part(bdev)
#else
#define vdev_bdev_reread_part(bdev) check_disk_change(bdev)
#endif /* HAVE_BLKDEV_REREAD_PART */

/*
* 2.6.22 API change
* The function invalidate_bdev() lost it's second argument because
Expand Down
30 changes: 22 additions & 8 deletions module/zfs/vdev_disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,7 @@ vdev_bdev_mode(int smode)
static uint64_t
bdev_capacity(struct block_device *bdev)
{
if (bdev->bd_part != NULL)
return (bdev->bd_part->nr_sects << SECTOR_BITS);
else
return (i_size_read(bdev->bd_inode));
return (i_size_read(bdev->bd_inode));
}

/*
Expand Down Expand Up @@ -208,7 +205,7 @@ static int
vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
uint64_t *ashift)
{
struct block_device *bdev = ERR_PTR(-ENXIO);
struct block_device *disk_bdev, *bdev = ERR_PTR(-ENXIO);
vdev_disk_t *vd;
int count = 0, mode, block_size;

Expand All @@ -223,17 +220,34 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
mode = spa_mode(v->vdev_spa);

/*
* Reopen the device if it is not currently open. Otherwise, when
* expanding a device close and open it to trigger a re-scanning
* of the partition table in order to get an accurate size.
* Reopen the device if it is not currently open. When expanding a
* device get a reference on the disk then close the partition.
* Trigger a re-scanning of the disk partition table to get an
* accurate size, close the disk, and then reopen the partition.
*/
if (v->vdev_tsd != NULL) {
ASSERT(v->vdev_reopening);
vd = v->vdev_tsd;

if (vd->vd_bdev && v->vdev_wholedisk && v->vdev_expanding) {
int error = -EINVAL;

disk_bdev = vd->vd_bdev->bd_contains;
if (vd->vd_bdev != disk_bdev)
error = vdev_bdev_get(disk_bdev);

vdev_bdev_close(vd->vd_bdev, vdev_bdev_mode(mode));
vd->vd_bdev = NULL;

if (error == 0) {
error = vdev_bdev_reread_part(disk_bdev);
if (error) {
vdev_dbgmsg(v, "Error re-reading "
"partition table: %d", error);
}

vdev_bdev_put(disk_bdev);
}
} else {
goto skip_open;
}
Expand Down

0 comments on commit 79a648a

Please sign in to comment.