Index: sys/kern/kern_proc.c =================================================================== --- sys/kern/kern_proc.c +++ sys/kern/kern_proc.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -2444,6 +2445,27 @@ PA_UNLOCK_COND(locked_pa); } +/* + * Build the pseudo-path for SysV and POSIX shm, if appropriate. + */ +static void +get_fullpath(char *path, size_t size, vm_object_t object) +{ + void *data; + + switch (vm_object_path_info(object, &data)) { + case OBJPATH_NONE: + case OBJPATH_VNODE: + break; + case OBJPATH_SHMP: + shm_fullpath(path, size, data); + break; + case OBJPATH_SHMS: + sysvshm_fullpath(path, size, data); + break; + } +} + /* * Must be called with the process locked and will return unlocked. */ @@ -2536,12 +2558,14 @@ last_timestamp = map->timestamp; vm_map_unlock_read(map); - freepath = NULL; - fullpath = ""; + kve->kve_path[0] = '\0'; if (lobj != NULL) { kve->kve_type = vm_object_kvme_type(lobj, &vp); if (vp != NULL) vref(vp); + else get_fullpath(kve->kve_path, + sizeof(kve->kve_path), + lobj); if (lobj != obj) VM_OBJECT_RUNLOCK(lobj); @@ -2549,6 +2573,8 @@ kve->kve_shadow_count = obj->shadow_count; VM_OBJECT_RUNLOCK(obj); if (vp != NULL) { + freepath = NULL; + fullpath = ""; vn_fullpath(curthread, vp, &fullpath, &freepath); kve->kve_vn_type = vntype_to_kinfo(vp->v_type); @@ -2568,6 +2594,9 @@ kve->kve_status = KF_ATTR_VALID; } vput(vp); + strlcpy(kve->kve_path, fullpath, sizeof(kve->kve_path)); + if (freepath != NULL) + free(freepath, M_TEMP); } } else { kve->kve_type = KVME_TYPE_NONE; @@ -2575,10 +2604,6 @@ kve->kve_shadow_count = 0; } - strlcpy(kve->kve_path, fullpath, sizeof(kve->kve_path)); - if (freepath != NULL) - free(freepath, M_TEMP); - /* Pack record size down */ if ((flags & KERN_VMMAP_PACK_KINFO) != 0) kve->kve_structsize = Index: sys/kern/sysv_shm.c =================================================================== --- sys/kern/sysv_shm.c +++ sys/kern/sysv_shm.c @@ -755,6 +755,7 @@ VM_OBJECT_WLOCK(shm_object); vm_object_clear_flag(shm_object, OBJ_ONEMAPPING); vm_object_set_flag(shm_object, OBJ_COLORED | OBJ_NOSPLIT); + vm_object_set_path_info(shm_object, OBJPATH_SHMS, shmseg); VM_OBJECT_WUNLOCK(shm_object); shmseg->object = shm_object; @@ -779,6 +780,17 @@ return (0); } +void +sysvshm_fullpath(char *path, size_t size, void *data) +{ + struct shmid_kernel *shmseg; + + shmseg = (struct shmid_kernel *) data; + + if (shmseg != NULL && shmseg->u.shm_perm.key != IPC_PRIVATE) + snprintf(path, size, "%ld", shmseg->u.shm_perm.key); +} + #ifndef _SYS_SYSPROTO_H_ struct shmget_args { key_t key; Index: sys/kern/uipc_shm.c =================================================================== --- sys/kern/uipc_shm.c +++ sys/kern/uipc_shm.c @@ -558,6 +558,7 @@ KASSERT(shmfd->shm_object != NULL, ("shm_create: vm_pager_allocate")); shmfd->shm_object->pg_color = 0; VM_OBJECT_WLOCK(shmfd->shm_object); + vm_object_set_path_info(shmfd->shm_object, OBJPATH_SHMP, shmfd); vm_object_clear_flag(shmfd->shm_object, OBJ_ONEMAPPING); vm_object_set_flag(shmfd->shm_object, OBJ_COLORED | OBJ_NOSPLIT); VM_OBJECT_WUNLOCK(shmfd->shm_object); @@ -686,6 +687,10 @@ FREAD | FWRITE); if (error) return (error); + VM_OBJECT_WLOCK(map->sm_shmfd->shm_object); + vm_object_set_path_info(map->sm_shmfd->shm_object, + OBJPATH_NONE, NULL); + VM_OBJECT_WUNLOCK(map->sm_shmfd->shm_object); map->sm_shmfd->shm_path = NULL; LIST_REMOVE(map, sm_link); shm_drop(map->sm_shmfd); @@ -1095,6 +1100,17 @@ return (0); } +void +shm_fullpath(char *path, size_t size, void *data) +{ + struct shmfd *shmfd = (struct shmfd *) data; + + if (shmfd->shm_path == NULL) + strlcpy(path, "", size); + else + strlcpy(path, shmfd->shm_path, size); +} + static int shm_fill_kinfo_locked(struct shmfd *shmfd, struct kinfo_file *kif, bool list) { Index: sys/sys/mman.h =================================================================== --- sys/sys/mman.h +++ sys/sys/mman.h @@ -242,6 +242,7 @@ struct shmfd *shm_hold(struct shmfd *shmfd); void shm_drop(struct shmfd *shmfd); int shm_dotruncate(struct shmfd *shmfd, off_t length); +void shm_fullpath(char *path, size_t size, void *data); extern struct fileops shm_ops; #else /* !_KERNEL */ Index: sys/sys/shm.h =================================================================== --- sys/sys/shm.h +++ sys/sys/shm.h @@ -155,6 +155,7 @@ void shmexit(struct vmspace *); void shmfork(struct proc *, struct proc *); +void sysvshm_fullpath(char *path, size_t size, void *data); #else /* !_KERNEL */ Index: sys/vm/vm_object.h =================================================================== --- sys/vm/vm_object.h +++ sys/vm/vm_object.h @@ -168,6 +168,15 @@ void *swp_tmpfs; struct pctrie swp_blks; } swp; + + /* + * For OBJT_PHYS (no pager), OBJT_DEFAULT and OBJT_SWAP if + * not OBJ_TMPFS, we can store a back pointer that can be + * used to genenrate a path for procstat. + */ + struct { + void *data; + } path_info; } un_pager; struct ucred *cred; vm_ooffset_t charge; @@ -193,6 +202,18 @@ #define OBJ_DISCONNECTWNT 0x4000 /* disconnect from vnode wanted */ #define OBJ_TMPFS 0x8000 /* has tmpfs vnode allocated */ +/* + * If the OBJ_TMPFS flag is not set, we overload the OBJ_TMPS_DIRTY flag to + * select between SysV and POSIX shm path_info. + */ +#define OBJ_SYSV_SHM OBJ_TMPFS_DIRTY + +/* Values returned by vm_object_path_info. */ +#define OBJPATH_NONE 0x0 /* no path info available */ +#define OBJPATH_VNODE 0x1 /* use vn_fullpath on vnode */ +#define OBJPATH_SHMS 0x2 /* use sysvshm_fullpath */ +#define OBJPATH_SHMP 0x3 /* use shm_fullpath */ + /* * Helpers to perform conversion between vm_object page indexes and offsets. * IDX_TO_OFF() converts an index into an offset. @@ -324,6 +345,9 @@ void vm_object_set_writeable_dirty (vm_object_t); void vm_object_init (void); int vm_object_kvme_type(vm_object_t object, struct vnode **vpp); +int vm_object_path_info(vm_object_t object, void **data); +void vm_object_set_path_info(vm_object_t object, int path_info_type, + void *data); void vm_object_madvise(vm_object_t, vm_pindex_t, vm_pindex_t, int); boolean_t vm_object_page_clean(vm_object_t object, vm_ooffset_t start, vm_ooffset_t end, int flags); Index: sys/vm/vm_object.c =================================================================== --- sys/vm/vm_object.c +++ sys/vm/vm_object.c @@ -256,6 +256,7 @@ case OBJT_DEFAULT: case OBJT_SWAP: object->flags = OBJ_ONEMAPPING; + object->un_pager.path_info.data = NULL; break; case OBJT_DEVICE: case OBJT_SG: @@ -266,6 +267,7 @@ break; case OBJT_PHYS: object->flags = OBJ_UNMANAGED; + object->un_pager.path_info.data = NULL; break; case OBJT_VNODE: object->flags = 0; @@ -2343,6 +2345,54 @@ } } +/* + * Return the type of the path info pointer. If data is not NULL, + * set it to the path info pointer or NULL. The return value + * indicates which function can be used to convert the path info + * pointer to a path. + */ +int +vm_object_path_info(vm_object_t object, void **data) +{ + VM_OBJECT_ASSERT_LOCKED(object); + if (data != NULL) + *data = object->un_pager.path_info.data; + if (object->type != OBJT_DEFAULT && + object->type != OBJT_SWAP && + object->type != OBJT_PHYS) + return (OBJPATH_NONE); + if (object->un_pager.path_info.data == NULL) + return (OBJPATH_NONE); + if ((object->flags & OBJ_TMPFS) != 0) + return (OBJPATH_NONE); + if ((object->flags & OBJ_SYSV_SHM) != 0) + return (OBJPATH_SHMS); + else + return (OBJPATH_SHMP); +} + +void +vm_object_set_path_info(vm_object_t object, int path_info_type, + void *data) +{ + VM_OBJECT_ASSERT_LOCKED(object); + KASSERT(object->type == OBJT_DEFAULT || + object->type == OBJT_SWAP || + object->type == OBJT_PHYS, + ("cannot set path info for object type %d", object->type)); + KASSERT((object->flags & OBJ_TMPFS) == 0, + ("cannot set path info for tmpfs object")); + KASSERT(path_info_type == OBJPATH_SHMS || + path_info_type == OBJPATH_SHMP || + path_info_type == OBJPATH_NONE, + ("unknown path info type")); + object->un_pager.path_info.data = data; + if (path_info_type == OBJPATH_SHMS) + vm_object_set_flag(object, OBJ_SYSV_SHM); + else + vm_object_clear_flag(object, OBJ_SYSV_SHM); +} + static int sysctl_vm_object_list(SYSCTL_HANDLER_ARGS) {