Skip to content

Commit

Permalink
[JFFS2] Support new device nodes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
dwmw2 committed May 18, 2006
1 parent f6a673b commit aef9ab4
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 22 deletions.
12 changes: 5 additions & 7 deletions fs/jffs2/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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);
Expand Down
25 changes: 18 additions & 7 deletions fs/jffs2/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -297,21 +297,32 @@ 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);
jffs2_do_clear_inode(c, f);
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:
Expand Down
7 changes: 2 additions & 5 deletions fs/jffs2/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,19 +679,16 @@ 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;

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;
Expand Down
11 changes: 11 additions & 0 deletions fs/jffs2/nodelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 1 addition & 3 deletions fs/jffs2/os-linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions include/linux/jffs2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */

0 comments on commit aef9ab4

Please sign in to comment.