> I tried to copy a 8GB Xen domU disk image from a zvol device
> to an image file on an ufs filesystem, and was surprised that
> reading from the zvol character device doesn''t detect
"EOF".
>
> On snv_66 (sparc) and snv_73 (x86) I can reproduce it, like this:
>
> # zfs create -V 1440k tank/floppy-img
>
> # dd if=/dev/zvol/dsk/tank/floppy-img of=/dev/null
> bs=1k count=2000
> 1440+0 records in
> 1440+0 records out
> (no problem on block device, we detect eof after
> reading 1440k)
>
>
> # dd if=/dev/zvol/rdsk/tank/floppy-img of=/dev/null
> bs=1k count=2000
> 2000+0 records in
> 2000+0 records out
>
> (Oops! No eof detected on zvol raw device after
> reading 1440k?)
After looking at the code in usr/src/uts/common/fs/zfs/zvol.c
it seems that neither zvol_read() nor zvol_write() cares about
the zvol''s "zv_volsize".
I think we need something like this:
diff -r 26be3efbd346 usr/src/uts/common/fs/zfs/zvol.c
--- a/usr/src/uts/common/fs/zfs/zvol.c Thu Aug 23 00:53:10 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zvol.c Thu Aug 23 16:30:41 2007 +0200
@@ -904,6 +904,7 @@ zvol_read(dev_t dev, uio_t *uio, cred_t
{
minor_t minor = getminor(dev);
zvol_state_t *zv;
+ uint64_t volsize;
rl_t *rl;
int error = 0;
@@ -914,10 +915,16 @@ zvol_read(dev_t dev, uio_t *uio, cred_t
if (zv == NULL)
return (ENXIO);
+ volsize = zv->zv_volsize;
+
rl = zfs_range_lock(&zv->zv_znode, uio->uio_loffset,
uio->uio_resid,
RL_READER);
- while (uio->uio_resid > 0) {
+ while (uio->uio_resid > 0 && uio->uio_loffset <
volsize) {
uint64_t bytes = MIN(uio->uio_resid, DMU_MAX_ACCESS >>
1);
+
+ /* don''t read past the end */
+ if (bytes > volsize - uio->uio_loffset)
+ bytes = volsize - uio->uio_loffset;
error = dmu_read_uio(zv->zv_objset, ZVOL_OBJ, uio, bytes);
if (error)
@@ -933,6 +940,7 @@ zvol_write(dev_t dev, uio_t *uio, cred_t
{
minor_t minor = getminor(dev);
zvol_state_t *zv;
+ uint64_t volsize;
rl_t *rl;
int error = 0;
@@ -943,13 +951,19 @@ zvol_write(dev_t dev, uio_t *uio, cred_t
if (zv == NULL)
return (ENXIO);
+ volsize = zv->zv_volsize;
+
rl = zfs_range_lock(&zv->zv_znode, uio->uio_loffset,
uio->uio_resid,
RL_WRITER);
- while (uio->uio_resid > 0) {
+ while (uio->uio_resid > 0 && uio->uio_loffset <
volsize) {
uint64_t bytes = MIN(uio->uio_resid, DMU_MAX_ACCESS >>
1);
uint64_t off = uio->uio_loffset;
-
- dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
+ dmu_tx_t *tx;
+
+ if (bytes > volsize - off) /* don''t write past
the end */
+ bytes = volsize - off;
+
+ tx = dmu_tx_create(zv->zv_objset);
dmu_tx_hold_write(tx, ZVOL_OBJ, off, bytes);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
This message posted from opensolaris.org