kcmp implementation for mesa

From: Rozhuk Ivan <rozhuk.im_at_gmail.com>
Date: Fri, 19 Jan 2024 11:10:47 UTC
Hi!


graphics/mesa-* uses SYS_kcmp [1] to compare two fds:

int
os_same_file_description(int fd1, int fd2)
{
   pid_t pid = getpid();

   /* Same file descriptor trivially implies same file description */
   if (fd1 == fd2)
      return 0;

   return syscall(SYS_kcmp, pid, pid, KCMP_FILE, fd1, fd2);
}

FreeBSD does not implemet this and we got in terminal:
"amdgpu: os_same_file_description couldn't determine if two DRM fds reference the same file description."


Mesa say:
/* DRM file descriptors, file descriptions and buffer sharing.
 *
 * amdgpu_device_initialize first argument is a file descriptor (fd)
 * representing a specific GPU.
 * If a fd is duplicated using os_dupfd_cloexec,
 * the file description will remain the same (os_same_file_description will
 * return 0).
 * But if the same device is re-opened, the fd and the file description will
 * be different.
 *
 * amdgpu_screen_winsys's fd tracks the file description which was
 * given to amdgpu_winsys_create. This is the fd used by the application
 * using the driver and may be used in other ioctl (eg: drmModeAddFB)
 *
 * amdgpu_winsys's fd is the file description used to initialize the
 * device handle in libdrm_amdgpu.
 *
 * The 2 fds can be different, even in systems with a single GPU, eg: if
 * radv is initialized before radeonsi.
 *
 * This fd tracking is useful for buffer sharing because KMS/GEM handles are
 * specific to a DRM file description, i.e. the same handle value may refer
 * to different underlying BOs in different DRM file descriptions.
 * As an example, if an app wants to use drmModeAddFB it'll need a KMS handle
 * valid for its fd (== amdgpu_screen_winsys::fd).
 * If both fds are identical, there's nothing to do: bo->u.real.kms_handle
 * can be used directly (see amdgpu_bo_get_handle).
 * If they're different, the BO has to be exported from the device fd as
 * a dma-buf, then imported from the app fd as a KMS handle.
 */



I do few checks with dup() and os_dupfd_cloexec() and code show that fd equal.

Does this implementation will do that mesa expects?


#include <sys/user.h>
#include <fcntl.h>

int
os_same_file_description(int fd1, int fd2) {
	struct kinfo_file kif1, kif2;

	/* Same file descriptor trivially implies same file description */
	if (fd1 == fd2)
		return (0);

	kif1.kf_structsize = sizeof(kif1);
	kif2.kf_structsize = sizeof(kif2);
	if (-1 == fcntl(fd1, F_KINFO, &kif1) ||
	    -1 == fcntl(fd2, F_KINFO, &kif2))
		return (-1);

	if (kif1.kf_type != kif2.kf_type ||
	    0 != memcmp(&kif1.kf_path, &kif2.kf_path, sizeof(kif1.kf_path)))
		return (3);

	switch (kif1.kf_type) {
	case KF_TYPE_VNODE:
		if (0 == memcmp(&kif1.kf_un.kf_file, &kif2.kf_un.kf_file,
		    sizeof(kif1.kf_un.kf_file)))
			return (0);
		return (3);
	case KF_TYPE_SOCKET:
		if (0 == memcmp(&kif1.kf_un.kf_sock, &kif2.kf_un.kf_sock,
		    sizeof(kif1.kf_un.kf_sock)))
			return (0);
		return (3);
	case KF_TYPE_PIPE:
		if (0 == memcmp(&kif1.kf_un.kf_pipe, &kif2.kf_un.kf_pipe,
		    sizeof(kif1.kf_un.kf_pipe)))
			return (0);
		return (3);
	//case KF_TYPE_FIFO:
	case KF_TYPE_KQUEUE:
		if (0 == memcmp(&kif1.kf_un.kf_kqueue, &kif2.kf_un.kf_kqueue,
		    sizeof(kif1.kf_un.kf_kqueue)))
			return (0);
		return (3);
	//case KF_TYPE_MQUEUE:
	//case KF_TYPE_SHM:
	case KF_TYPE_SEM:
		if (0 == memcmp(&kif1.kf_un.kf_sem, &kif2.kf_un.kf_sem,
		    sizeof(kif1.kf_un.kf_sem)))
			return (0);
		return (3);
	case KF_TYPE_PTS:
		if (0 == memcmp(&kif1.kf_un.kf_pts, &kif2.kf_un.kf_pts,
		    sizeof(kif1.kf_un.kf_pts)))
			return (0);
		return (3);
	case KF_TYPE_PROCDESC:
		if (0 == memcmp(&kif1.kf_un.kf_proc, &kif2.kf_un.kf_proc,
		    sizeof(kif1.kf_un.kf_proc)))
			return (0);
		return (3);
	//case KF_TYPE_DEV:
	case KF_TYPE_EVENTFD:
		if (0 == memcmp(&kif1.kf_un.kf_eventfd, &kif2.kf_un.kf_eventfd,
		    sizeof(kif1.kf_un.kf_eventfd)))
			return (0);
		return (3);
	case KF_TYPE_TIMERFD:
		if (0 == memcmp(&kif1.kf_un.kf_timerfd, &kif2.kf_un.kf_timerfd,
		    sizeof(kif1.kf_un.kf_timerfd)))
			return (0);
		return (3);
	}
	/* Otherwise we can't tell */
	return (-1);
}


Refs:
1. https://man7.org/linux/man-pages/man2/kcmp.2.html