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
This commit is contained in:
parent
1484574843
commit
1ed5f62d61
@ -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;
|
||||
|
@ -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++)
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user