summaryrefslogtreecommitdiffstats
path: root/fs/jffs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/dir.c12
-rw-r--r--fs/jffs2/fs.c25
-rw-r--r--fs/jffs2/gc.c7
-rw-r--r--fs/jffs2/nodelist.h11
-rw-r--r--fs/jffs2/nodemgmt.c39
-rw-r--r--fs/jffs2/os-linux.h4
-rw-r--r--fs/jffs2/scan.c85
-rw-r--r--fs/jffs2/summary.c36
-rw-r--r--fs/jffs2/summary.h3
9 files changed, 122 insertions, 100 deletions
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index f1b18b9..ff1b795 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -629,12 +629,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();
@@ -643,17 +643,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 4607cdc..a0f8467 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);
@@ -238,6 +237,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));
@@ -269,7 +270,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;
@@ -303,8 +303,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);
@@ -312,12 +320,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 a5ef9814..23587f8 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -700,7 +700,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;
@@ -708,11 +708,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 351d947..8dda98f 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -281,6 +281,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/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 49127a1..0e1f58a 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -470,6 +470,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
struct jffs2_unknown_node n;
int ret, addedsize;
size_t retlen;
+ uint32_t freed_len;
if(!ref) {
printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
@@ -499,32 +500,34 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
spin_lock(&c->erase_completion_lock);
+ freed_len = ref_totlen(c, jeb, ref);
+
if (ref_flags(ref) == REF_UNCHECKED) {
- D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) {
+ D1(if (unlikely(jeb->unchecked_size < freed_len)) {
printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
- ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
+ freed_len, blocknr, ref->flash_offset, jeb->used_size);
BUG();
})
- D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
- jeb->unchecked_size -= ref_totlen(c, jeb, ref);
- c->unchecked_size -= ref_totlen(c, jeb, ref);
+ D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), freed_len));
+ jeb->unchecked_size -= freed_len;
+ c->unchecked_size -= freed_len;
} else {
- D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) {
+ D1(if (unlikely(jeb->used_size < freed_len)) {
printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
- ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
+ freed_len, blocknr, ref->flash_offset, jeb->used_size);
BUG();
})
- D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
- jeb->used_size -= ref_totlen(c, jeb, ref);
- c->used_size -= ref_totlen(c, jeb, ref);
+ D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), freed_len));
+ jeb->used_size -= freed_len;
+ c->used_size -= freed_len;
}
// Take care, that wasted size is taken into concern
- if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
+ if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) {
D1(printk(KERN_DEBUG "Dirtying\n"));
- addedsize = ref_totlen(c, jeb, ref);
- jeb->dirty_size += ref_totlen(c, jeb, ref);
- c->dirty_size += ref_totlen(c, jeb, ref);
+ addedsize = freed_len;
+ jeb->dirty_size += freed_len;
+ c->dirty_size += freed_len;
/* Convert wasted space to dirty, if not a bad block */
if (jeb->wasted_size) {
@@ -545,8 +548,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
} else {
D1(printk(KERN_DEBUG "Wasting\n"));
addedsize = 0;
- jeb->wasted_size += ref_totlen(c, jeb, ref);
- c->wasted_size += ref_totlen(c, jeb, ref);
+ jeb->wasted_size += freed_len;
+ c->wasted_size += freed_len;
}
ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
@@ -634,8 +637,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
goto out_erase_sem;
}
- if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
- printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
+ if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) {
+ printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), freed_len);
goto out_erase_sem;
}
if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 9936ae2..d2ad2a2 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/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 5847e76..40d62d0 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -437,11 +437,12 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock
}
#endif
+/* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into
+ the flash, XIP-style */
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
+ unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
struct jffs2_unknown_node *node;
struct jffs2_unknown_node crcnode;
- struct jffs2_sum_marker *sm;
uint32_t ofs, prevofs;
uint32_t hdr_crc, buf_ofs, buf_len;
int err;
@@ -475,44 +476,70 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
#endif
if (jffs2_sum_active()) {
- sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL);
- if (!sm) {
- return -ENOMEM;
- }
+ struct jffs2_sum_marker *sm;
+ void *sumptr = NULL;
+ uint32_t sumlen;
+
+ if (!buf_size) {
+ /* XIP case. Just look, point at the summary if it's there */
+ sm = (void *)buf + jeb->offset - sizeof(*sm);
+ if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
+ sumptr = buf + je32_to_cpu(sm->offset);
+ sumlen = c->sector_size - je32_to_cpu(sm->offset);
+ }
+ } else {
+ /* If NAND flash, read a whole page of it. Else just the end */
+ if (c->wbuf_pagesize)
+ buf_len = c->wbuf_pagesize;
+ else
+ buf_len = sizeof(*sm);
+
+ /* Read as much as we want into the _end_ of the preallocated buffer */
+ err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
+ jeb->offset + c->sector_size - buf_len,
+ buf_len);
+ if (err)
+ return err;
+
+ sm = (void *)buf + buf_size - sizeof(*sm);
+ if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
+ sumlen = c->sector_size - je32_to_cpu(sm->offset);
+ sumptr = buf + buf_size - sumlen;
+
+ /* Now, make sure the summary itself is available */
+ if (sumlen > buf_size) {
+ /* Need to kmalloc for this. */
+ sumptr = kmalloc(sumlen, GFP_KERNEL);
+ if (!sumptr)
+ return -ENOMEM;
+ memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len);
+ }
+ if (buf_len < sumlen) {
+ /* Need to read more so that the entire summary node is present */
+ err = jffs2_fill_scan_buf(c, sumptr,
+ jeb->offset + c->sector_size - sumlen,
+ sumlen - buf_len);
+ if (err)
+ return err;
+ }
+ }
- err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size -
- sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker));
- if (err) {
- kfree(sm);
- return err;
}
- if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) {
- err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random);
- if (err) {
- kfree(sm);
+ if (sumptr) {
+ err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random);
+ if (err)
return err;
- }
+ if (buf_size && sumlen > buf_size)
+ kfree(sumptr);
}
-
- kfree(sm);
-
- ofs = jeb->offset;
- prevofs = jeb->offset - 1;
}
buf_ofs = jeb->offset;
if (!buf_size) {
+ /* This is the XIP case -- we're reading _directly_ from the flash chip */
buf_len = c->sector_size;
-
- if (jffs2_sum_active()) {
- /* must reread because of summary test */
- err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
- if (err)
- return err;
- }
-
} else {
buf_len = EMPTY_SCAN_SIZE(c->sector_size);
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 439b9f6..5dbe87b 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -399,7 +399,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
raw = jffs2_alloc_raw_node_ref();
if (!raw) {
JFFS2_NOTICE("allocation of node reference failed\n");
- kfree(summary);
return -ENOMEM;
}
@@ -407,7 +406,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!ic) {
JFFS2_NOTICE("scan_make_ino_cache failed\n");
jffs2_free_raw_node_ref(raw);
- kfree(summary);
return -ENOMEM;
}
@@ -439,10 +437,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
jeb->offset + je32_to_cpu(spd->offset));
fd = jffs2_alloc_full_dirent(spd->nsize+1);
- if (!fd) {
- kfree(summary);
+ if (!fd)
return -ENOMEM;
- }
memcpy(&fd->name, spd->name, spd->nsize);
fd->name[spd->nsize] = 0;
@@ -451,7 +447,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!raw) {
jffs2_free_full_dirent(fd);
JFFS2_NOTICE("allocation of node reference failed\n");
- kfree(summary);
return -ENOMEM;
}
@@ -459,7 +454,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!ic) {
jffs2_free_full_dirent(fd);
jffs2_free_raw_node_ref(raw);
- kfree(summary);
return -ENOMEM;
}
@@ -585,45 +579,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
default : {
printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype));
JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
- kfree(summary);
return -EIO;
}
}
}
- kfree(summary);
return 0;
}
/* Process the summary node - called from jffs2_scan_eraseblock() */
-
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- uint32_t ofs, uint32_t *pseudo_random)
+ struct jffs2_raw_summary *summary, uint32_t sumsize,
+ uint32_t *pseudo_random)
{
struct jffs2_unknown_node crcnode;
struct jffs2_raw_node_ref *cache_ref;
- struct jffs2_raw_summary *summary;
- int ret, sumsize;
+ int ret, ofs;
uint32_t crc;
- sumsize = c->sector_size - ofs;
- ofs += jeb->offset;
+ ofs = jeb->offset + c->sector_size - sumsize;
dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
- jeb->offset, ofs, sumsize);
-
- summary = kmalloc(sumsize, GFP_KERNEL);
-
- if (!summary) {
- return -ENOMEM;
- }
-
- ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
-
- if (ret) {
- kfree(summary);
- return ret;
- }
+ jeb->offset, ofs, sumsize);
/* OK, now check for node validity and CRC */
crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -673,7 +650,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
if (!marker_ref) {
JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
- kfree(summary);
return -ENOMEM;
}
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
index a3b66c1..ce892d5 100644
--- a/fs/jffs2/summary.h
+++ b/fs/jffs2/summary.h
@@ -200,7 +200,8 @@ int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *r
int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs);
int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs);
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- uint32_t ofs, uint32_t *pseudo_random);
+ struct jffs2_raw_summary *summary, uint32_t sumlen,
+ uint32_t *pseudo_random);
#else /* SUMMARY DISABLED */
OpenPOWER on IntegriCloud