[JFFS2] Support new device nodes
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 18 May 2006 23:28:49 +0000 (00:28 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Thu, 18 May 2006 23:28:49 +0000 (00:28 +0100)
Device node major/minor numbers are just stored in the payload of a single
data node. Just extend that to 4 bytes and use new_encode_dev() for it.

We only use the 4-byte format if we _need_ to, if !old_valid_dev(foo).
This preserves backwards compatibility with older code as much as
possible. If we do make devices with major or minor numbers above 255, and
then mount the file system with the old code, it'll just read the first
two bytes and get the numbers wrong. If it comes to garbage-collect it,
it'll then write back those wrong numbers. But that's about the best we
can expect.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
fs/jffs2/dir.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/nodelist.h
fs/jffs2/os-linux.h
include/linux/jffs2.h

index 1c8e8c0f6ceac9ec2cf2fdf058dffea177559547..a6c11cef1b7369772290da4b27a7348d36b4f436 100644 (file)
@@ -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);
index ea1f37d4fc5867deb21f46e6539721cb70dd42a5..24cb4c688efc9f9257218d7e13148496316c86af 100644 (file)
@@ -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:
index 967fb2cf8e21ed849cc330fce8aa7928c51ae0ef..77d30707de56eee127cc55355b77b0f1e76805ff 100644 (file)
@@ -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;
index f6645afe88e448685e955cc4521b7fdc969e68da..24e0f28a8bac8654547550a77f23263213a68158 100644 (file)
@@ -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) {
index d307cf548625b5a9b654af3c711b6c619edbfce9..a10eb03ac95b0f0e448cb80a244c708ba1f070c0 100644 (file)
@@ -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)
index a26fbd498c79bf2ba1545f32ad3ecfdce4f0c3f5..007d76d290cbeaf22986a2beb9284fd3e860e200 100644 (file)
@@ -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__ */