Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 May 2021 07:09:47 GMT
From:      Fedor Uporov <fsu@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 1ed5f62d61ac - main - Add chr/blk devices support.
Message-ID:  <202105070709.14779lLg058771@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by fsu:

URL: https://cgit.FreeBSD.org/src/commit/?id=1ed5f62d61accf8c7a4d45e2e701a0179ff2fe1b

commit 1ed5f62d61accf8c7a4d45e2e701a0179ff2fe1b
Author:     Fedor Uporov <fsu@FreeBSD.org>
AuthorDate: 2021-02-18 08:26:50 +0000
Commit:     Fedor Uporov <fsu@FreeBSD.org>
CommitDate: 2021-05-07 07:08:31 +0000

    Add chr/blk devices support.
    
    The dev field is placed into the inode structure.
    The major/minor numbers conversion to/from linux compatile
    format happen during on-disk inodes writing/reading.
    
    Reviewed by:    pfg
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D29930
---
 sys/fs/ext2fs/ext2_inode.c     |  3 +--
 sys/fs/ext2fs/ext2_inode_cnv.c | 54 ++++++++++++++++++++++++++++++++++++++++--
 sys/fs/ext2fs/ext2_vnops.c     | 32 ++++++++++++++++---------
 sys/fs/ext2fs/ext2fs.h         |  7 ++++++
 sys/fs/ext2fs/inode.h          |  2 +-
 5 files changed, 82 insertions(+), 16 deletions(-)

diff --git a/sys/fs/ext2fs/ext2_inode.c b/sys/fs/ext2fs/ext2_inode.c
index 34c32f2f113d..1412017b4b3c 100644
--- a/sys/fs/ext2fs/ext2_inode.c
+++ b/sys/fs/ext2fs/ext2_inode.c
@@ -605,8 +605,7 @@ ext2_inactive(struct vop_inactive_args *ap)
 	if (ip->i_nlink <= 0) {
 		ext2_extattr_free(ip);
 		error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td);
-		if (!(ip->i_flag & IN_E4EXTENTS))
-			ip->i_rdev = 0;
+		ip->i_rdev = 0;
 		mode = ip->i_mode;
 		ip->i_mode = 0;
 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c
index bfa505896637..a71d5cef21aa 100644
--- a/sys/fs/ext2fs/ext2_inode_cnv.c
+++ b/sys/fs/ext2fs/ext2_inode_cnv.c
@@ -96,6 +96,42 @@ ext2_print_inode(struct inode *in)
 
 #define XTIME_TO_NSEC(x)	((le32toh(x) & EXT3_NSEC_MASK) >> 2)
 
+static inline bool
+ext2_old_valid_dev(dev_t dev)
+{
+	return (major(dev) < 256 && minor(dev) < 256);
+}
+
+static inline uint16_t
+ext2_old_encode_dev(dev_t dev)
+{
+	return ((major(dev) << 8) | minor(dev));
+}
+
+static inline dev_t
+ext2_old_decode_dev(uint16_t val)
+{
+	return (makedev((val >> 8) & 255, val & 255));
+}
+
+static inline uint32_t
+ext2_new_encode_dev(dev_t dev)
+{
+	unsigned maj = major(dev);
+	unsigned min = minor(dev);
+
+	return ((min & 0xff) | (maj << 8) | ((min & ~0xff) << 12));
+}
+
+static inline dev_t
+ext2_new_decode_dev(uint32_t dev)
+{
+	unsigned maj = (dev & 0xfff00) >> 8;
+	unsigned min = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+
+	return (makedev(maj, min));
+}
+
 /*
  *	raw ext2 inode LE to host inode conversion
  */
@@ -172,7 +208,12 @@ ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip)
 	ip->i_uid |= (uint32_t)le16toh(ei->e2di_uid_high) << 16;
 	ip->i_gid |= (uint32_t)le16toh(ei->e2di_gid_high) << 16;
 
-	if ((ip->i_flag & IN_E4EXTENTS)) {
+	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) {
+		if (ei->e2di_blocks[0])
+			ip->i_rdev = ext2_old_decode_dev(le32toh(ei->e2di_blocks[0]));
+		else
+			ip->i_rdev = ext2_new_decode_dev(le32toh(ei->e2di_blocks[1]));
+	} else if ((ip->i_flag & IN_E4EXTENTS)) {
 		memcpy(ip->i_data, ei->e2di_blocks, sizeof(ei->e2di_blocks));
 	} else {
 		for (i = 0; i < EXT2_NDADDR; i++)
@@ -247,7 +288,16 @@ ext2_i2ei(struct inode *ip, struct ext2fs_dinode *ei)
 	ei->e2di_gid = htole16(ip->i_gid & 0xffff);
 	ei->e2di_gid_high = htole16(ip->i_gid >> 16 & 0xffff);
 
-	if ((ip->i_flag & IN_E4EXTENTS)) {
+	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) {
+		if (ext2_old_valid_dev(ip->i_rdev)) {
+			ei->e2di_blocks[0] = htole32(ext2_old_encode_dev(ip->i_rdev));
+			ei->e2di_blocks[1] = 0;
+		} else {
+			ei->e2di_blocks[0] = 0;
+			ei->e2di_blocks[1] = htole32(ext2_new_encode_dev(ip->i_rdev));
+			ei->e2di_blocks[2] = 0;
+		}
+	} else if ((ip->i_flag & IN_E4EXTENTS)) {
 		memcpy(ei->e2di_blocks, ip->i_data, sizeof(ei->e2di_blocks));
 	} else {
 		for (i = 0; i < EXT2_NDADDR; i++)
diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c
index 1ab360a7ad87..2721aa535b40 100644
--- a/sys/fs/ext2fs/ext2_vnops.c
+++ b/sys/fs/ext2fs/ext2_vnops.c
@@ -322,9 +322,6 @@ ext2_access(struct vop_access_args *ap)
 	accmode_t accmode = ap->a_accmode;
 	int error;
 
-	if (vp->v_type == VBLK || vp->v_type == VCHR)
-		return (EOPNOTSUPP);
-
 	/*
 	 * Disallow write attempts on read-only file systems;
 	 * unless the file is a socket, fifo, or a block or
@@ -622,6 +619,18 @@ ext2_fsync(struct vop_fsync_args *ap)
 	return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT));
 }
 
+static int
+ext2_check_mknod_limits(dev_t dev)
+{
+	unsigned maj = major(dev);
+	unsigned min = minor(dev);
+
+	if (maj > EXT2_MAJOR_MAX || min > EXT2_MINOR_MAX)
+		return (EINVAL);
+
+	return (0);
+}
+
 /*
  * Mknod vnode call
  */
@@ -635,20 +644,21 @@ ext2_mknod(struct vop_mknod_args *ap)
 	ino_t ino;
 	int error;
 
+	if (vap->va_rdev != VNOVAL) {
+		error = ext2_check_mknod_limits(vap->va_rdev);
+		if (error)
+			return (error);
+	}
+
 	error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
 	    ap->a_dvp, vpp, ap->a_cnp);
 	if (error)
 		return (error);
 	ip = VTOI(*vpp);
 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
-	if (vap->va_rdev != VNOVAL) {
-		/*
-		 * Want to be able to use this to make badblock
-		 * inodes, so don't truncate the dev number.
-		 */
-		if (!(ip->i_flag & IN_E4EXTENTS))
-			ip->i_rdev = vap->va_rdev;
-	}
+	if (vap->va_rdev != VNOVAL)
+		ip->i_rdev = vap->va_rdev;
+
 	/*
 	 * Remove inode, then reload it through VFS_VGET so it is
 	 * checked to see if it is an alias of an existing entry in
diff --git a/sys/fs/ext2fs/ext2fs.h b/sys/fs/ext2fs/ext2fs.h
index 81ff6838f16f..b11ccc0b5b5a 100644
--- a/sys/fs/ext2fs/ext2fs.h
+++ b/sys/fs/ext2fs/ext2fs.h
@@ -429,4 +429,11 @@ struct ext2_gd {
 #define	EXT2_FIRST_INO(s)	(le32toh((EXT2_SB(s)->e2fs->e2fs_rev) == \
     E2FS_REV0) ? EXT2_FIRSTINO : le32toh(EXT2_SB(s)->e2fs->e2fs_first_ino))
 
+/*
+ * Linux major/minor values limits
+ */
+#define	EXT2_MINORBITS	(20)
+#define	EXT2_MAJOR_MAX	(0xffffffff >> EXT2_MINORBITS)
+#define	EXT2_MINOR_MAX	((1 << EXT2_MINORBITS) - 1)
+
 #endif	/* !_FS_EXT2FS_EXT2FS_H_ */
diff --git a/sys/fs/ext2fs/inode.h b/sys/fs/ext2fs/inode.h
index 2b9ec687a75c..e6af6ef8d5b6 100644
--- a/sys/fs/ext2fs/inode.h
+++ b/sys/fs/ext2fs/inode.h
@@ -110,6 +110,7 @@ struct inode {
 	uint32_t	i_gen;		/* Generation number. */
 	uint64_t	i_facl;		/* EA block number. */
 	uint32_t	i_flags;	/* Status flags (chflags). */
+	dev_t		i_rdev; 	/* Major/minor inode values. */
 	union {
 		struct {
 			uint32_t i_db[EXT2_NDADDR]; /* Direct disk blocks. */
@@ -131,7 +132,6 @@ struct inode {
  * di_db area.
  */
 #define	i_shortlink	i_db
-#define	i_rdev		i_db[0]
 
 /* File permissions. */
 #define	IEXEC		0000100		/* Executable. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105070709.14779lLg058771>