git: 1ed5f62d61ac - main - Add chr/blk devices support.
Fedor Uporov
fsu at FreeBSD.org
Fri May 7 07:09:48 UTC 2021
The branch main has been updated by fsu:
URL: https://cgit.FreeBSD.org/src/commit/?id=1ed5f62d61accf8c7a4d45e2e701a0179ff2fe1b
commit 1ed5f62d61accf8c7a4d45e2e701a0179ff2fe1b
Author: Fedor Uporov <fsu at FreeBSD.org>
AuthorDate: 2021-02-18 08:26:50 +0000
Commit: Fedor Uporov <fsu at 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. */
More information about the dev-commits-src-main
mailing list