diff -r 618609ec5c0b sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h Wed May 27 17:02:10 2009 +0000 +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h Wed May 27 22:09:44 2009 +0000 @@ -161,6 +161,16 @@ */ } znode_phys_t; +#ifdef _ZFS_FSTAT +/* + * ZFS information exposed to fstat. + */ +typedef struct zfs_fstat { + uint64_t z_id; /* Must match type in znode. */ + znode_phys_t z_phys; +} zfs_fstat_t; +#endif + /* * Directory entry locks control access to directory entries. * They are used to protect creates, deletes, and renames. diff -r 618609ec5c0b sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Wed May 27 17:02:10 2009 +0000 +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Wed May 27 22:09:44 2009 +0000 @@ -55,14 +55,15 @@ #include #include #include +#define _ZFS_FSTAT #include #include #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 +1612,29 @@ (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) +{ + zfs_fstat_t z_fstat; + 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(zfs_fstat_t)); + if (error) + return (error) + z_fstat.z_id = zp->z_id; + z_fstat.z_phys = *zp_z_phys; + error = SYSCTL_OUT(req, &z_fstat, sizeof(zfs_fstat_t)); + if (error) + return (error); + return (0); +} diff -r 618609ec5c0b usr.bin/fstat/zfs.c --- a/usr.bin/fstat/zfs.c Wed May 27 17:02:10 2009 +0000 +++ b/usr.bin/fstat/zfs.c Wed May 27 22:09:44 2009 +0000 @@ -41,6 +41,7 @@ #include #include #include +#define _ZFS_FSTAT #include #include @@ -52,83 +53,55 @@ #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; + zfs_fstat_t z_fstatp; struct mount mount, *mountptr; - uint64_t *zid; - void *znodeptr, *vnodeptr; - 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); - } + void *vnodeptr + size_t mibsize, size; + int mib[5]; /* Since we have problems including vnode.h, we'll use the wrappers. */ vnodeptr = getvnodedata(vp); if (!KVM_READ(vnodeptr, znodeptr, (size_t)size)) { dprintf(stderr, "can't read znode at %p for pid %d\n", (void *)vnodeptr, Pid); - goto bad; + return (0); } - /* - * 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); - goto bad; + /* 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, &z_fstatp, &size, NULL, 0) == -1) { + dprintf(stderr, "error getting sysctl\n"); + return (0); + } + zphysp = (znode_phys_t *)&z_fstatp.z_phys; /* Get the mount pointer, and read from the address. */ mountptr = getvnodemount(vp); if (!KVM_READ(mountptr, &mount, sizeof(mount))) { dprintf(stderr, "can't read mount at %p for pid %d\n", (void *)mountptr, Pid); - goto bad; + return (0); } fsp->fsid = (long)mount.mnt_stat.f_fsid.val[0]; - fsp->fileid = *zid; + fsp->fileid = z_fstatp.z_id; /* * XXX: Shows up wrong in output, but UFS has this error too. Could * 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; return (1); -bad: - free(znodeptr); - return (0); }