[luis.garces@gmail.com: kern/164445: [zfs][patch] WAS: lseek(2) always returns ENXIO with SEEK_DATA/SEEK_HOLE on 9.0 64bit ZFS]

Mark Linimon linimon at lonesome.com
Mon Mar 12 00:36:42 UTC 2012


----- Forwarded message from Luis Garces-Erice <luis.garces at gmail.com> -----

Date: Wed, 7 Mar 2012 20:53:35 +0100
From: Luis Garces-Erice <luis.garces at gmail.com>
To: freebsd-bugs at freebsd.org
Subject: kern/164445: [zfs][patch] WAS: lseek(2) always returns ENXIO with
	SEEK_DATA/SEEK_HOLE on 9.0 64bit ZFS

Hi all

after digging a bit more into this
(http://www.freebsd.org/cgi/query-pr.cgi?pr=164445), I've found the
problem to be in ZFS or below. The patch attached addresses the
symptom, but the problem remains.

When invoking SEEK_DATA/SEEK_HOLE on a file on ZFS in FreeBSD 9.0 64
bit, the functions ddi_copyin and ddi_copyout in zfs_ioctl() do not
copy the offset passed from the application to the ioctl. The offset
is passed correctly to zfs_ioctl(), though, but those functions copy
garbage into the offset used by zfs_holey(). The corrupted offset is
often bigger than the file, and thus the ioctl returns ENXIO.

The patch does the copy of the offset passed from the application
correctly, and allows lseek(2) with SEEK_DATA/SEEK_HOLE to be used on
ZFS, but it is not a solution. I couldn't see a problem in the
assembler of the copyin and copyout functions in
sys/amd64/amd64/support.S, but I might be wrong, I'm no assembler
expert.


-- 
Luis
****

diff -w -u -r sys.orig/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
--- sys.orig/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	2012-01-03 04:27:03.000000000 +0100
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	2012-03-06 11:26:27.000000000 +0100
@@ -296,6 +296,8 @@
 		if (ddi_copyin((void *)data, &off, sizeof (off), flag))
 			return (EFAULT);
 
+		// ddi_copyin did not copy the offset
+		off = (offset_t)*((offset_t *)data);
 		zp = VTOZ(vp);
 		zfsvfs = zp->z_zfsvfs;
 		ZFS_ENTER(zfsvfs);
@@ -308,6 +310,8 @@
 			return (error);
 		if (ddi_copyout(&off, (void *)data, sizeof (off), flag))
 			return (EFAULT);
+		// ddi_copyout did not copy the offset
+		*((offset_t *)data)=off;
 		return (0);
 	}
 	return (ENOTTY);

----- End forwarded message -----


More information about the freebsd-fs mailing list