@@ -225,15 +225,29 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
struct gendisk *disk = bdev->bd_disk;
struct virtio_blk *vblk = disk->private_data;
+ /* user passes the address of a char[] for return of the id string
+ * and has set char[0] to the array size. copy id string to this
+ * char[] and return the number of non-nul characters in the internal
+ * id string. The caller can then determine if all were received.
+ */
if (cmd == 0x56424944) { /* 'VBID' */
void __user *usr_data = (void __user *)data;
char id_str[VIRTIO_BLK_ID_BYTES];
- int err;
-
- err = virtblk_get_id(disk, id_str);
- if (!err && copy_to_user(usr_data, id_str, VIRTIO_BLK_ID_BYTES))
- err = -EFAULT;
- return err;
+ unsigned char idlen;
+ int rv;
+
+ if (copy_from_user(&idlen, usr_data, sizeof (idlen)))
+ return -EFAULT;
+ if (VIRTIO_BLK_ID_BYTES < idlen)
+ idlen = VIRTIO_BLK_ID_BYTES;
+ if ((rv = virtblk_get_id(disk, id_str)))
+ return rv;
+ if (copy_to_user(usr_data, id_str, idlen))
+ return -EFAULT;
+ for (rv = 0; rv < VIRTIO_BLK_ID_BYTES; ++rv)
+ if (!id_str[rv])
+ break;
+ return rv;
}
/*
* Only allow the generic SCSI ioctls if the host can support it.