Author: tsoome
Date: Thu Nov  2 08:47:03 2017
New Revision: 325310
URL: https://svnweb.freebsd.org/changeset/base/325310

Log:
  zfs.c:vdev_read() needs to be careful about large sectors
  
  Using the same implementation as done in efi/boot1. We must handle smaller
  than sector size IO etc.
  
  Differential Revision:        https://reviews.freebsd.org/D12850

Modified:
  head/sys/boot/zfs/zfs.c

Modified: head/sys/boot/zfs/zfs.c
==============================================================================
--- head/sys/boot/zfs/zfs.c     Thu Nov  2 07:25:59 2017        (r325309)
+++ head/sys/boot/zfs/zfs.c     Thu Nov  2 08:47:03 2017        (r325310)
@@ -368,17 +368,61 @@ zfs_readdir(struct open_file *f, struct dirent *d)
 }
 
 static int
-vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t size)
+vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t bytes)
 {
-       int fd;
+       int fd, ret;
+       size_t res, size, remainder, rb_size, blksz;
+       unsigned secsz;
+       off_t off;
+       char *bouncebuf, *rb_buf;
 
        fd = (uintptr_t) priv;
-       lseek(fd, offset, SEEK_SET);
-       if (read(fd, buf, size) == size) {
-               return 0;
-       } else {
-               return (EIO);
+       bouncebuf = NULL;
+
+       ret = ioctl(fd, DIOCGSECTORSIZE, &secsz);
+       if (ret != 0)
+               return (ret);
+
+       off = offset / secsz;
+       remainder = offset % secsz;
+       if (lseek(fd, off * secsz, SEEK_SET) == -1)
+               return (errno);
+
+       rb_buf = buf;
+       rb_size = bytes;
+       size = roundup2(bytes + remainder, secsz);
+       blksz = size;
+       if (remainder != 0 || size != bytes) {
+               bouncebuf = zfs_alloc(secsz);
+               if (bouncebuf == NULL) {
+                       printf("vdev_read: out of memory\n");
+                       return (ENOMEM);
+               }
+               rb_buf = bouncebuf;
+               blksz = rb_size - remainder;
        }
+
+       while (bytes > 0) {
+               res = read(fd, rb_buf, rb_size);
+               if (res != rb_size) {
+                       ret = EIO;
+                       goto error;
+               }
+               if (bytes < blksz)
+                       blksz = bytes;
+               if (bouncebuf != NULL)
+                       memcpy(buf, rb_buf + remainder, blksz);
+               buf = (void *)((uintptr_t)buf + blksz);
+               bytes -= blksz;
+               remainder = 0;
+               blksz = rb_size;
+       }
+
+       ret = 0;
+error:
+       if (bouncebuf != NULL)
+               zfs_free(bouncebuf, secsz);
+       return (ret);
 }
 
 static int
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to