/* * JFFS3 -- Journalling Flash File System, Version 3. * * Copyright (C) 2001-2003 Red Hat, Inc. * * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * * JFFS2 Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp * $Id: fs.c,v 3.9 2005/02/09 14:25:14 pavlov Exp $ * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "nodelist.h" #include "summary.h" static int jffs3_do_setattr (struct inode *inode, struct iattr *iattr) { struct jffs3_full_dnode *old_metadata, *new_metadata; struct jffs3_inode_info *f = JFFS3_INODE_INFO(inode); struct jffs3_sb_info *c = JFFS3_SB_INFO(inode->i_sb); struct jffs3_raw_inode *ri; unsigned short dev; unsigned char *mdata = NULL; int mdatalen = 0; unsigned int ivalid; uint32_t phys_ofs, alloclen; int ret; DBG_VFS(1, "ino #%lu\n", inode->i_ino); ret = inode_change_ok(inode, iattr); if (ret) return ret; /* Special cases - we don't want more than one data node for these types on the medium at any time. So setattr must read the original data associated with the node (i.e. the device numbers or the target name) and write 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); mdata = (char *)&dev; mdatalen = sizeof(dev); DBG_VFS(1, "Writing %d bytes of kdev_t\n", mdatalen); } else if (S_ISLNK(inode->i_mode)) { mdatalen = f->metadata->size; mdata = kmalloc(f->metadata->size, GFP_USER); if (!mdata) return -ENOMEM; ret = jffs3_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); if (ret) { kfree(mdata); return ret; } DBG_VFS(1, "Writing %d bytes of symlink target\n", mdatalen); } ri = jffs3_alloc_raw_inode(); if (!ri) { if (S_ISLNK(inode->i_mode)) kfree(mdata); return -ENOMEM; } ret = jffs3_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL, JFFS3_SUMMARY_INODE_SIZE); if (ret) { jffs3_free_raw_inode(ri); if (S_ISLNK(inode->i_mode & S_IFMT)) kfree(mdata); return ret; } down(&f->sem); ivalid = iattr->ia_valid; ri->magic = cpu_to_je16(JFFS3_MAGIC_BITMASK); ri->nodetype = cpu_to_je16(JFFS3_NODETYPE_INODE); ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs3_unknown_node)-4)); ri->ino = cpu_to_je32(inode->i_ino); ri->version = cpu_to_je32(++f->highest_version); ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid); ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid); if (ivalid & ATTR_MODE) if (iattr->ia_mode & S_ISGID && !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); else ri->mode = cpu_to_jemode(iattr->ia_mode); else ri->mode = cpu_to_jemode(inode->i_mode); ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); ri->offset = cpu_to_je32(0); ri->csize = ri->dsize = cpu_to_je32(mdatalen); ri->compr = JFFS3_COMPR_NONE; if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { /* It's an extension. Make it a hole node */ ri->compr = JFFS3_COMPR_ZERO; ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); ri->offset = cpu_to_je32(inode->i_size); } ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); if (mdatalen) ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); else ri->data_crc = cpu_to_je32(0); new_metadata = jffs3_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL); if (S_ISLNK(inode->i_mode)) kfree(mdata); if (IS_ERR(new_metadata)) { jffs3_complete_reservation(c); jffs3_free_raw_inode(ri); up(&f->sem); return PTR_ERR(new_metadata); } /* It worked. Update the inode */ inode->i_atime = ITIME(je32_to_cpu(ri->atime)); inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); inode->i_mode = jemode_to_cpu(ri->mode); inode->i_uid = je16_to_cpu(ri->uid); inode->i_gid = je16_to_cpu(ri->gid); old_metadata = f->metadata; if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) jffs3_truncate_fraglist (c, &f->fragtree, iattr->ia_size); if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { jffs3_add_full_dnode_to_inode(c, f, new_metadata); inode->i_size = iattr->ia_size; f->metadata = NULL; } else { f->metadata = new_metadata; } if (old_metadata) { jffs3_mark_node_obsolete(c, old_metadata->raw); jffs3_free_full_dnode(old_metadata); } jffs3_free_raw_inode(ri); up(&f->sem); jffs3_complete_reservation(c); /* We have to do the vmtruncate() without f->sem held, since some pages may be locked and waiting for it in readpage(). We are protected from a simultaneous write() extending i_size back past iattr->ia_size, because do_truncate() holds the generic inode semaphore. */ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) vmtruncate(inode, iattr->ia_size); return 0; } int jffs3_setattr (struct dentry *dentry, struct iattr *iattr) { return jffs3_do_setattr(dentry->d_inode, iattr); } int jffs3_statfs (struct super_block *sb, struct kstatfs *buf) { struct jffs3_sb_info *c = JFFS3_SB_INFO(sb); unsigned long avail; buf->f_type = JFFS3_SUPER_MAGIC; buf->f_bsize = 1 << PAGE_SHIFT; buf->f_blocks = c->flash_size >> PAGE_SHIFT; buf->f_files = 0; buf->f_ffree = 0; buf->f_namelen = JFFS3_MAX_NAME_LEN; spin_lock(&c->erase_completion_lock); avail = c->dirty_size + c->free_size; if (avail > c->sector_size * c->resv_blocks_write) avail -= c->sector_size * c->resv_blocks_write; else avail = 0; buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; if (DEBUG2) { DBG_VFS(2, "Blocks info:\n"); jffs3_dbg_dump_block_lists(c); } spin_unlock(&c->erase_completion_lock); return 0; } void jffs3_clear_inode (struct inode *inode) { /* We can forget about this inode for now - drop all * the nodelists associated with it, etc. */ struct jffs3_sb_info *c = JFFS3_SB_INFO(inode->i_sb); struct jffs3_inode_info *f = JFFS3_INODE_INFO(inode); DBG_VFS(1, "Clear ino #%lu, mode %o\n", inode->i_ino, inode->i_mode); jffs3_do_clear_inode(c, f); } void jffs3_read_inode (struct inode *inode) { struct jffs3_inode_info *f; struct jffs3_sb_info *c; struct jffs3_raw_inode latest_node; int ret; DBG_VFS(1, "Read ino #%lu\n", inode->i_ino); f = JFFS3_INODE_INFO(inode); c = JFFS3_SB_INFO(inode->i_sb); jffs3_init_inode_info(f); ret = jffs3_do_read_inode(c, f, inode->i_ino, &latest_node); if (ret) { make_bad_inode(inode); up(&f->sem); return; } inode->i_mode = jemode_to_cpu(latest_node.mode); inode->i_uid = je16_to_cpu(latest_node.uid); inode->i_gid = je16_to_cpu(latest_node.gid); inode->i_size = je32_to_cpu(latest_node.isize); inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); inode->i_nlink = f->inocache->nlink; inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; switch (inode->i_mode & S_IFMT) { jint16_t rdev; case S_IFLNK: inode->i_op = &jffs3_symlink_inode_operations; break; case S_IFDIR: { struct jffs3_full_dirent *fd; for (fd=f->dents; fd; fd = fd->next) { if (fd->type == DT_DIR && fd->ino) inode->i_nlink++; } /* and '..' */ inode->i_nlink++; /* Root dir gets i_nlink 3 for some reason */ if (inode->i_ino == 1) inode->i_nlink++; inode->i_op = &jffs3_dir_inode_operations; inode->i_fop = &jffs3_dir_operations; break; } case S_IFREG: inode->i_op = &jffs3_file_inode_operations; inode->i_fop = &jffs3_file_operations; inode->i_mapping->a_ops = &jffs3_file_address_operations; inode->i_mapping->nrpages = 0; break; case S_IFBLK: case S_IFCHR: /* Read the device numbers from the media */ DBG_VFS(1, "Reading device numbers from flash\n"); if (jffs3_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) { /* Eep */ NOTICE_MSG("Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino); up(&f->sem); jffs3_do_clear_inode(c, f); make_bad_inode(inode); return; } case S_IFSOCK: case S_IFIFO: inode->i_op = &jffs3_file_inode_operations; init_special_inode(inode, inode->i_mode, old_decode_dev((je16_to_cpu(rdev)))); break; default: WARNING_MSG("Bogus i_mode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); } up(&f->sem); DBG_VFS(1, "Inode #%u was read\n", f->inocache->ino); DBG_VFS(2, "Inode nlink %d, state %d, highest_version %d, flags %#x, " "fragtree root node %p, dents %p, metadata %p\n", f->inocache->nlink, f->inocache->state, f->highest_version, f->flags, f->fragtree.rb_node, f->dents, f->metadata); } void jffs3_dirty_inode (struct inode *inode) { struct iattr iattr; if (!(inode->i_state & I_DIRTY_DATASYNC)) { DBG_VFS(2, "Calling setattr() for ino #%lu\n", inode->i_ino); return; } DBG_VFS(1, "Calling setattr() for ino #%lu\n", inode->i_ino); iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME; iattr.ia_mode = inode->i_mode; iattr.ia_uid = inode->i_uid; iattr.ia_gid = inode->i_gid; iattr.ia_atime = inode->i_atime; iattr.ia_mtime = inode->i_mtime; iattr.ia_ctime = inode->i_ctime; jffs3_do_setattr(inode, &iattr); } int jffs3_remount_fs (struct super_block *sb, int *flags, char *data) { struct jffs3_sb_info *c = JFFS3_SB_INFO(sb); if (c->flags & JFFS3_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY)) return -EROFS; /* We stop if it was running, then restart if it needs to. This also catches the case where it was stopped and this is just a remount to restart it. Flush the writebuffer, if neccecary, else we loose it */ if (!(sb->s_flags & MS_RDONLY)) { jffs3_stop_garbage_collect_thread(c); down(&c->alloc_sem); jffs3_flush_wbuf_pad(c); up(&c->alloc_sem); } if (!(*flags & MS_RDONLY)) jffs3_start_garbage_collect_thread(c); *flags |= MS_NOATIME; return 0; } void jffs3_write_super (struct super_block *sb) { struct jffs3_sb_info *c = JFFS3_SB_INFO(sb); sb->s_dirt = 0; if (sb->s_flags & MS_RDONLY) return; DBG_VFS(1, "Entering\n"); jffs3_garbage_collect_trigger(c); jffs3_erase_pending_blocks(c, 0); jffs3_flush_wbuf_gc(c, 0); } /* jffs3_new_inode: allocate a new inode and inocache, add it to the hash, fill in the raw_inode while you're at it. */ struct inode *jffs3_new_inode (struct inode *dir_i, int mode, struct jffs3_raw_inode *ri) { struct inode *inode; struct super_block *sb = dir_i->i_sb; struct jffs3_sb_info *c; struct jffs3_inode_info *f; int ret; DBG_VFS(1, "dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode); c = JFFS3_SB_INFO(sb); inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); f = JFFS3_INODE_INFO(inode); jffs3_init_inode_info(f); memset(ri, 0, sizeof(*ri)); /* Set OS-specific defaults for new inodes */ ri->uid = cpu_to_je16(current->fsuid); if (dir_i->i_mode & S_ISGID) { ri->gid = cpu_to_je16(dir_i->i_gid); if (S_ISDIR(mode)) mode |= S_ISGID; } else { ri->gid = cpu_to_je16(current->fsgid); } ri->mode = cpu_to_jemode(mode); ret = jffs3_do_new_inode (c, f, mode, ri); if (ret) { make_bad_inode(inode); iput(inode); return ERR_PTR(ret); } inode->i_nlink = 1; inode->i_ino = je32_to_cpu(ri->ino); inode->i_mode = jemode_to_cpu(ri->mode); inode->i_gid = je16_to_cpu(ri->gid); inode->i_uid = je16_to_cpu(ri->uid); inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; inode->i_size = 0; insert_inode_hash(inode); return inode; } int jffs3_do_fill_super(struct super_block *sb, void *data, int silent) { struct jffs3_sb_info *c; struct inode *root_i; int ret; size_t blocks; c = JFFS3_SB_INFO(sb); #ifndef CONFIG_JFFS3_FS_WRITEBUFFER if (c->mtd->type == MTD_NANDFLASH) { ERROR_MSG("Cannot operate on NAND flash unless jffs3 NAND support is compiled in.\n"); return -EINVAL; } #endif c->flash_size = c->mtd->size; /* * Check, if we have to concatenate physical blocks to larger virtual blocks * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation) */ c->sector_size = c->mtd->erasesize; blocks = c->flash_size / c->sector_size; if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) { while ((blocks * sizeof (struct jffs3_eraseblock)) > (128 * 1024)) { blocks >>= 1; c->sector_size <<= 1; } } /* * Size alignment check */ if ((c->sector_size * blocks) != c->flash_size) { c->flash_size = c->sector_size * blocks; NOTICE_MSG("Flash size not aligned to erasesize, reducing to %dKiB\n", c->flash_size / 1024); } if (c->sector_size != c->mtd->erasesize) NOTICE_MSG("Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", c->mtd->erasesize / 1024, c->sector_size / 1024); if (c->flash_size < 5*c->sector_size) { ERROR_MSG("Too few erase blocks (%d)\n", c->flash_size / c->sector_size); return -EINVAL; } c->cleanmarker_size = sizeof(struct jffs3_unknown_node); /* Joern -- stick alignment for weird 8-byte-page flash here */ /* NAND (or other bizarre) flash... do setup accordingly */ ret = jffs3_flash_setup(c); if (ret) return ret; c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs3_inode_cache *), GFP_KERNEL); if (!c->inocache_list) { ret = -ENOMEM; goto out_wbuf; } memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs3_inode_cache *)); if ((ret = jffs3_do_mount_fs(c))) goto out_inohash; ret = -EINVAL; DBG_VFS(1, "Getting root inode\n"); root_i = iget(sb, 1); if (is_bad_inode(root_i)) { WARNING_MSG("Get root inode failed\n"); goto out_nodes; } sb->s_root = d_alloc_root(root_i); if (!sb->s_root) goto out_root_i; #if LINUX_VERSION_CODE >= 0x20403 sb->s_maxbytes = 0xFFFFFFFF; #endif sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = JFFS3_SUPER_MAGIC; if (!(sb->s_flags & MS_RDONLY)) jffs3_start_garbage_collect_thread(c); return 0; out_root_i: iput(root_i); out_nodes: jffs3_free_ino_caches(c); jffs3_free_raw_node_refs(c); if (c->mtd->flags & MTD_NO_VIRTBLOCKS) vfree(c->blocks); else kfree(c->blocks); out_inohash: kfree(c->inocache_list); out_wbuf: jffs3_flash_cleanup(c); return ret; } void jffs3_gc_release_inode(struct jffs3_sb_info *c, struct jffs3_inode_info *f) { iput(OFNI_EDONI_2SFFJ(f)); } struct jffs3_inode_info *jffs3_gc_fetch_inode(struct jffs3_sb_info *c, int inum, int nlink) { struct inode *inode; struct jffs3_inode_cache *ic; if (!nlink) { /* The inode has zero nlink but its nodes weren't yet marked obsolete. This has to be because we're still waiting for the final (close() and) iput() to happen. There's a possibility that the final iput() could have happened while we were contemplating. In order to ensure that we don't cause a new read_inode() (which would fail) for the inode in question, we use ilookup() in this case instead of iget(). The nlink can't _become_ zero at this point because we're holding the alloc_sem, and jffs3_do_unlink() would also need that while decrementing nlink on any inode. */ inode = ilookup(OFNI_BS_2SFFJ(c), inum); if (!inode) { DBG_GC(1, "ilookup() failed for ino #%u; inode is probably deleted.\n", inum); spin_lock(&c->inocache_lock); ic = jffs3_get_ino_cache(c, inum); if (!ic) { DBG_GC(1, "Inode cache for ino #%u is gone.\n", inum); spin_unlock(&c->inocache_lock); return NULL; } if (ic->state != INO_STATE_CHECKEDABSENT) { /* Wait for progress. Don't just loop */ DBG_GC(1, "Waiting for ino #%u in state %d\n", ic->ino, ic->state); sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); } else { spin_unlock(&c->inocache_lock); } return NULL; } } else { /* Inode has links to it still; they're not going away because jffs3_do_unlink() would need the alloc_sem and we have it. Just iget() it, and if read_inode() is necessary that's OK. */ inode = iget(OFNI_BS_2SFFJ(c), inum); if (!inode) return ERR_PTR(-ENOMEM); } if (is_bad_inode(inode)) { ERROR_MSG("Eep. read_inode() failed for ino #%u. nlink %d\n", inum, nlink); /* NB. This will happen again. We need to do something appropriate here. */ iput(inode); return ERR_PTR(-EIO); } return JFFS3_INODE_INFO(inode); } unsigned char *jffs3_gc_fetch_page(struct jffs3_sb_info *c, struct jffs3_inode_info *f, unsigned long offset, unsigned long *priv) { struct inode *inode = OFNI_EDONI_2SFFJ(f); struct page *pg; pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, (void *)jffs3_do_readpage_unlock, inode); if (IS_ERR(pg)) return (void *)pg; *priv = (unsigned long)pg; return kmap(pg); } void jffs3_gc_release_page(struct jffs3_sb_info *c, unsigned char *ptr, unsigned long *priv) { struct page *pg = (void *)*priv; kunmap(pg); page_cache_release(pg); } int jffs3_flash_setup(struct jffs3_sb_info *c) { int ret = 0; if (jffs3_cleanmarker_oob(c)) { /* NAND flash... do setup accordingly */ ret = jffs3_nand_flash_setup(c); if (ret) return ret; } /* add setups for other bizarre flashes here... */ if (jffs3_nor_ecc(c)) { ret = jffs3_nor_ecc_flash_setup(c); if (ret) return ret; } return ret; } void jffs3_flash_cleanup(struct jffs3_sb_info *c) { if (jffs3_cleanmarker_oob(c)) { jffs3_nand_flash_cleanup(c); } /* add cleanups for other bizarre flashes here... */ if (jffs3_nor_ecc(c)) { jffs3_nor_ecc_flash_cleanup(c); } }