diff -r a7a805f15593 sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Tue May 26 21:56:18 2009 +0000 +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Wed May 27 21:40:35 2009 +0000 @@ -60,9 +60,9 @@ #include "zfs_prop.h" -/* Used by fstat(1). */ -SYSCTL_INT(_debug_sizeof, OID_AUTO, znode, CTLFLAG_RD, 0, sizeof(znode_t), - "sizeof(znode_t)"); +// XXX: CTLFLAG_MPSAFE +SYSCTL_NODE(_vfs_zfs_znode, OID_AUTO, fstat, CTLFLAG_RD, sysctl_znode_fstat, + ("znode data needed by fstat")); /* * Define ZNODE_STATS to turn on statistic gathering. By default, it is only @@ -1611,3 +1611,30 @@ (void) memmove(buf, path, buf + len - path); return (error); } + +/* + * Expose data of a znode needed by fstat. + */ +static int +sysctl_znode_fstat(SYSCTL_HANDLER_ARGS) +{ + znode_t *zp; + + zp = (znode_t *)arg1; + + if (req->newptr != NULL) + return (EPERM); + if (zp->z_phys == NULL) + return (ENOENT); + error = sysctl_wire_old_buffer(req, + sizeof(zp->z_id) + sizeof(*zp->z_phys)); + if (error) + return (error) + error = SYSCTL_OUT(req, &z_id, sizeof(zp->z_id)); + if (error) + return (error); + error = SYSCTL_OUT(req, zp->z_phys, sizeof(*zp->z_phys)); + if (error) + return (error); + return (0); +} diff -r a7a805f15593 usr.bin/fstat/zfs.c --- a/usr.bin/fstat/zfs.c Tue May 26 21:56:18 2009 +0000 +++ b/usr.bin/fstat/zfs.c Wed May 27 21:40:35 2009 +0000 @@ -52,36 +52,17 @@ #undef dprintf #include -/* - * Offset calculations that are used to get data from znode without having the - * definition. - */ -#define LOCATION_ZID (2 * sizeof(void *)) -#define LOCATION_ZPHYS(zsize) ((zsize) - (2 * sizeof(void *))) - int zfs_filestat(struct vnode *vp, struct filestat *fsp) { - znode_phys_t zphys; + znode_phys_t *zphysp; struct mount mount, *mountptr; uint64_t *zid; - void *znodeptr, *vnodeptr; + void *vnodeptr, *buf; + size_t mibsize; + int mib[5]; char *dataptr; - void *zphys_addr; - size_t len; - int size; - - len = sizeof(size); - if (sysctlbyname("debug.sizeof.znode", &size, &len, NULL, 0) == -1) { - dprintf(stderr, "error getting sysctl\n"); - return (0); - } - znodeptr = malloc(size); - if (znodeptr == NULL) { - dprintf(stderr, "error allocating memory for znode storage\n"); - return (0); - } /* Since we have problems including vnode.h, we'll use the wrappers. */ vnodeptr = getvnodedata(vp); @@ -91,22 +72,30 @@ goto bad; } - /* - * z_id field is stored in the third pointer. We therefore skip the two - * first bytes. - * - * Pointer to the z_phys structure is the next last pointer. Therefore - * go back two bytes from the end. - */ - dataptr = znodeptr; - zid = (uint64_t *)(dataptr + LOCATION_ZID); - zphys_addr = *(void **)(dataptr + LOCATION_ZPHYS(size)); - - if (!KVM_READ(zphys_addr, &zphys, sizeof(zphys))) { - dprintf(stderr, "can't read znode_phys at %p for pid %d\n", - zphys_addr, Pid); + /* Read ZFS specific information via sysctl. */ + len = sizeof(size); + mibsize = sizeof(mib) / sizeof(mib[0]) + if (sysctlnametomib("vfs.zfs.znode.fstat", mib, mibsize) == 1) + dprintf(stderr, "error getting sysctl mib\n"); + return (0); + } + mib[4] = vnodeptr; + if (sysctl(mib, mibsize, NULL, &bufsize, NULL, 0) == -1) { + dprintf(stderr, "error getting sysctl\n"); + return (0); + } + buf = malloc(bufsize); + if (buf == NULL) { + dprintf(stderr, "error allocating memory for sysctl storage\n"); + return (0); + } + if (sysctl(mib, mibsize, buf, &bufsize, NULL, 0) == -1) { + dprintf(stderr, "error getting sysctl\n"); goto bad; } + dataptr = buf; + zid = sizeof(*zid)dataptr; + zphysp = (znode_phys_t *)(dataptr + sizeof(*zid)); /* Get the mount pointer, and read from the address. */ mountptr = getvnodemount(vp); @@ -123,12 +112,12 @@ * be that we're casting mode-variables from 64-bit to 8-bit or simply * error in the mode-to-string function. */ - fsp->mode = (mode_t)zphys.zp_mode; - fsp->size = (u_long)zphys.zp_size; - fsp->rdev = (dev_t)zphys.zp_rdev; - free(znodeptr); + fsp->mode = (mode_t)zphys->zp_mode; + fsp->size = (u_long)zphys->zp_size; + fsp->rdev = (dev_t)zphys->zp_rdev; + free(buf); return (1); bad: - free(znodeptr); + free(buf); return (0); }