Commit aef9ab47 authored by David Woodhouse's avatar David Woodhouse
Browse files

[JFFS2] Support new device nodes



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: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent f6a673b3
......@@ -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);
......
......@@ -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:
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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)
......
......@@ -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__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment