summaryrefslogtreecommitdiffstats
path: root/module/zfs/zvol.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2011-02-25 14:36:01 +0700
committerBrian Behlendorf <[email protected]>2011-05-02 08:54:40 -0700
commitdf554c148ecfdfb7e597f8ab7eee71388b24a19d (patch)
treef55979c7c3c842464a896e1551f93b3cfbd3e66f /module/zfs/zvol.c
parente90a3de3e8b52061aeb0717b031a956cc1e705d5 (diff)
Fix 'zfs set volsize=N pool/dataset'
This change fixes a kernel panic which would occur when resizing a dataset which was not open. The objset_t stored in the zvol_state_t will be set to NULL when the block device is closed. To avoid this issue we pass the correct objset_t as the third arg. The code has also been updated to correctly notify the kernel when the block device capacity changes. For 2.6.28 and newer kernels the capacity change will be immediately detected. For earlier kernels the capacity change will be detected when the device is next opened. This is a known limitation of older kernels. Online ext3 resize test case passes on 2.6.28+ kernels: $ dd if=/dev/zero of=/tmp/zvol bs=1M count=1 seek=1023 $ zpool create tank /tmp/zvol $ zfs create -V 500M tank/zd0 $ mkfs.ext3 /dev/zd0 $ mkdir /mnt/zd0 $ mount /dev/zd0 /mnt/zd0 $ df -h /mnt/zd0 $ zfs set volsize=800M tank/zd0 $ resize2fs /dev/zd0 $ df -h /mnt/zd0 Original-patch-by: Fajar A. Nugraha <[email protected]> Closes #68 Closes #84
Diffstat (limited to 'module/zfs/zvol.c')
-rw-r--r--module/zfs/zvol.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 65a924057..61e22b8ec 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -228,7 +228,7 @@ zvol_check_volsize(uint64_t volsize, uint64_t blocksize)
* Ensure the zap is flushed then inform the VFS of the capacity change.
*/
static int
-zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
+zvol_update_volsize(zvol_state_t *zv, uint64_t volsize, objset_t *os)
{
struct block_device *bdev;
dmu_tx_t *tx;
@@ -236,7 +236,7 @@ zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
ASSERT(MUTEX_HELD(&zvol_state_lock));
- tx = dmu_tx_create(zv->zv_objset);
+ tx = dmu_tx_create(os);
dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
@@ -244,27 +244,35 @@ zvol_update_volsize(zvol_state_t *zv, uint64_t volsize)
return (error);
}
- error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1,
+ error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1,
&volsize, tx);
dmu_tx_commit(tx);
if (error)
return (error);
- error = dmu_free_long_range(zv->zv_objset,
+ error = dmu_free_long_range(os,
ZVOL_OBJ, volsize, DMU_OBJECT_END);
if (error)
return (error);
- zv->zv_volsize = volsize;
- zv->zv_changed = 1;
-
bdev = bdget_disk(zv->zv_disk, 0);
if (!bdev)
- return EIO;
+ return (EIO);
+/*
+ * 2.6.28 API change
+ * Added check_disk_size_change() helper function.
+ */
+#ifdef HAVE_CHECK_DISK_SIZE_CHANGE
+ set_capacity(zv->zv_disk, volsize >> 9);
+ zv->zv_volsize = volsize;
+ check_disk_size_change(zv->zv_disk, bdev);
+#else
+ zv->zv_volsize = volsize;
+ zv->zv_changed = 1;
+ (void) check_disk_change(bdev);
+#endif /* HAVE_CHECK_DISK_SIZE_CHANGE */
- error = check_disk_change(bdev);
- ASSERT3U(error, !=, 0);
bdput(bdev);
return (0);
@@ -311,7 +319,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
goto out_doi;
}
- error = zvol_update_volsize(zv, volsize);
+ error = zvol_update_volsize(zv, volsize, os);
out_doi:
kmem_free(doi, sizeof(dmu_object_info_t));
out: