From nobody Fri Apr 28 08:57:22 2023 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Q761b0r6cz48C2c; Fri, 28 Apr 2023 08:57:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Q761Z5pgzz4SG2; Fri, 28 Apr 2023 08:57:22 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1682672242; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=0/S+EnQ7Sao8wsNJcQDEV4Oh36PMDaanLk2rvrh7rfA=; b=U9W3fXsYvlXr3on3iWxDX1LKL+2aDnAhlr0q1M1zXzRzrzsvwKY/MaEWOASZZtMXHRaJFk CE/YOTzXaDGIQR8fv41+rTzoGjlp0yesINA/Q1ZD/kzmfLBZzBA1ggbMGiowmVU4wSpH7Z Z1OvWbx4C3sohXJhIJGAJOIh5narkRwXE64HmoqcG6Jq0ZYbLsoyxUQe3fWqSoBW4GeF7O WRv9Kk0LVfiaMmGY5qeoZatBH4pw/8sEgxSYvmUzPCGINuPzuWl6Pmjyqwip95Bfi33Gjp y6eDDj1h65TnoW+gonYSmqdMhx+ouVwv89pR1vKbwnPssaBvSq1rXThVdx/Cgw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1682672242; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=0/S+EnQ7Sao8wsNJcQDEV4Oh36PMDaanLk2rvrh7rfA=; b=iFsYBNfpue1AlefLDjsvPQ/AOdsKY7kVgoj7YgGPabWvy0uxw1pkP+bwYIoyUpzpAUlG+J qZdSFt5idVoMd8N2UMNpyT7z1ZEuCG3qzSh+1E1VNdGE07P5Mn4F5vnTbvSNFdEm56RHMz xpagmwZwPZACJitpT4p+9XCxflVXFocYe9S+sf2iJqFmr7gql/sZof09ILGvr5DHiLAqqf tU7VA6Z/wIeBMQgjCwoUhYuVA51DU0KNpqNV1BcpAUpq2+5+MVnnJsX9WRpxpPIOcpXpwX 2s+tWCh8axX4TjD3BgoQhFk1dOaxwRKks+b5jiPE0yAkOqTRFSEt6GiLVYCkrg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1682672242; a=rsa-sha256; cv=none; b=NdC5ZFY1VzdZxxKSWnxo6u8rUHEmpC9EZqvYnKgZbM6grxjXs+m79sorXlruIlG84J7bkS OVt/BDBDAmrXZN/qDg/u5JtdkKwMU/sEDjg4NoMVzteV8XzSO6pxgPPtmMThttM0lhX/6Q 2OYhiYNJCijRDfaPQsf/jqFAFppePtpwKSOkNVhDjaJeHuDuvKBBCcYJv14mpAMFmdQDzY djIlpj/CAqvdvXaBS8cvJxVVkIMj0FhLD07K54DR5jovPwaWMRuoBo53S6Yvh0govwc2Dy jbNAuYembWMrKHtiUjm7EjzSvtpfV0pBCB6PFSfbi/yjxqdQAk8biMrOxZAWvA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Q761Z4nxYzt0B; Fri, 28 Apr 2023 08:57:22 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 33S8vMQu018181; Fri, 28 Apr 2023 08:57:22 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 33S8vM8g018180; Fri, 28 Apr 2023 08:57:22 GMT (envelope-from git) Date: Fri, 28 Apr 2023 08:57:22 GMT Message-Id: <202304280857.33S8vM8g018180@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dmitry Chagin Subject: git: 166e2e5a9e87 - main - linux(4): Uniformly dev_t arguments translation List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dchagin X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 166e2e5a9e87d32dbfc7838903904673873f1e71 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=166e2e5a9e87d32dbfc7838903904673873f1e71 commit 166e2e5a9e87d32dbfc7838903904673873f1e71 Author: Dmitry Chagin AuthorDate: 2023-04-28 08:55:05 +0000 Commit: Dmitry Chagin CommitDate: 2023-04-28 08:55:05 +0000 linux(4): Uniformly dev_t arguments translation The two main uses of dev_t are in struct stat and as a parameter of the mknod system calls. As of version 2.6.0 of the Linux kernel, dev_t is a 32-bit quantity with 12 bits set asaid for the major number and 20 for the minor number. The in-kernel dev_t encoded as MMMmmmmm, where M is a hex digit of the major number and m is a hex digit of the minor number. The user-space dev_t encoded as mmmM MMmm, where M and m is the major and minor numbers accordingly. This is downward compatible with legacy systems where dev_t is 16 bits wide, encoded as MMmm. In glibc dev_t is a 64-bit quantity, with 32-bit major and minor numbers, encoded as MMMM Mmmm mmmM MMmm. This is downward compatible with the Linux kernel and with legacy systems where dev_t is 16 bits wide. In the FreeBSD dev_t is a 64-bit quantity. The major and minor numbers are encoded as MMMmmmMm, therefore conversion of the device numbers between Linux user-space and FreeBSD kernel required. --- sys/compat/linux/linux.h | 68 ++++++++++++++++++++++++++++++++++++++++++ sys/compat/linux/linux_misc.c | 4 +-- sys/compat/linux/linux_stats.c | 49 ++++++++++++------------------ sys/compat/linux/linux_util.c | 3 +- 4 files changed, 91 insertions(+), 33 deletions(-) diff --git a/sys/compat/linux/linux.h b/sys/compat/linux/linux.h index 4ad94bf11efd..9f320efa5110 100644 --- a/sys/compat/linux/linux.h +++ b/sys/compat/linux/linux.h @@ -33,6 +33,74 @@ */ typedef uint32_t l_dev_t; +/* + * Linux dev_t conversion routines. + * + * As of version 2.6.0 of the Linux kernel, dev_t is a 32-bit quantity + * with 12 bits set asaid for the major number and 20 for the minor number. + * The in-kernel dev_t encoded as MMMmmmmm, where M is a hex digit of the + * major number and m is a hex digit of the minor number. + * The user-space dev_t encoded as mmmM MMmm, where M and m is the major + * and minor numbers accordingly. This is downward compatible with legacy + * systems where dev_t is 16 bits wide, encoded as MMmm. + * In glibc dev_t is a 64-bit quantity, with 32-bit major and minor numbers, + * encoded as MMMM Mmmm mmmM MMmm. This is downward compatible with the Linux + * kernel and with legacy systems where dev_t is 16 bits wide. + * + * In the FreeBSD dev_t is a 64-bit quantity. The major and minor numbers + * are encoded as MMMmmmMm, therefore conversion of the device numbers between + * Linux user-space and FreeBSD kernel required. + */ +static __inline l_dev_t +linux_encode_dev(int _major, int _minor) +{ + + return ((_minor & 0xff) | ((_major & 0xfff) << 8) | + (((_minor & ~0xff) << 12) & 0xfff00000)); +} + +static __inline l_dev_t +linux_new_encode_dev(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev))); +} + +static __inline int +linux_encode_major(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : major(_dev) & 0xfff); +} + +static __inline int +linux_encode_minor(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : minor(_dev) & 0xfffff); +} + +static __inline int +linux_decode_major(l_dev_t _dev) +{ + + return ((_dev & 0xfff00) >> 8); +} + +static __inline int +linux_decode_minor(l_dev_t _dev) +{ + + return ((_dev & 0xff) | ((_dev & 0xfff00000) >> 12)); +} + +static __inline dev_t +linux_decode_dev(l_dev_t _dev) +{ + + return (makedev(linux_decode_major(_dev), linux_decode_minor(_dev))); +} + /* * Private Brandinfo flags */ diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index ba0ac190a946..bc6ff9559493 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -901,7 +901,7 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args) case S_IFCHR: case S_IFBLK: error = kern_mknodat(td, AT_FDCWD, path, seg, - args->mode, args->dev); + args->mode, linux_decode_dev(args->dev)); break; case S_IFDIR: @@ -956,7 +956,7 @@ linux_mknodat(struct thread *td, struct linux_mknodat_args *args) case S_IFCHR: case S_IFBLK: error = kern_mknodat(td, dfd, path, seg, args->mode, - args->dev); + linux_decode_dev(args->dev)); break; case S_IFDIR: diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c index 260709b23202..95b8668eb2db 100644 --- a/sys/compat/linux/linux_stats.c +++ b/sys/compat/linux/linux_stats.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include #endif +#include #include #include @@ -139,38 +140,19 @@ linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg, } #endif -/* - * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so - * truncation of a dev_t to 16 bits gives the same result as unpacking - * using major() and minor() and repacking in the l_dev_t format. This - * detail is hidden in dev_to_ldev(). Overflow in conversions of dev_t's - * are not checked for, as for other fields. - * - * dev_to_ldev() is only used for translating st_dev. When we convert - * st_rdev for copying it out, it isn't really a dev_t, but has already - * been translated to an l_dev_t in a nontrivial way. Translating it - * again would be illogical but would have no effect since the low 16 - * bits have the same encoding. - * - * The nontrivial translation for st_rdev renumbers some devices, but not - * ones that can be mounted on, so it is consistent with the translation - * for st_dev except when the renumbering or truncation causes conflicts. - */ -#define dev_to_ldev(d) ((uint16_t)(d)) - static int newstat_copyout(struct stat *buf, void *ubuf) { struct l_newstat tbuf; bzero(&tbuf, sizeof(tbuf)); - tbuf.st_dev = dev_to_ldev(buf->st_dev); + tbuf.st_dev = linux_new_encode_dev(buf->st_dev); tbuf.st_ino = buf->st_ino; tbuf.st_mode = buf->st_mode; tbuf.st_nlink = buf->st_nlink; tbuf.st_uid = buf->st_uid; tbuf.st_gid = buf->st_gid; - tbuf.st_rdev = buf->st_rdev; + tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev); tbuf.st_size = buf->st_size; tbuf.st_atim.tv_sec = buf->st_atim.tv_sec; tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; @@ -239,19 +221,27 @@ linux_newfstat(struct thread *td, struct linux_newfstat_args *args) } #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) + +static __inline uint16_t +linux_old_encode_dev(dev_t _dev) +{ + + return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev))); +} + static int old_stat_copyout(struct stat *buf, void *ubuf) { struct l_old_stat lbuf; bzero(&lbuf, sizeof(lbuf)); - lbuf.st_dev = dev_to_ldev(buf->st_dev); + lbuf.st_dev = linux_old_encode_dev(buf->st_dev); lbuf.st_ino = buf->st_ino; lbuf.st_mode = buf->st_mode; lbuf.st_nlink = buf->st_nlink; lbuf.st_uid = buf->st_uid; lbuf.st_gid = buf->st_gid; - lbuf.st_rdev = buf->st_rdev; + lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev); lbuf.st_size = MIN(buf->st_size, INT32_MAX); lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; @@ -550,13 +540,13 @@ stat64_copyout(struct stat *buf, void *ubuf) struct l_stat64 lbuf; bzero(&lbuf, sizeof(lbuf)); - lbuf.st_dev = dev_to_ldev(buf->st_dev); + lbuf.st_dev = linux_new_encode_dev(buf->st_dev); lbuf.st_ino = buf->st_ino; lbuf.st_mode = buf->st_mode; lbuf.st_nlink = buf->st_nlink; lbuf.st_uid = buf->st_uid; lbuf.st_gid = buf->st_gid; - lbuf.st_rdev = buf->st_rdev; + lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev); lbuf.st_size = buf->st_size; lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; @@ -762,11 +752,10 @@ statx_copyout(struct stat *buf, void *ubuf) tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec; tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec; tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec; - - tbuf.stx_rdev_major = buf->st_rdev >> 8; - tbuf.stx_rdev_minor = buf->st_rdev & 0xff; - tbuf.stx_dev_major = buf->st_dev >> 8; - tbuf.stx_dev_minor = buf->st_dev & 0xff; + tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev); + tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev); + tbuf.stx_dev_major = linux_encode_major(buf->st_dev); + tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev); return (copyout(&tbuf, ubuf, sizeof(tbuf))); } diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c index dd739fde2551..afb0bb082dd5 100644 --- a/sys/compat/linux/linux_util.c +++ b/sys/compat/linux/linux_util.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -248,7 +249,7 @@ translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; if (linux_vn_get_major_minor(vp, &major, &minor) == 0) - sb->st_rdev = (major << 8 | minor); + sb->st_rdev = makedev(major, minor); } char *