The branch main has been updated by fsu:

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

commit 1ed5f62d61accf8c7a4d45e2e701a0179ff2fe1b
Author:     Fedor Uporov <f...@freebsd.org>
AuthorDate: 2021-02-18 08:26:50 +0000
Commit:     Fedor Uporov <f...@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. */
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to