static ssize_t do_io_rw()

in pci/vfio_pci_rdwr.c [97:201]


static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
			void __iomem *io, char __user *buf,
			loff_t off, size_t count, size_t x_start,
			size_t x_end, bool iswrite)
{
	ssize_t done = 0;
	int ret;

	while (count) {
		size_t fillable, filled;

		if (off < x_start)
			fillable = min(count, (size_t)(x_start - off));
		else if (off >= x_end)
			fillable = count;
		else
			fillable = 0;

		if (fillable >= 4 && !(off % 4)) {
			u32 val;

			if (iswrite) {
				if (copy_from_user(&val, buf, 4))
					return -EFAULT;

				ret = vfio_pci_iowrite32(vdev, test_mem,
							 val, io + off);
				if (ret)
					return ret;
			} else {
				ret = vfio_pci_ioread32(vdev, test_mem,
							&val, io + off);
				if (ret)
					return ret;

				if (copy_to_user(buf, &val, 4))
					return -EFAULT;
			}

			filled = 4;
		} else if (fillable >= 2 && !(off % 2)) {
			u16 val;

			if (iswrite) {
				if (copy_from_user(&val, buf, 2))
					return -EFAULT;

				ret = vfio_pci_iowrite16(vdev, test_mem,
							 val, io + off);
				if (ret)
					return ret;
			} else {
				ret = vfio_pci_ioread16(vdev, test_mem,
							&val, io + off);
				if (ret)
					return ret;

				if (copy_to_user(buf, &val, 2))
					return -EFAULT;
			}

			filled = 2;
		} else if (fillable) {
			u8 val;

			if (iswrite) {
				if (copy_from_user(&val, buf, 1))
					return -EFAULT;

				ret = vfio_pci_iowrite8(vdev, test_mem,
							val, io + off);
				if (ret)
					return ret;
			} else {
				ret = vfio_pci_ioread8(vdev, test_mem,
						       &val, io + off);
				if (ret)
					return ret;

				if (copy_to_user(buf, &val, 1))
					return -EFAULT;
			}

			filled = 1;
		} else {
			/* Fill reads with -1, drop writes */
			filled = min(count, (size_t)(x_end - off));
			if (!iswrite) {
				u8 val = 0xFF;
				size_t i;

				for (i = 0; i < filled; i++)
					if (copy_to_user(buf + i, &val, 1))
						return -EFAULT;
			}
		}

		count -= filled;
		done += filled;
		off += filled;
		buf += filled;
	}

	return done;
}