162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 562306a36Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/capability.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/cred.h> 1962306a36Sopenharmony_ci#include <linux/fs.h> 2062306a36Sopenharmony_ci#include <linux/fs_context.h> 2162306a36Sopenharmony_ci#include <linux/list.h> 2262306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 2362306a36Sopenharmony_ci#include <linux/pagemap.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/vmalloc.h> 2662306a36Sopenharmony_ci#include <linux/vfs.h> 2762306a36Sopenharmony_ci#include <linux/crc32.h> 2862306a36Sopenharmony_ci#include "nodelist.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int jffs2_flash_setup(struct jffs2_sb_info *c); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciint jffs2_do_setattr (struct inode *inode, struct iattr *iattr) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct jffs2_full_dnode *old_metadata, *new_metadata; 3562306a36Sopenharmony_ci struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 3662306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); 3762306a36Sopenharmony_ci struct jffs2_raw_inode *ri; 3862306a36Sopenharmony_ci union jffs2_device_node dev; 3962306a36Sopenharmony_ci unsigned char *mdata = NULL; 4062306a36Sopenharmony_ci int mdatalen = 0; 4162306a36Sopenharmony_ci unsigned int ivalid; 4262306a36Sopenharmony_ci uint32_t alloclen; 4362306a36Sopenharmony_ci int ret; 4462306a36Sopenharmony_ci int alloc_type = ALLOC_NORMAL; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Special cases - we don't want more than one data node 4962306a36Sopenharmony_ci for these types on the medium at any time. So setattr 5062306a36Sopenharmony_ci must read the original data associated with the node 5162306a36Sopenharmony_ci (i.e. the device numbers or the target name) and write 5262306a36Sopenharmony_ci it out again with the appropriate data attached */ 5362306a36Sopenharmony_ci if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { 5462306a36Sopenharmony_ci /* For these, we don't actually need to read the old node */ 5562306a36Sopenharmony_ci mdatalen = jffs2_encode_dev(&dev, inode->i_rdev); 5662306a36Sopenharmony_ci mdata = (char *)&dev; 5762306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", 5862306a36Sopenharmony_ci __func__, mdatalen); 5962306a36Sopenharmony_ci } else if (S_ISLNK(inode->i_mode)) { 6062306a36Sopenharmony_ci mutex_lock(&f->sem); 6162306a36Sopenharmony_ci mdatalen = f->metadata->size; 6262306a36Sopenharmony_ci mdata = kmalloc(f->metadata->size, GFP_USER); 6362306a36Sopenharmony_ci if (!mdata) { 6462306a36Sopenharmony_ci mutex_unlock(&f->sem); 6562306a36Sopenharmony_ci return -ENOMEM; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); 6862306a36Sopenharmony_ci if (ret) { 6962306a36Sopenharmony_ci mutex_unlock(&f->sem); 7062306a36Sopenharmony_ci kfree(mdata); 7162306a36Sopenharmony_ci return ret; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci mutex_unlock(&f->sem); 7462306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n", 7562306a36Sopenharmony_ci __func__, mdatalen); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ri = jffs2_alloc_raw_inode(); 7962306a36Sopenharmony_ci if (!ri) { 8062306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 8162306a36Sopenharmony_ci kfree(mdata); 8262306a36Sopenharmony_ci return -ENOMEM; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen, 8662306a36Sopenharmony_ci ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); 8762306a36Sopenharmony_ci if (ret) { 8862306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 8962306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 9062306a36Sopenharmony_ci kfree(mdata); 9162306a36Sopenharmony_ci return ret; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci mutex_lock(&f->sem); 9462306a36Sopenharmony_ci ivalid = iattr->ia_valid; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 9762306a36Sopenharmony_ci ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); 9862306a36Sopenharmony_ci ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); 9962306a36Sopenharmony_ci ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ri->ino = cpu_to_je32(inode->i_ino); 10262306a36Sopenharmony_ci ri->version = cpu_to_je32(++f->highest_version); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci ri->uid = cpu_to_je16((ivalid & ATTR_UID)? 10562306a36Sopenharmony_ci from_kuid(&init_user_ns, iattr->ia_uid):i_uid_read(inode)); 10662306a36Sopenharmony_ci ri->gid = cpu_to_je16((ivalid & ATTR_GID)? 10762306a36Sopenharmony_ci from_kgid(&init_user_ns, iattr->ia_gid):i_gid_read(inode)); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (ivalid & ATTR_MODE) 11062306a36Sopenharmony_ci ri->mode = cpu_to_jemode(iattr->ia_mode); 11162306a36Sopenharmony_ci else 11262306a36Sopenharmony_ci ri->mode = cpu_to_jemode(inode->i_mode); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); 11662306a36Sopenharmony_ci ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); 11762306a36Sopenharmony_ci ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); 11862306a36Sopenharmony_ci ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode_get_ctime(inode))); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci ri->offset = cpu_to_je32(0); 12162306a36Sopenharmony_ci ri->csize = ri->dsize = cpu_to_je32(mdatalen); 12262306a36Sopenharmony_ci ri->compr = JFFS2_COMPR_NONE; 12362306a36Sopenharmony_ci if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { 12462306a36Sopenharmony_ci /* It's an extension. Make it a hole node */ 12562306a36Sopenharmony_ci ri->compr = JFFS2_COMPR_ZERO; 12662306a36Sopenharmony_ci ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); 12762306a36Sopenharmony_ci ri->offset = cpu_to_je32(inode->i_size); 12862306a36Sopenharmony_ci } else if (ivalid & ATTR_SIZE && !iattr->ia_size) { 12962306a36Sopenharmony_ci /* For truncate-to-zero, treat it as deletion because 13062306a36Sopenharmony_ci it'll always be obsoleting all previous nodes */ 13162306a36Sopenharmony_ci alloc_type = ALLOC_DELETION; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 13462306a36Sopenharmony_ci if (mdatalen) 13562306a36Sopenharmony_ci ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); 13662306a36Sopenharmony_ci else 13762306a36Sopenharmony_ci ri->data_crc = cpu_to_je32(0); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); 14062306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 14162306a36Sopenharmony_ci kfree(mdata); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (IS_ERR(new_metadata)) { 14462306a36Sopenharmony_ci jffs2_complete_reservation(c); 14562306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 14662306a36Sopenharmony_ci mutex_unlock(&f->sem); 14762306a36Sopenharmony_ci return PTR_ERR(new_metadata); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci /* It worked. Update the inode */ 15062306a36Sopenharmony_ci inode->i_atime = ITIME(je32_to_cpu(ri->atime)); 15162306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, ITIME(je32_to_cpu(ri->ctime))); 15262306a36Sopenharmony_ci inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); 15362306a36Sopenharmony_ci inode->i_mode = jemode_to_cpu(ri->mode); 15462306a36Sopenharmony_ci i_uid_write(inode, je16_to_cpu(ri->uid)); 15562306a36Sopenharmony_ci i_gid_write(inode, je16_to_cpu(ri->gid)); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci old_metadata = f->metadata; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) 16162306a36Sopenharmony_ci jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { 16462306a36Sopenharmony_ci jffs2_add_full_dnode_to_inode(c, f, new_metadata); 16562306a36Sopenharmony_ci inode->i_size = iattr->ia_size; 16662306a36Sopenharmony_ci inode->i_blocks = (inode->i_size + 511) >> 9; 16762306a36Sopenharmony_ci f->metadata = NULL; 16862306a36Sopenharmony_ci } else { 16962306a36Sopenharmony_ci f->metadata = new_metadata; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci if (old_metadata) { 17262306a36Sopenharmony_ci jffs2_mark_node_obsolete(c, old_metadata->raw); 17362306a36Sopenharmony_ci jffs2_free_full_dnode(old_metadata); 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci jffs2_free_raw_inode(ri); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci mutex_unlock(&f->sem); 17862306a36Sopenharmony_ci jffs2_complete_reservation(c); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* We have to do the truncate_setsize() without f->sem held, since 18162306a36Sopenharmony_ci some pages may be locked and waiting for it in read_folio(). 18262306a36Sopenharmony_ci We are protected from a simultaneous write() extending i_size 18362306a36Sopenharmony_ci back past iattr->ia_size, because do_truncate() holds the 18462306a36Sopenharmony_ci generic inode semaphore. */ 18562306a36Sopenharmony_ci if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { 18662306a36Sopenharmony_ci truncate_setsize(inode, iattr->ia_size); 18762306a36Sopenharmony_ci inode->i_blocks = (inode->i_size + 511) >> 9; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ciint jffs2_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 19462306a36Sopenharmony_ci struct iattr *iattr) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 19762306a36Sopenharmony_ci int rc; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci rc = setattr_prepare(&nop_mnt_idmap, dentry, iattr); 20062306a36Sopenharmony_ci if (rc) 20162306a36Sopenharmony_ci return rc; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci rc = jffs2_do_setattr(inode, iattr); 20462306a36Sopenharmony_ci if (!rc && (iattr->ia_valid & ATTR_MODE)) 20562306a36Sopenharmony_ci rc = posix_acl_chmod(&nop_mnt_idmap, dentry, inode->i_mode); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return rc; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciint jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb); 21362306a36Sopenharmony_ci unsigned long avail; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci buf->f_type = JFFS2_SUPER_MAGIC; 21662306a36Sopenharmony_ci buf->f_bsize = 1 << PAGE_SHIFT; 21762306a36Sopenharmony_ci buf->f_blocks = c->flash_size >> PAGE_SHIFT; 21862306a36Sopenharmony_ci buf->f_files = 0; 21962306a36Sopenharmony_ci buf->f_ffree = 0; 22062306a36Sopenharmony_ci buf->f_namelen = JFFS2_MAX_NAME_LEN; 22162306a36Sopenharmony_ci buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC; 22262306a36Sopenharmony_ci buf->f_fsid.val[1] = c->mtd->index; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 22562306a36Sopenharmony_ci avail = c->dirty_size + c->free_size; 22662306a36Sopenharmony_ci if (avail > c->sector_size * c->resv_blocks_write) 22762306a36Sopenharmony_ci avail -= c->sector_size * c->resv_blocks_write; 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci avail = 0; 23062306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_civoid jffs2_evict_inode (struct inode *inode) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci /* We can forget about this inode for now - drop all 24162306a36Sopenharmony_ci * the nodelists associated with it, etc. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); 24462306a36Sopenharmony_ci struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci jffs2_dbg(1, "%s(): ino #%lu mode %o\n", 24762306a36Sopenharmony_ci __func__, inode->i_ino, inode->i_mode); 24862306a36Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 24962306a36Sopenharmony_ci clear_inode(inode); 25062306a36Sopenharmony_ci jffs2_do_clear_inode(c, f); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistruct inode *jffs2_iget(struct super_block *sb, unsigned long ino) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct jffs2_inode_info *f; 25662306a36Sopenharmony_ci struct jffs2_sb_info *c; 25762306a36Sopenharmony_ci struct jffs2_raw_inode latest_node; 25862306a36Sopenharmony_ci union jffs2_device_node jdev; 25962306a36Sopenharmony_ci struct inode *inode; 26062306a36Sopenharmony_ci dev_t rdev = 0; 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci jffs2_dbg(1, "%s(): ino == %lu\n", __func__, ino); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci inode = iget_locked(sb, ino); 26662306a36Sopenharmony_ci if (!inode) 26762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 26862306a36Sopenharmony_ci if (!(inode->i_state & I_NEW)) 26962306a36Sopenharmony_ci return inode; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci f = JFFS2_INODE_INFO(inode); 27262306a36Sopenharmony_ci c = JFFS2_SB_INFO(inode->i_sb); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci jffs2_init_inode_info(f); 27562306a36Sopenharmony_ci mutex_lock(&f->sem); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); 27862306a36Sopenharmony_ci if (ret) 27962306a36Sopenharmony_ci goto error; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci inode->i_mode = jemode_to_cpu(latest_node.mode); 28262306a36Sopenharmony_ci i_uid_write(inode, je16_to_cpu(latest_node.uid)); 28362306a36Sopenharmony_ci i_gid_write(inode, je16_to_cpu(latest_node.gid)); 28462306a36Sopenharmony_ci inode->i_size = je32_to_cpu(latest_node.isize); 28562306a36Sopenharmony_ci inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); 28662306a36Sopenharmony_ci inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); 28762306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, ITIME(je32_to_cpu(latest_node.ctime))); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci set_nlink(inode, f->inocache->pino_nlink); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci inode->i_blocks = (inode->i_size + 511) >> 9; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci case S_IFLNK: 29662306a36Sopenharmony_ci inode->i_op = &jffs2_symlink_inode_operations; 29762306a36Sopenharmony_ci inode->i_link = f->target; 29862306a36Sopenharmony_ci break; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci case S_IFDIR: 30162306a36Sopenharmony_ci { 30262306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 30362306a36Sopenharmony_ci set_nlink(inode, 2); /* parent and '.' */ 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci for (fd=f->dents; fd; fd = fd->next) { 30662306a36Sopenharmony_ci if (fd->type == DT_DIR && fd->ino) 30762306a36Sopenharmony_ci inc_nlink(inode); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci /* Root dir gets i_nlink 3 for some reason */ 31062306a36Sopenharmony_ci if (inode->i_ino == 1) 31162306a36Sopenharmony_ci inc_nlink(inode); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci inode->i_op = &jffs2_dir_inode_operations; 31462306a36Sopenharmony_ci inode->i_fop = &jffs2_dir_operations; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci case S_IFREG: 31862306a36Sopenharmony_ci inode->i_op = &jffs2_file_inode_operations; 31962306a36Sopenharmony_ci inode->i_fop = &jffs2_file_operations; 32062306a36Sopenharmony_ci inode->i_mapping->a_ops = &jffs2_file_address_operations; 32162306a36Sopenharmony_ci inode->i_mapping->nrpages = 0; 32262306a36Sopenharmony_ci break; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci case S_IFBLK: 32562306a36Sopenharmony_ci case S_IFCHR: 32662306a36Sopenharmony_ci /* Read the device numbers from the media */ 32762306a36Sopenharmony_ci if (f->metadata->size != sizeof(jdev.old_id) && 32862306a36Sopenharmony_ci f->metadata->size != sizeof(jdev.new_id)) { 32962306a36Sopenharmony_ci pr_notice("Device node has strange size %d\n", 33062306a36Sopenharmony_ci f->metadata->size); 33162306a36Sopenharmony_ci goto error_io; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci jffs2_dbg(1, "Reading device numbers from flash\n"); 33462306a36Sopenharmony_ci ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size); 33562306a36Sopenharmony_ci if (ret < 0) { 33662306a36Sopenharmony_ci /* Eep */ 33762306a36Sopenharmony_ci pr_notice("Read device numbers for inode %lu failed\n", 33862306a36Sopenharmony_ci (unsigned long)inode->i_ino); 33962306a36Sopenharmony_ci goto error; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci if (f->metadata->size == sizeof(jdev.old_id)) 34262306a36Sopenharmony_ci rdev = old_decode_dev(je16_to_cpu(jdev.old_id)); 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci rdev = new_decode_dev(je32_to_cpu(jdev.new_id)); 34562306a36Sopenharmony_ci fallthrough; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci case S_IFSOCK: 34862306a36Sopenharmony_ci case S_IFIFO: 34962306a36Sopenharmony_ci inode->i_op = &jffs2_file_inode_operations; 35062306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, rdev); 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci default: 35462306a36Sopenharmony_ci pr_warn("%s(): Bogus i_mode %o for ino %lu\n", 35562306a36Sopenharmony_ci __func__, inode->i_mode, (unsigned long)inode->i_ino); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci mutex_unlock(&f->sem); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci jffs2_dbg(1, "jffs2_read_inode() returning\n"); 36162306a36Sopenharmony_ci unlock_new_inode(inode); 36262306a36Sopenharmony_ci return inode; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cierror_io: 36562306a36Sopenharmony_ci ret = -EIO; 36662306a36Sopenharmony_cierror: 36762306a36Sopenharmony_ci mutex_unlock(&f->sem); 36862306a36Sopenharmony_ci iget_failed(inode); 36962306a36Sopenharmony_ci return ERR_PTR(ret); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_civoid jffs2_dirty_inode(struct inode *inode, int flags) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct iattr iattr; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!(inode->i_state & I_DIRTY_DATASYNC)) { 37762306a36Sopenharmony_ci jffs2_dbg(2, "%s(): not calling setattr() for ino #%lu\n", 37862306a36Sopenharmony_ci __func__, inode->i_ino); 37962306a36Sopenharmony_ci return; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci jffs2_dbg(1, "%s(): calling setattr() for ino #%lu\n", 38362306a36Sopenharmony_ci __func__, inode->i_ino); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME; 38662306a36Sopenharmony_ci iattr.ia_mode = inode->i_mode; 38762306a36Sopenharmony_ci iattr.ia_uid = inode->i_uid; 38862306a36Sopenharmony_ci iattr.ia_gid = inode->i_gid; 38962306a36Sopenharmony_ci iattr.ia_atime = inode->i_atime; 39062306a36Sopenharmony_ci iattr.ia_mtime = inode->i_mtime; 39162306a36Sopenharmony_ci iattr.ia_ctime = inode_get_ctime(inode); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci jffs2_do_setattr(inode, &iattr); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciint jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (c->flags & JFFS2_SB_FLAG_RO && !sb_rdonly(sb)) 40162306a36Sopenharmony_ci return -EROFS; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* We stop if it was running, then restart if it needs to. 40462306a36Sopenharmony_ci This also catches the case where it was stopped and this 40562306a36Sopenharmony_ci is just a remount to restart it. 40662306a36Sopenharmony_ci Flush the writebuffer, if necessary, else we loose it */ 40762306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 40862306a36Sopenharmony_ci jffs2_stop_garbage_collect_thread(c); 40962306a36Sopenharmony_ci mutex_lock(&c->alloc_sem); 41062306a36Sopenharmony_ci jffs2_flush_wbuf_pad(c); 41162306a36Sopenharmony_ci mutex_unlock(&c->alloc_sem); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!(fc->sb_flags & SB_RDONLY)) 41562306a36Sopenharmony_ci jffs2_start_garbage_collect_thread(c); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci fc->sb_flags |= SB_NOATIME; 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, 42262306a36Sopenharmony_ci fill in the raw_inode while you're at it. */ 42362306a36Sopenharmony_cistruct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_raw_inode *ri) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct inode *inode; 42662306a36Sopenharmony_ci struct super_block *sb = dir_i->i_sb; 42762306a36Sopenharmony_ci struct jffs2_sb_info *c; 42862306a36Sopenharmony_ci struct jffs2_inode_info *f; 42962306a36Sopenharmony_ci int ret; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci jffs2_dbg(1, "%s(): dir_i %ld, mode 0x%x\n", 43262306a36Sopenharmony_ci __func__, dir_i->i_ino, mode); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci c = JFFS2_SB_INFO(sb); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci inode = new_inode(sb); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (!inode) 43962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci f = JFFS2_INODE_INFO(inode); 44262306a36Sopenharmony_ci jffs2_init_inode_info(f); 44362306a36Sopenharmony_ci mutex_lock(&f->sem); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci memset(ri, 0, sizeof(*ri)); 44662306a36Sopenharmony_ci /* Set OS-specific defaults for new inodes */ 44762306a36Sopenharmony_ci ri->uid = cpu_to_je16(from_kuid(&init_user_ns, current_fsuid())); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (dir_i->i_mode & S_ISGID) { 45062306a36Sopenharmony_ci ri->gid = cpu_to_je16(i_gid_read(dir_i)); 45162306a36Sopenharmony_ci if (S_ISDIR(mode)) 45262306a36Sopenharmony_ci mode |= S_ISGID; 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci ri->gid = cpu_to_je16(from_kgid(&init_user_ns, current_fsgid())); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* POSIX ACLs have to be processed now, at least partly. 45862306a36Sopenharmony_ci The umask is only applied if there's no default ACL */ 45962306a36Sopenharmony_ci ret = jffs2_init_acl_pre(dir_i, inode, &mode); 46062306a36Sopenharmony_ci if (ret) { 46162306a36Sopenharmony_ci mutex_unlock(&f->sem); 46262306a36Sopenharmony_ci make_bad_inode(inode); 46362306a36Sopenharmony_ci iput(inode); 46462306a36Sopenharmony_ci return ERR_PTR(ret); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci ret = jffs2_do_new_inode (c, f, mode, ri); 46762306a36Sopenharmony_ci if (ret) { 46862306a36Sopenharmony_ci mutex_unlock(&f->sem); 46962306a36Sopenharmony_ci make_bad_inode(inode); 47062306a36Sopenharmony_ci iput(inode); 47162306a36Sopenharmony_ci return ERR_PTR(ret); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci set_nlink(inode, 1); 47462306a36Sopenharmony_ci inode->i_ino = je32_to_cpu(ri->ino); 47562306a36Sopenharmony_ci inode->i_mode = jemode_to_cpu(ri->mode); 47662306a36Sopenharmony_ci i_gid_write(inode, je16_to_cpu(ri->gid)); 47762306a36Sopenharmony_ci i_uid_write(inode, je16_to_cpu(ri->uid)); 47862306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 47962306a36Sopenharmony_ci ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci inode->i_blocks = 0; 48262306a36Sopenharmony_ci inode->i_size = 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (insert_inode_locked(inode) < 0) { 48562306a36Sopenharmony_ci mutex_unlock(&f->sem); 48662306a36Sopenharmony_ci make_bad_inode(inode); 48762306a36Sopenharmony_ci iput(inode); 48862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return inode; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int calculate_inocache_hashsize(uint32_t flash_size) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci /* 49762306a36Sopenharmony_ci * Pick a inocache hash size based on the size of the medium. 49862306a36Sopenharmony_ci * Count how many megabytes we're dealing with, apply a hashsize twice 49962306a36Sopenharmony_ci * that size, but rounding down to the usual big powers of 2. And keep 50062306a36Sopenharmony_ci * to sensible bounds. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci int size_mb = flash_size / 1024 / 1024; 50462306a36Sopenharmony_ci int hashsize = (size_mb * 2) & ~0x3f; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (hashsize < INOCACHE_HASHSIZE_MIN) 50762306a36Sopenharmony_ci return INOCACHE_HASHSIZE_MIN; 50862306a36Sopenharmony_ci if (hashsize > INOCACHE_HASHSIZE_MAX) 50962306a36Sopenharmony_ci return INOCACHE_HASHSIZE_MAX; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return hashsize; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ciint jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct jffs2_sb_info *c; 51762306a36Sopenharmony_ci struct inode *root_i; 51862306a36Sopenharmony_ci int ret; 51962306a36Sopenharmony_ci size_t blocks; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci c = JFFS2_SB_INFO(sb); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Do not support the MLC nand */ 52462306a36Sopenharmony_ci if (c->mtd->type == MTD_MLCNANDFLASH) 52562306a36Sopenharmony_ci return -EINVAL; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci#ifndef CONFIG_JFFS2_FS_WRITEBUFFER 52862306a36Sopenharmony_ci if (c->mtd->type == MTD_NANDFLASH) { 52962306a36Sopenharmony_ci errorf(fc, "Cannot operate on NAND flash unless jffs2 NAND support is compiled in"); 53062306a36Sopenharmony_ci return -EINVAL; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci if (c->mtd->type == MTD_DATAFLASH) { 53362306a36Sopenharmony_ci errorf(fc, "Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in"); 53462306a36Sopenharmony_ci return -EINVAL; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci#endif 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci c->flash_size = c->mtd->size; 53962306a36Sopenharmony_ci c->sector_size = c->mtd->erasesize; 54062306a36Sopenharmony_ci blocks = c->flash_size / c->sector_size; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * Size alignment check 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci if ((c->sector_size * blocks) != c->flash_size) { 54662306a36Sopenharmony_ci c->flash_size = c->sector_size * blocks; 54762306a36Sopenharmony_ci infof(fc, "Flash size not aligned to erasesize, reducing to %dKiB", 54862306a36Sopenharmony_ci c->flash_size / 1024); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (c->flash_size < 5*c->sector_size) { 55262306a36Sopenharmony_ci errorf(fc, "Too few erase blocks (%d)", 55362306a36Sopenharmony_ci c->flash_size / c->sector_size); 55462306a36Sopenharmony_ci return -EINVAL; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci c->cleanmarker_size = sizeof(struct jffs2_unknown_node); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* NAND (or other bizarre) flash... do setup accordingly */ 56062306a36Sopenharmony_ci ret = jffs2_flash_setup(c); 56162306a36Sopenharmony_ci if (ret) 56262306a36Sopenharmony_ci return ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); 56562306a36Sopenharmony_ci c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); 56662306a36Sopenharmony_ci if (!c->inocache_list) { 56762306a36Sopenharmony_ci ret = -ENOMEM; 56862306a36Sopenharmony_ci goto out_wbuf; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci jffs2_init_xattr_subsystem(c); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if ((ret = jffs2_do_mount_fs(c))) 57462306a36Sopenharmony_ci goto out_inohash; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci jffs2_dbg(1, "%s(): Getting root inode\n", __func__); 57762306a36Sopenharmony_ci root_i = jffs2_iget(sb, 1); 57862306a36Sopenharmony_ci if (IS_ERR(root_i)) { 57962306a36Sopenharmony_ci jffs2_dbg(1, "get root inode failed\n"); 58062306a36Sopenharmony_ci ret = PTR_ERR(root_i); 58162306a36Sopenharmony_ci goto out_root; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ret = -ENOMEM; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci jffs2_dbg(1, "%s(): d_make_root()\n", __func__); 58762306a36Sopenharmony_ci sb->s_root = d_make_root(root_i); 58862306a36Sopenharmony_ci if (!sb->s_root) 58962306a36Sopenharmony_ci goto out_root; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci sb->s_maxbytes = 0xFFFFFFFF; 59262306a36Sopenharmony_ci sb->s_blocksize = PAGE_SIZE; 59362306a36Sopenharmony_ci sb->s_blocksize_bits = PAGE_SHIFT; 59462306a36Sopenharmony_ci sb->s_magic = JFFS2_SUPER_MAGIC; 59562306a36Sopenharmony_ci sb->s_time_min = 0; 59662306a36Sopenharmony_ci sb->s_time_max = U32_MAX; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (!sb_rdonly(sb)) 59962306a36Sopenharmony_ci jffs2_start_garbage_collect_thread(c); 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ciout_root: 60362306a36Sopenharmony_ci jffs2_free_ino_caches(c); 60462306a36Sopenharmony_ci jffs2_free_raw_node_refs(c); 60562306a36Sopenharmony_ci kvfree(c->blocks); 60662306a36Sopenharmony_ci jffs2_clear_xattr_subsystem(c); 60762306a36Sopenharmony_ci jffs2_sum_exit(c); 60862306a36Sopenharmony_ci out_inohash: 60962306a36Sopenharmony_ci kfree(c->inocache_list); 61062306a36Sopenharmony_ci out_wbuf: 61162306a36Sopenharmony_ci jffs2_flash_cleanup(c); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci return ret; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_civoid jffs2_gc_release_inode(struct jffs2_sb_info *c, 61762306a36Sopenharmony_ci struct jffs2_inode_info *f) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci iput(OFNI_EDONI_2SFFJ(f)); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistruct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, 62362306a36Sopenharmony_ci int inum, int unlinked) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct inode *inode; 62662306a36Sopenharmony_ci struct jffs2_inode_cache *ic; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (unlinked) { 62962306a36Sopenharmony_ci /* The inode has zero nlink but its nodes weren't yet marked 63062306a36Sopenharmony_ci obsolete. This has to be because we're still waiting for 63162306a36Sopenharmony_ci the final (close() and) iput() to happen. 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci There's a possibility that the final iput() could have 63462306a36Sopenharmony_ci happened while we were contemplating. In order to ensure 63562306a36Sopenharmony_ci that we don't cause a new read_inode() (which would fail) 63662306a36Sopenharmony_ci for the inode in question, we use ilookup() in this case 63762306a36Sopenharmony_ci instead of iget(). 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci The nlink can't _become_ zero at this point because we're 64062306a36Sopenharmony_ci holding the alloc_sem, and jffs2_do_unlink() would also 64162306a36Sopenharmony_ci need that while decrementing nlink on any inode. 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci inode = ilookup(OFNI_BS_2SFFJ(c), inum); 64462306a36Sopenharmony_ci if (!inode) { 64562306a36Sopenharmony_ci jffs2_dbg(1, "ilookup() failed for ino #%u; inode is probably deleted.\n", 64662306a36Sopenharmony_ci inum); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci spin_lock(&c->inocache_lock); 64962306a36Sopenharmony_ci ic = jffs2_get_ino_cache(c, inum); 65062306a36Sopenharmony_ci if (!ic) { 65162306a36Sopenharmony_ci jffs2_dbg(1, "Inode cache for ino #%u is gone\n", 65262306a36Sopenharmony_ci inum); 65362306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 65462306a36Sopenharmony_ci return NULL; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci if (ic->state != INO_STATE_CHECKEDABSENT) { 65762306a36Sopenharmony_ci /* Wait for progress. Don't just loop */ 65862306a36Sopenharmony_ci jffs2_dbg(1, "Waiting for ino #%u in state %d\n", 65962306a36Sopenharmony_ci ic->ino, ic->state); 66062306a36Sopenharmony_ci sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); 66162306a36Sopenharmony_ci } else { 66262306a36Sopenharmony_ci spin_unlock(&c->inocache_lock); 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci return NULL; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci } else { 66862306a36Sopenharmony_ci /* Inode has links to it still; they're not going away because 66962306a36Sopenharmony_ci jffs2_do_unlink() would need the alloc_sem and we have it. 67062306a36Sopenharmony_ci Just iget() it, and if read_inode() is necessary that's OK. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum); 67362306a36Sopenharmony_ci if (IS_ERR(inode)) 67462306a36Sopenharmony_ci return ERR_CAST(inode); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci if (is_bad_inode(inode)) { 67762306a36Sopenharmony_ci pr_notice("Eep. read_inode() failed for ino #%u. unlinked %d\n", 67862306a36Sopenharmony_ci inum, unlinked); 67962306a36Sopenharmony_ci /* NB. This will happen again. We need to do something appropriate here. */ 68062306a36Sopenharmony_ci iput(inode); 68162306a36Sopenharmony_ci return ERR_PTR(-EIO); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return JFFS2_INODE_INFO(inode); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int jffs2_flash_setup(struct jffs2_sb_info *c) { 68862306a36Sopenharmony_ci int ret = 0; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (jffs2_cleanmarker_oob(c)) { 69162306a36Sopenharmony_ci /* NAND flash... do setup accordingly */ 69262306a36Sopenharmony_ci ret = jffs2_nand_flash_setup(c); 69362306a36Sopenharmony_ci if (ret) 69462306a36Sopenharmony_ci return ret; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* and Dataflash */ 69862306a36Sopenharmony_ci if (jffs2_dataflash(c)) { 69962306a36Sopenharmony_ci ret = jffs2_dataflash_setup(c); 70062306a36Sopenharmony_ci if (ret) 70162306a36Sopenharmony_ci return ret; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* and Intel "Sibley" flash */ 70562306a36Sopenharmony_ci if (jffs2_nor_wbuf_flash(c)) { 70662306a36Sopenharmony_ci ret = jffs2_nor_wbuf_flash_setup(c); 70762306a36Sopenharmony_ci if (ret) 70862306a36Sopenharmony_ci return ret; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* and an UBI volume */ 71262306a36Sopenharmony_ci if (jffs2_ubivol(c)) { 71362306a36Sopenharmony_ci ret = jffs2_ubivol_setup(c); 71462306a36Sopenharmony_ci if (ret) 71562306a36Sopenharmony_ci return ret; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return ret; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_civoid jffs2_flash_cleanup(struct jffs2_sb_info *c) { 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (jffs2_cleanmarker_oob(c)) { 72462306a36Sopenharmony_ci jffs2_nand_flash_cleanup(c); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* and DataFlash */ 72862306a36Sopenharmony_ci if (jffs2_dataflash(c)) { 72962306a36Sopenharmony_ci jffs2_dataflash_cleanup(c); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* and Intel "Sibley" flash */ 73362306a36Sopenharmony_ci if (jffs2_nor_wbuf_flash(c)) { 73462306a36Sopenharmony_ci jffs2_nor_wbuf_flash_cleanup(c); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* and an UBI volume */ 73862306a36Sopenharmony_ci if (jffs2_ubivol(c)) { 73962306a36Sopenharmony_ci jffs2_ubivol_cleanup(c); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci} 742