Page MenuHomeFreeBSD

D29930.id87991.diff
No OneTemporary

D29930.id87991.diff

diff --git a/sys/fs/ext2fs/ext2_inode.c b/sys/fs/ext2fs/ext2_inode.c
--- a/sys/fs/ext2fs/ext2_inode.c
+++ b/sys/fs/ext2fs/ext2_inode.c
@@ -605,8 +605,7 @@
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
--- a/sys/fs/ext2fs/ext2_inode_cnv.c
+++ b/sys/fs/ext2fs/ext2_inode_cnv.c
@@ -96,6 +96,42 @@
#define XTIME_TO_NSEC(x) ((le32toh(x) & EXT3_NSEC_MASK) >> 2)
+static bool
+ext2_old_valid_dev(dev_t dev)
+{
+ return (major(dev) < 256 && minor(dev) < 256);
+}
+
+static uint16_t
+ext2_old_encode_dev(dev_t dev)
+{
+ return ((major(dev) << 8) | minor(dev));
+}
+
+static dev_t
+ext2_old_decode_dev(uint16_t val)
+{
+ return (makedev((val >> 8) & 255, val & 255));
+}
+
+static 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 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 @@
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 @@
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
--- a/sys/fs/ext2fs/ext2_vnops.c
+++ b/sys/fs/ext2fs/ext2_vnops.c
@@ -322,9 +322,6 @@
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
@@ -620,6 +617,18 @@
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
*/
@@ -633,20 +642,21 @@
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
--- a/sys/fs/ext2fs/ext2fs.h
+++ b/sys/fs/ext2fs/ext2fs.h
@@ -429,4 +429,11 @@
#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
--- a/sys/fs/ext2fs/inode.h
+++ b/sys/fs/ext2fs/inode.h
@@ -110,6 +110,7 @@
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 @@
* di_db area.
*/
#define i_shortlink i_db
-#define i_rdev i_db[0]
/* File permissions. */
#define IEXEC 0000100 /* Executable. */

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 22, 12:15 PM (13 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27846197
Default Alt Text
D29930.id87991.diff (5 KB)

Event Timeline