diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 1c8e8c0f6cea..a6c11cef1b73 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -591,12 +591,12 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - jint16_t dev; + union jffs2_device_node dev; int devlen = 0; uint32_t alloclen, phys_ofs; int ret; - if (!old_valid_dev(rdev)) + if (!new_valid_dev(rdev)) return -EINVAL; ri = jffs2_alloc_raw_inode(); @@ -605,17 +605,15 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de c = JFFS2_SB_INFO(dir_i->i_sb); - if (S_ISBLK(mode) || S_ISCHR(mode)) { - dev = cpu_to_je16(old_encode_dev(rdev)); - devlen = sizeof(dev); - } + if (S_ISBLK(mode) || S_ISCHR(mode)) + devlen = jffs2_encode_dev(&dev, rdev); /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ namelen = dentry->d_name.len; ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index ea1f37d4fc58..24cb4c688efc 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -33,7 +33,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode *ri; - unsigned short dev; + union jffs2_device_node dev; unsigned char *mdata = NULL; int mdatalen = 0; unsigned int ivalid; @@ -51,9 +51,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) it out again with the appropriate data attached */ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { /* For these, we don't actually need to read the old node */ - dev = old_encode_dev(inode->i_rdev); + mdatalen = jffs2_encode_dev(&dev, inode->i_rdev); mdata = (char *)&dev; - mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); } else if (S_ISLNK(inode->i_mode)) { down(&f->sem); @@ -232,6 +231,8 @@ void jffs2_read_inode (struct inode *inode) struct jffs2_inode_info *f; struct jffs2_sb_info *c; struct jffs2_raw_inode latest_node; + union jffs2_device_node jdev; + dev_t rdev = 0; int ret; D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); @@ -263,7 +264,6 @@ void jffs2_read_inode (struct inode *inode) inode->i_blocks = (inode->i_size + 511) >> 9; switch (inode->i_mode & S_IFMT) { - jint16_t rdev; case S_IFLNK: inode->i_op = &jffs2_symlink_inode_operations; @@ -297,8 +297,16 @@ void jffs2_read_inode (struct inode *inode) case S_IFBLK: case S_IFCHR: /* Read the device numbers from the media */ + if (f->metadata->size != sizeof(jdev.old) && + f->metadata->size != sizeof(jdev.new)) { + printk(KERN_NOTICE "Device node has strange size %d\n", f->metadata->size); + up(&f->sem); + jffs2_do_clear_inode(c, f); + make_bad_inode(inode); + return; + } D1(printk(KERN_DEBUG "Reading device numbers from flash\n")); - if (jffs2_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) { + if (jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size) < 0) { /* Eep */ printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino); up(&f->sem); @@ -306,12 +314,15 @@ void jffs2_read_inode (struct inode *inode) make_bad_inode(inode); return; } + if (f->metadata->size == sizeof(jdev.old)) + rdev = old_decode_dev(je16_to_cpu(jdev.old)); + else + rdev = new_decode_dev(je32_to_cpu(jdev.new)); case S_IFSOCK: case S_IFIFO: inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, - old_decode_dev((je16_to_cpu(rdev)))); + init_special_inode(inode, inode->i_mode, rdev); break; default: diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 967fb2cf8e21..77d30707de56 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -679,7 +679,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; struct jffs2_node_frag *last_frag; - jint16_t dev; + union jffs2_device_node dev; char *mdata = NULL, mdatalen = 0; uint32_t alloclen, phys_ofs, ilen; int ret; @@ -687,11 +687,8 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ if (S_ISBLK(JFFS2_F_I_MODE(f)) || S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ - /* FIXME: for minor or major > 255. */ - dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | - JFFS2_F_I_RDEV_MIN(f))); + mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f)); mdata = (char *)&dev; - mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { mdatalen = fn->size; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index f6645afe88e4..24e0f28a8bac 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -268,6 +268,17 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, #define PAD(x) (((x)+3)&~3) +static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev) +{ + if (old_valid_dev(rdev)) { + jdev->old = cpu_to_je16(old_encode_dev(rdev)); + return sizeof(jdev->old); + } else { + jdev->new = cpu_to_je32(new_encode_dev(rdev)); + return sizeof(jdev->new); + } +} + static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) { while(raw->next_in_ino) { diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index d307cf548625..a10eb03ac95b 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -31,9 +31,7 @@ struct kvec; #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) - -#define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f))) -#define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f))) +#define JFFS2_F_I_RDEV(f) (OFNI_EDONI_2SFFJ(f)->i_rdev) #define ITIME(sec) ((struct timespec){sec, 0}) #define I_SEC(tv) ((tv).tv_sec) diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index a26fbd498c79..007d76d290cb 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -173,4 +173,10 @@ union jffs2_node_union struct jffs2_unknown_node u; }; +/* Data payload for device nodes. */ +union jffs2_device_node { + jint16_t old; + jint32_t new; +}; + #endif /* __LINUX_JFFS2_H__ */