+
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f)
+{
+ iput(OFNI_EDONI_2SFFJ(f));
+}
+
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+ int inum, int nlink)
+{
+ struct inode *inode;
+ struct jffs2_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 jffs2_do_unlink() would also
+ need that while decrementing nlink on any inode.
+ */
+ inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+ if (!inode) {
+ D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
+ inum));
+
+ spin_lock(&c->inocache_lock);
+ ic = jffs2_get_ino_cache(c, inum);
+ if (!ic) {
+ D1(printk(KERN_DEBUG "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 */
+ D1(printk(KERN_DEBUG "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
+ jffs2_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)) {
+ printk(KERN_NOTICE "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 JFFS2_INODE_INFO(inode);
+}
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+ struct jffs2_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 *)jffs2_do_readpage_unlock, inode);
+ if (IS_ERR(pg))
+ return (void *)pg;
+
+ *priv = (unsigned long)pg;
+ return kmap(pg);
+}
+
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+ unsigned char *ptr,
+ unsigned long *priv)
+{
+ struct page *pg = (void *)*priv;
+
+ kunmap(pg);
+ page_cache_release(pg);
+}
+
+static int jffs2_flash_setup(struct jffs2_sb_info *c) {
+ int ret = 0;
+
+ if (jffs2_cleanmarker_oob(c)) {
+ /* NAND flash... do setup accordingly */
+ ret = jffs2_nand_flash_setup(c);
+ if (ret)
+ return ret;
+ }
+
+ /* and Dataflash */
+ if (jffs2_dataflash(c)) {
+ ret = jffs2_dataflash_setup(c);
+ if (ret)
+ return ret;
+ }
+
+ /* and Intel "Sibley" flash */
+ if (jffs2_nor_wbuf_flash(c)) {
+ ret = jffs2_nor_wbuf_flash_setup(c);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
+
+ if (jffs2_cleanmarker_oob(c)) {
+ jffs2_nand_flash_cleanup(c);
+ }
+
+ /* and DataFlash */
+ if (jffs2_dataflash(c)) {
+ jffs2_dataflash_cleanup(c);
+ }
+
+ /* and Intel "Sibley" flash */
+ if (jffs2_nor_wbuf_flash(c)) {
+ jffs2_nor_wbuf_flash_cleanup(c);
+ }
+}