static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen; int ret; mode |= S_IFDIR; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); /* 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), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_dir_inode_operations; inode->i_fop = &jffs2_dir_operations; f = JFFS2_INODE_INFO(inode); /* Directories get nlink 2 at start */ inode->i_nlink = 2; /* but ic->pino_nlink is the parent ino# */ f->inocache->pino_nlink = dir_i->i_ino; ri->data_crc = cpu_to_je32(0); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = PTR_ERR(fn); goto fail; } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = jffs2_init_security(inode, dir_i, &dentry->d_name); if (ret) goto fail; ret = jffs2_init_acl_post(inode); if (ret) goto fail; ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) goto fail; rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); ret = -ENOMEM; goto fail; } dir_f = JFFS2_INODE_INFO(dir_i); mutex_lock(&dir_f->sem); rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; rd->type = DT_DIR; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); ret = PTR_ERR(fd); goto fail; } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); inc_nlink(dir_i); jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); d_instantiate(dentry, inode); unlock_new_inode(inode); return 0; fail: iget_failed(inode); return ret; }
static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_summary *summary, uint32_t *pseudo_random) { struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; void *sp; int i, ino; int err; sp = summary->sum; for (i=0; i<je32_to_cpu(summary->sum_num); i++) { dbg_summary("processing summary index %d\n", i); cond_resched(); /* Make sure there's a spare ref for dirty space */ err = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (err) return err; switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *spi; spi = sp; ino = je32_to_cpu(spi->inode); dbg_summary("Inode at 0x%08x-0x%08x\n", jeb->offset + je32_to_cpu(spi->offset), jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen)); ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) { JFFS2_NOTICE("scan_make_ino_cache failed\n"); return -ENOMEM; } sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); sp += JFFS2_SUMMARY_INODE_SIZE; break; } case JFFS2_NODETYPE_DIRENT: { struct jffs2_sum_dirent_flash *spd; int checkedlen; spd = sp; dbg_summary("Dirent at 0x%08x-0x%08x\n", jeb->offset + je32_to_cpu(spd->offset), jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); /* This should never happen, but https://dev.laptop.org/ticket/4184 */ checkedlen = strnlen(spd->name, spd->nsize); if (!checkedlen) { pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n", jeb->offset + je32_to_cpu(spd->offset)); return -EIO; } if (checkedlen < spd->nsize) { pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n", jeb->offset + je32_to_cpu(spd->offset), checkedlen); } fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) return -ENOMEM; memcpy(&fd->name, spd->name, checkedlen); fd->name[checkedlen] = 0; ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); if (!ic) { jffs2_free_full_dirent(fd); return -ENOMEM; } fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_UNCHECKED, PAD(je32_to_cpu(spd->totlen)), ic); fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); fd->nhash = full_name_hash(NULL, fd->name, checkedlen); fd->type = spd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); *pseudo_random += je32_to_cpu(spd->version); sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); break; } #ifdef CONFIG_JFFS2_FS_XATTR case JFFS2_NODETYPE_XATTR: { struct jffs2_xattr_datum *xd; struct jffs2_sum_xattr_flash *spx; spx = (struct jffs2_sum_xattr_flash *)sp; dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", jeb->offset + je32_to_cpu(spx->offset), jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); if (IS_ERR(xd)) return PTR_ERR(xd); if (xd->version > je32_to_cpu(spx->version)) { /* node is not the newest one */ struct jffs2_raw_node_ref *raw = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, PAD(je32_to_cpu(spx->totlen)), NULL); raw->next_in_ino = xd->node->next_in_ino; xd->node->next_in_ino = raw; } else { xd->version = je32_to_cpu(spx->version); sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, PAD(je32_to_cpu(spx->totlen)), (void *)xd); } *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; break; } case JFFS2_NODETYPE_XREF: { struct jffs2_xattr_ref *ref; struct jffs2_sum_xref_flash *spr; spr = (struct jffs2_sum_xref_flash *)sp; dbg_summary("xref at %#08x-%#08x\n", jeb->offset + je32_to_cpu(spr->offset), jeb->offset + je32_to_cpu(spr->offset) + (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); ref = jffs2_alloc_xattr_ref(); if (!ref) { JFFS2_NOTICE("allocation of xattr_datum failed\n"); return -ENOMEM; } ref->next = c->xref_temp; c->xref_temp = ref; sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, PAD(sizeof(struct jffs2_raw_xref)), (void *)ref); *pseudo_random += ref->node->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; break; } #endif default : { uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype); JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype); if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT) return -EIO; /* For compatible node types, just fall back to the full scan */ c->wasted_size -= jeb->wasted_size; c->free_size += c->sector_size - jeb->free_size; c->used_size -= jeb->used_size; c->dirty_size -= jeb->dirty_size; jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0; jeb->free_size = c->sector_size; jffs2_free_jeb_node_refs(c, jeb); return -ENOTRECOVERABLE; } } } return 0; }
static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen; int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ if (targetlen > 254) return -ENAMETOOLONG; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); /* 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) + targetlen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_symlink_inode_operations; f = JFFS2_INODE_INFO(inode); inode->i_size = targetlen; ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = PTR_ERR(fn); goto fail; } /* We use f->target field to store the target path. */ f->target = kmemdup(target, targetlen + 1, GFP_KERNEL); if (!f->target) { ; mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = -ENOMEM; goto fail; } D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = jffs2_init_security(inode, dir_i, &dentry->d_name); if (ret) goto fail; ret = jffs2_init_acl_post(inode); if (ret) goto fail; ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) goto fail; rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); ret = -ENOMEM; goto fail; } dir_f = JFFS2_INODE_INFO(dir_i); mutex_lock(&dir_f->sem); rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; rd->type = DT_LNK; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); ret = PTR_ERR(fd); goto fail; } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); d_instantiate(dentry, inode); unlock_new_inode(inode); return 0; fail: iget_failed(inode); return ret; }
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s) { struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; uint32_t checkedlen; uint32_t crc; int err; D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs)); /* We don't get here unless the node is still valid, so we don't have to mask in the ACCURATE bit any more. */ crc = crc32(0, rd, sizeof(*rd)-8); if (crc != je32_to_cpu(rd->node_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ofs, je32_to_cpu(rd->node_crc), crc); /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen))))) return err; return 0; } pseudo_random += je32_to_cpu(rd->version); /* Should never happen. Did. (OLPC trac #4184)*/ checkedlen = strnlen(rd->name, rd->nsize); if (checkedlen < rd->nsize) { printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", ofs, checkedlen); } fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) { return -ENOMEM; } memcpy(&fd->name, rd->name, checkedlen); fd->name[checkedlen] = 0; crc = crc32(0, fd->name, rd->nsize); if (crc != je32_to_cpu(rd->name_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ofs, je32_to_cpu(rd->name_crc), crc); D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); jffs2_free_full_dirent(fd); /* FIXME: Why do we believe totlen? */ /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */ if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen))))) return err; return 0; } ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); if (!ic) { jffs2_free_full_dirent(fd); return -ENOMEM; } fd->raw = jffs2_link_node_ref(c, jeb, ofs | dirent_node_state(rd), PAD(je32_to_cpu(rd->totlen)), ic); fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = rd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); if (jffs2_sum_active()) { jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset); } return 0; }
/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an directory entry node is found. * * Returns: 0 on succes; * 1 if the node should be marked obsolete; * negative error code on failure. */ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_raw_dirent *rd, size_t read, struct jffs2_full_dirent **fdp, uint32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_full_dirent *fd; /* The direntry nodes are checked during the flash scanning */ BUG_ON(ref_flags(ref) == REF_UNCHECKED); /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); /* Sanity check */ if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); return 1; } fd = jffs2_alloc_full_dirent(rd->nsize + 1); if (unlikely(!fd)) return -ENOMEM; fd->raw = ref; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); fd->type = rd->type; /* Pick out the mctime of the latest dirent */ if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) { *mctime_ver = fd->version; *latest_mctime = je32_to_cpu(rd->mctime); } /* * Copy as much of the name as possible from the raw * dirent we've already read from the flash. */ if (read > sizeof(*rd)) memcpy(&fd->name[0], &rd->name[0], min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) )); /* Do we need to copy any more of the name directly from the flash? */ if (rd->nsize + sizeof(*rd) > read) { /* FIXME: point() */ int err; int already = read - sizeof(*rd); err = jffs2_flash_read(c, (ref_offset(ref)) + read, rd->nsize - already, &read, &fd->name[already]); if (unlikely(read != rd->nsize - already) && likely(!err)) return -EIO; if (unlikely(err)) { JFFS2_ERROR("read remainder of name: error %d\n", err); jffs2_free_full_dirent(fd); return -EIO; } } fd->nhash = full_name_hash(fd->name, rd->nsize); fd->next = NULL; fd->name[rd->nsize] = '\0'; /* * Wheee. We now have a complete jffs2_full_dirent structure, with * the name in it and everything. Link it into the list */ jffs2_add_fd_to_list(c, fd, fdp); return 0; }
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s) { struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; uint32_t checkedlen; uint32_t crc; int err; jffs2_dbg(1, "%s(): Node at 0x%08x\n", __func__, ofs); crc = crc32(0, rd, sizeof(*rd)-8); if (crc != je32_to_cpu(rd->node_crc)) { pr_notice("%s(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", __func__, ofs, je32_to_cpu(rd->node_crc), crc); if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen))))) return err; return 0; } pseudo_random += je32_to_cpu(rd->version); checkedlen = strnlen(rd->name, rd->nsize); if (checkedlen < rd->nsize) { pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n", ofs, checkedlen); } fd = jffs2_alloc_full_dirent(checkedlen+1); if (!fd) { return -ENOMEM; } memcpy(&fd->name, rd->name, checkedlen); fd->name[checkedlen] = 0; crc = crc32(0, fd->name, rd->nsize); if (crc != je32_to_cpu(rd->name_crc)) { pr_notice("%s(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", __func__, ofs, je32_to_cpu(rd->name_crc), crc); jffs2_dbg(1, "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)); jffs2_free_full_dirent(fd); if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen))))) return err; return 0; } ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); if (!ic) { jffs2_free_full_dirent(fd); return -ENOMEM; } fd->raw = jffs2_link_node_ref(c, jeb, ofs | dirent_node_state(rd), PAD(je32_to_cpu(rd->totlen)), ic); fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = rd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); if (jffs2_sum_active()) { jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset); } return 0; }
/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an directory entry node is found. * * Returns: 0 on success; * negative error code on failure. */ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_raw_dirent *rd, size_t read, struct jffs2_readinode_info *rii) { struct jffs2_full_dirent *fd; uint32_t crc; /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); crc = crc32(0, rd, sizeof(*rd) - 8); if (unlikely(crc != je32_to_cpu(rd->node_crc))) { JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n", ref_offset(ref), je32_to_cpu(rd->node_crc), crc); jffs2_mark_node_obsolete(c, ref); return 0; } /* If we've never checked the CRCs on this node, check them now */ if (ref_flags(ref) == REF_UNCHECKED) { struct jffs2_eraseblock *jeb; int len; /* Sanity check */ if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); jffs2_mark_node_obsolete(c, ref); return 0; } jeb = &c->blocks[ref->flash_offset / c->sector_size]; len = ref_totlen(c, jeb, ref); spin_lock(&c->erase_completion_lock); jeb->used_size += len; jeb->unchecked_size -= len; c->used_size += len; c->unchecked_size -= len; ref->flash_offset = ref_offset(ref) | dirent_node_state(rd); spin_unlock(&c->erase_completion_lock); } fd = jffs2_alloc_full_dirent(rd->nsize + 1); if (unlikely(!fd)) return -ENOMEM; fd->raw = ref; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); fd->type = rd->type; if (fd->version > rii->highest_version) rii->highest_version = fd->version; /* Pick out the mctime of the latest dirent */ if(fd->version > rii->mctime_ver && je32_to_cpu(rd->mctime)) { rii->mctime_ver = fd->version; rii->latest_mctime = je32_to_cpu(rd->mctime); } /* * Copy as much of the name as possible from the raw * dirent we've already read from the flash. */ if (read > sizeof(*rd)) memcpy(&fd->name[0], &rd->name[0], min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) )); /* Do we need to copy any more of the name directly from the flash? */ if (rd->nsize + sizeof(*rd) > read) { /* FIXME: point() */ int err; int already = read - sizeof(*rd); err = jffs2_flash_read(c, (ref_offset(ref)) + read, rd->nsize - already, &read, &fd->name[already]); if (unlikely(read != rd->nsize - already) && likely(!err)) return -EIO; if (unlikely(err)) { JFFS2_ERROR("read remainder of name: error %d\n", err); jffs2_free_full_dirent(fd); return -EIO; } } fd->nhash = full_name_hash(fd->name, rd->nsize); fd->next = NULL; fd->name[rd->nsize] = '\0'; /* * Wheee. We now have a complete jffs2_full_dirent structure, with * the name in it and everything. Link it into the list */ jffs2_add_fd_to_list(c, fd, &rii->fds); return 0; }
static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; __u32 alloclen, phys_ofs; __u32 writtenlen; int ret; /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ if (strlen(target) > 254) return -EINVAL; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); /* 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) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_symlink_inode_operations; f = JFFS2_INODE_INFO(inode); inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target); ri->totlen = sizeof(*ri) + ri->dsize; ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = crc32(0, target, strlen(target)); ri->node_crc = crc32(0, ri, sizeof(*ri)-8); fn = jffs2_write_dnode(inode, ri, target, strlen(target), phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); /* Work out where to put the dirent node now. */ writtenlen = (writtenlen+3)&~3; phys_ofs += writtenlen; alloclen -= writtenlen; if (alloclen < sizeof(*rd)+namelen) { /* Not enough space left in this chunk. Get some more */ jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ jffs2_clear_inode(inode); return ret; } } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = inode->i_ino; rd->mctime = CURRENT_TIME; rd->nsize = namelen; rd->type = DT_LNK; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } dir_i->i_mtime = dir_i->i_ctime = rd->mctime; jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); d_instantiate(dentry, inode); return 0; }
static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, int rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; unsigned short dev; int devlen = 0; __u32 alloclen, phys_ofs; __u32 writtenlen; int ret; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev)); devlen = sizeof(dev); } /* 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); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_file_inode_operations; init_special_inode(inode, inode->i_mode, rdev); f = JFFS2_INODE_INFO(inode); ri->dsize = ri->csize = devlen; ri->totlen = sizeof(*ri) + ri->csize; ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = crc32(0, &dev, devlen); ri->node_crc = crc32(0, ri, sizeof(*ri)-8); fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); /* Work out where to put the dirent node now. */ writtenlen = (writtenlen+3)&~3; phys_ofs += writtenlen; alloclen -= writtenlen; if (alloclen < sizeof(*rd)+namelen) { /* Not enough space left in this chunk. Get some more */ jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ jffs2_clear_inode(inode); return ret; } } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = inode->i_ino; rd->mctime = CURRENT_TIME; rd->nsize = namelen; /* XXX: This is ugly. */ rd->type = (mode & S_IFMT) >> 12; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } dir_i->i_mtime = dir_i->i_ctime = rd->mctime; jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); d_instantiate(dentry, inode); return 0; }
static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename) { struct jffs2_inode_info *dir_f, *f; struct jffs2_sb_info *c; struct jffs2_raw_dirent *rd; struct jffs2_full_dirent *fd; __u32 alloclen, phys_ofs; int ret; c = JFFS2_SB_INFO(dir_i->i_sb); rd = jffs2_alloc_raw_dirent(); if (!rd) return -ENOMEM; ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION); if (ret) { jffs2_free_raw_dirent(rd); return ret; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); /* Build a deletion node */ rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + dentry->d_name.len; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = 0; rd->mctime = CURRENT_TIME; rd->nsize = dentry->d_name.len; rd->type = DT_UNKNOWN; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { up(&dir_f->sem); return PTR_ERR(fd); } /* File it. This will mark the old one obsolete. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); if (!rename) { f = JFFS2_INODE_INFO(dentry->d_inode); down(&f->sem); while (f->dents) { /* There can be only deleted ones */ fd = f->dents; f->dents = fd->next; if (fd->ino) { printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", f->inocache->ino, fd->name, fd->ino); } else { D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino)); } jffs2_mark_node_obsolete(c, fd->raw); jffs2_free_full_dirent(fd); } /* Don't oops on unlinking a bad inode */ if (f->inocache) f->inocache->nlink--; dentry->d_inode->i_nlink--; up(&f->sem); } return 0; }
static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry, int rename) { struct jffs2_inode_info *dir_f, *f; struct jffs2_sb_info *c; struct jffs2_raw_dirent *rd; struct jffs2_full_dirent *fd; __u32 alloclen, phys_ofs; int ret; c = JFFS2_SB_INFO(dir_i->i_sb); rd = jffs2_alloc_raw_dirent(); if (!rd) return -ENOMEM; ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_dirent(rd); return ret; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); /* Build a deletion node */ rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + dentry->d_name.len; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = old_dentry->d_inode->i_ino; rd->mctime = CURRENT_TIME; rd->nsize = dentry->d_name.len; /* XXX: This is ugly. */ rd->type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!rd->type) rd->type = DT_REG; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { up(&dir_f->sem); return PTR_ERR(fd); } /* File it. This will mark the old one obsolete. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); if (!rename) { f = JFFS2_INODE_INFO(old_dentry->d_inode); down(&f->sem); old_dentry->d_inode->i_nlink = ++f->inocache->nlink; up(&f->sem); } return 0; }
static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; __u32 alloclen, phys_ofs; __u32 writtenlen; int ret; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); D1(printk(KERN_DEBUG "jffs2_create()\n")); /* 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), &phys_ofs, &alloclen, ALLOC_NORMAL); D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen)); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_file_inode_operations; inode->i_fop = &jffs2_file_operations; inode->i_mapping->a_ops = &jffs2_file_address_operations; inode->i_mapping->nrpages = 0; f = JFFS2_INODE_INFO(inode); ri->data_crc = 0; ri->node_crc = crc32(0, ri, sizeof(*ri)-8); fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode)); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; /* Work out where to put the dirent node now. */ writtenlen = PAD(writtenlen); phys_ofs += writtenlen; alloclen -= writtenlen; up(&f->sem); if (alloclen < sizeof(*rd)+namelen) { /* Not enough space left in this chunk. Get some more */ jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); jffs2_clear_inode(inode); return ret; } } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = inode->i_ino; rd->mctime = CURRENT_TIME; rd->nsize = namelen; rd->type = DT_REG; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_free_raw_dirent(rd); up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } dir_i->i_mtime = dir_i->i_ctime = rd->mctime; jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); d_instantiate(dentry, inode); D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); return 0; }
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; uint32_t crc; D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs)); /* We don't get here unless the node is still valid, so we don't have to mask in the ACCURATE bit any more. */ crc = crc32(0, rd, sizeof(*rd)-8); if (crc != je32_to_cpu(rd->node_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ofs, je32_to_cpu(rd->node_crc), crc); /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); return 0; } pseudo_random += je32_to_cpu(rd->version); fd = jffs2_alloc_full_dirent(rd->nsize+1); if (!fd) { return -ENOMEM; } memcpy(&fd->name, rd->name, rd->nsize); fd->name[rd->nsize] = 0; crc = crc32(0, fd->name, rd->nsize); if (crc != je32_to_cpu(rd->name_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ofs, je32_to_cpu(rd->name_crc), crc); D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); jffs2_free_full_dirent(fd); /* FIXME: Why do we believe totlen? */ /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); return 0; } raw = jffs2_alloc_raw_node_ref(); if (!raw) { jffs2_free_full_dirent(fd); printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n"); return -ENOMEM; } ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); if (!ic) { jffs2_free_full_dirent(fd); jffs2_free_raw_node_ref(raw); return -ENOMEM; } raw->totlen = PAD(je32_to_cpu(rd->totlen)); raw->flash_offset = ofs | REF_PRISTINE; raw->next_phys = NULL; raw->next_in_ino = ic->nodes; ic->nodes = raw; if (!jeb->first_node) jeb->first_node = raw; if (jeb->last_node) jeb->last_node->next_phys = raw; jeb->last_node = raw; fd->raw = raw; fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); fd->nhash = full_name_hash(fd->name, rd->nsize); fd->type = rd->type; USED_SPACE(PAD(je32_to_cpu(rd->totlen))); jffs2_add_fd_to_list(c, fd, &ic->scan_dents); return 0; }
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; struct jffs2_raw_dirent rd; __u16 oldnodetype; int ret; __u32 crc; ssize_t retlen; D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs)); ret = c->mtd->read(c->mtd, *ofs, sizeof(rd), &retlen, (char *)&rd); if (ret) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret); return ret; } if (retlen != sizeof(rd)) { printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", retlen, *ofs, sizeof(rd)); return -EIO; } /* We sort of assume that the node was accurate when it was first written to the medium :) */ oldnodetype = rd.nodetype; rd.nodetype |= JFFS2_NODE_ACCURATE; crc = crc32(0, &rd, sizeof(rd)-8); rd.nodetype = oldnodetype; if (crc != rd.node_crc) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", *ofs, rd.node_crc, crc); /* FIXME: Why do we believe totlen? */ DIRTY_SPACE(4); *ofs += 4; return 0; } pseudo_random += rd.version; fd = jffs2_alloc_full_dirent(rd.nsize+1); if (!fd) { return -ENOMEM; } ret = c->mtd->read(c->mtd, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]); if (ret) { jffs2_free_full_dirent(fd); printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs + sizeof(rd), ret); return ret; } if (retlen != rd.nsize) { jffs2_free_full_dirent(fd); printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", retlen, *ofs + sizeof(rd), rd.nsize); return -EIO; } crc = crc32(0, fd->name, rd.nsize); if (crc != rd.name_crc) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", *ofs, rd.name_crc, crc); fd->name[rd.nsize]=0; D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino)); jffs2_free_full_dirent(fd); /* FIXME: Why do we believe totlen? */ DIRTY_SPACE(PAD(rd.totlen)); *ofs += PAD(rd.totlen); return 0; } raw = jffs2_alloc_raw_node_ref(); if (!raw) { jffs2_free_full_dirent(fd); printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n"); return -ENOMEM; } ic = jffs2_scan_make_ino_cache(c, rd.pino); if (!ic) { jffs2_free_full_dirent(fd); jffs2_free_raw_node_ref(raw); return -ENOMEM; } raw->totlen = PAD(rd.totlen); raw->flash_offset = *ofs; raw->next_phys = NULL; raw->next_in_ino = ic->nodes; ic->nodes = raw; if (!jeb->first_node) jeb->first_node = raw; if (jeb->last_node) jeb->last_node->next_phys = raw; jeb->last_node = raw; if (rd.nodetype & JFFS2_NODE_ACCURATE) { fd->raw = raw; fd->next = NULL; fd->version = rd.version; fd->ino = rd.ino; fd->name[rd.nsize]=0; fd->nhash = full_name_hash(fd->name, rd.nsize); fd->type = rd.type; USED_SPACE(PAD(rd.totlen)); jffs2_add_fd_to_list(c, fd, &ic->scan->dents); } else { raw->flash_offset |= 1; jffs2_free_full_dirent(fd); DIRTY_SPACE(PAD(rd.totlen)); } *ofs += PAD(rd.totlen); return 0; }
static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; union jffs2_device_node dev; int devlen = 0; uint32_t alloclen; int ret; if (!new_valid_dev(rdev)) return -EINVAL; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); 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, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } inode->i_op = &jffs2_file_inode_operations; init_special_inode(inode, inode->i_mode, rdev); f = JFFS2_INODE_INFO(inode); ri->dsize = ri->csize = cpu_to_je32(devlen); ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = PTR_ERR(fn); goto fail; } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; mutex_unlock(&f->sem); jffs2_complete_reservation(c); ret = jffs2_init_security(inode, dir_i, &dentry->d_name); if (ret) goto fail; ret = jffs2_init_acl_post(inode); if (ret) goto fail; ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) goto fail; rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); ret = -ENOMEM; goto fail; } dir_f = JFFS2_INODE_INFO(dir_i); mutex_lock(&dir_f->sem); rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); rd->mctime = cpu_to_je32(get_seconds()); rd->nsize = namelen; /* XXX: This is ugly. */ rd->type = (mode & S_IFMT) >> 12; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); ret = PTR_ERR(fd); goto fail; } dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); d_instantiate(dentry, inode); unlock_new_inode(inode); return 0; fail: iget_failed(inode); return ret; }
int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct _inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; int ret; mode |= S_IFDIR; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ namelen = strlen((char *)d_name); ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } f = JFFS2_INODE_INFO(inode); ri->data_crc = cpu_to_je32(0); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); inode->i_nlink = 0; jffs2_iput(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ inode->i_nlink = 0; jffs2_iput(inode); return ret; } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); inode->i_nlink = 0; jffs2_iput(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); rd->mctime = cpu_to_je32(jffs2_get_timestamp()); rd->nsize = namelen; rd->type = DT_DIR; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ up(&dir_f->sem); inode->i_nlink = 0; jffs2_iput(inode); return PTR_ERR(fd); } /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); jffs2_iput(inode); return 0; }
int jffs2_mkdir (struct inode *dir_i, struct qstr *d_name, int mode, struct inode **new_i) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; struct inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; uint32_t writtenlen; int ret; mode |= S_IFDIR; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; c = JFFS2_SB_INFO(dir_i->i_sb); /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ namelen = d_name->len; ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); return ret; } inode = jffs2_new_inode(dir_i, mode, ri); if (IS_ERR(inode)) { jffs2_free_raw_inode(ri); jffs2_complete_reservation(c); return PTR_ERR(inode); } f = JFFS2_INODE_INFO(inode); ri->data_crc = 0; ri->node_crc = crc32(0, ri, sizeof(*ri)-8); fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); if (IS_ERR(fn)) { /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); /* Work out where to put the dirent node now. */ writtenlen = PAD(writtenlen); phys_ofs += writtenlen; alloclen -= writtenlen; if (alloclen < sizeof(*rd)+namelen) { /* Not enough space left in this chunk. Get some more */ jffs2_complete_reservation(c); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { /* Eep. */ jffs2_clear_inode(inode); return ret; } } rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->pino = dir_i->i_ino; rd->version = ++dir_f->highest_version; rd->ino = inode->i_ino; rd->mctime = CURRENT_TIME; rd->nsize = namelen; rd->type = DT_DIR; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, d_name->name, namelen); fd = jffs2_write_dirent(c, dir_f, rd, d_name->name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ up(&dir_f->sem); jffs2_clear_inode(inode); return PTR_ERR(fd); } /* Link the fd into the inode's list, obsoleting an old one if necessary. */ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); *new_i = inode; return 0; }
static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_summary *summary, uint32_t *pseudo_random) { struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; void *sp; int i, ino; sp = summary->sum; for (i=0; i<je32_to_cpu(summary->sum_num); i++) { dbg_summary("processing summary index %d\n", i); switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *spi; spi = sp; ino = je32_to_cpu(spi->inode); dbg_summary("Inode at 0x%08x\n", jeb->offset + je32_to_cpu(spi->offset)); raw = jffs2_alloc_raw_node_ref(); if (!raw) { JFFS2_NOTICE("allocation of node reference failed\n"); kfree(summary); return -ENOMEM; } ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) { JFFS2_NOTICE("scan_make_ino_cache failed\n"); jffs2_free_raw_node_ref(raw); kfree(summary); return -ENOMEM; } raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED; raw->__totlen = PAD(je32_to_cpu(spi->totlen)); raw->next_phys = NULL; raw->next_in_ino = ic->nodes; ic->nodes = raw; if (!jeb->first_node) jeb->first_node = raw; if (jeb->last_node) jeb->last_node->next_phys = raw; jeb->last_node = raw; *pseudo_random += je32_to_cpu(spi->version); UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen))); sp += JFFS2_SUMMARY_INODE_SIZE; break; } case JFFS2_NODETYPE_DIRENT: { struct jffs2_sum_dirent_flash *spd; spd = sp; dbg_summary("Dirent at 0x%08x\n", jeb->offset + je32_to_cpu(spd->offset)); fd = jffs2_alloc_full_dirent(spd->nsize+1); if (!fd) { kfree(summary); return -ENOMEM; } memcpy(&fd->name, spd->name, spd->nsize); fd->name[spd->nsize] = 0; raw = jffs2_alloc_raw_node_ref(); if (!raw) { jffs2_free_full_dirent(fd); JFFS2_NOTICE("allocation of node reference failed\n"); kfree(summary); return -ENOMEM; } ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); if (!ic) { jffs2_free_full_dirent(fd); jffs2_free_raw_node_ref(raw); kfree(summary); return -ENOMEM; } raw->__totlen = PAD(je32_to_cpu(spd->totlen)); raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE; raw->next_phys = NULL; raw->next_in_ino = ic->nodes; ic->nodes = raw; if (!jeb->first_node) jeb->first_node = raw; if (jeb->last_node) jeb->last_node->next_phys = raw; jeb->last_node = raw; fd->raw = raw; fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); fd->nhash = full_name_hash(fd->name, spd->nsize); fd->type = spd->type; USED_SPACE(PAD(je32_to_cpu(spd->totlen))); jffs2_add_fd_to_list(c, fd, &ic->scan_dents); *pseudo_random += je32_to_cpu(spd->version); sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); break; } default : { JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); kfree(summary); return -EIO; } } } kfree(summary); return 0; }