To support NFS export, we need to know the parent inode of directories.
Rather than growing the jffs2_inode_cache structure, share space with
the nlink field -- which was always set to 1 for directories anyway.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
 
 
 static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
-                                       struct jffs2_inode_cache *ic)
+                                   struct jffs2_inode_cache *ic)
 {
        struct jffs2_full_dirent *fd;
 
                        continue;
                }
 
-               if (child_ic->nlink++ && fd->type == DT_DIR) {
-                       JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
-                               fd->name, fd->ino, ic->ino);
-                       /* TODO: What do we do about it? */
-               }
+               if (fd->type == DT_DIR) {
+                       if (child_ic->pino_nlink) {
+                               JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
+                                           fd->name, fd->ino, ic->ino);
+                               /* TODO: What do we do about it? */
+                       } else {
+                               child_ic->pino_nlink = ic->ino;
+                       }
+               } else
+                       child_ic->pino_nlink++;
+
                dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
                /* Can't free scan_dents so far. We might need them in pass 2 */
        }
        dbg_fsbuild("pass 2 starting\n");
 
        for_each_inode(i, c, ic) {
-               if (ic->nlink)
+               if (ic->pino_nlink)
                        continue;
 
                jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
                        /* Reduce nlink of the child. If it's now zero, stick it on the
                           dead_fds list to be cleaned up later. Else just free the fd */
 
-                       child_ic->nlink--;
+                       if (fd->type == DT_DIR)
+                               child_ic->pino_nlink = 0;
+                       else
+                               child_ic->pino_nlink--;
 
-                       if (!child_ic->nlink) {
-                               dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n",
+                       if (!child_ic->pino_nlink) {
+                               dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
                                          fd->ino, fd->name);
                                fd->next = *dead_fds;
                                *dead_fds = fd;
                        } else {
                                dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
-                                         fd->ino, fd->name, child_ic->nlink);
+                                         fd->ino, fd->name, child_ic->pino_nlink);
                                jffs2_free_full_dirent(fd);
                        }
                }
 
        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));
+                 inode->i_ino, inode->i_mode, inode->i_nlink,
+                 f->inocache->pino_nlink, inode->i_mapping->nrpages));
        return 0;
 
  fail:
        ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
                              dentry->d_name.len, dead_f, now);
        if (dead_f->inocache)
-               dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+               dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
        if (!ret)
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
        return ret;
 
        if (!ret) {
                mutex_lock(&f->sem);
-               old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
+               old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
                mutex_unlock(&f->sem);
                d_instantiate(dentry, old_dentry->d_inode);
                dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
 
        inode->i_op = &jffs2_dir_inode_operations;
        inode->i_fop = &jffs2_dir_operations;
-       /* Directories get nlink 2 at start */
-       inode->i_nlink = 2;
 
        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));
 
 
 static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
 {
+       struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
+       struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
        struct jffs2_full_dirent *fd;
        int ret;
+       uint32_t now = get_seconds();
 
        for (fd = f->dents ; fd; fd = fd->next) {
                if (fd->ino)
                        return -ENOTEMPTY;
        }
-       ret = jffs2_unlink(dir_i, dentry);
-       if (!ret)
+
+       ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
+                             dentry->d_name.len, f, now);
+       if (!ret) {
+               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+               clear_nlink(dentry->d_inode);
                drop_nlink(dir_i);
+       }
        return ret;
 }
 
                   inode which didn't exist. */
                if (victim_f->inocache) {
                        mutex_lock(&victim_f->sem);
-                       victim_f->inocache->nlink--;
+                       if (S_ISDIR(new_dentry->d_inode->i_mode))
+                               victim_f->inocache->pino_nlink = 0;
+                       else
+                               victim_f->inocache->pino_nlink--;
                        mutex_unlock(&victim_f->sem);
                }
        }
                struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
                mutex_lock(&f->sem);
                inc_nlink(old_dentry->d_inode);
-               if (f->inocache)
-                       f->inocache->nlink++;
+               if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
+                       f->inocache->pino_nlink++;
                mutex_unlock(&f->sem);
 
                printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
 
                        break;
 #endif
                default:
-                       if (ic->nodes == (void *)ic && ic->nlink == 0)
+                       if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
                                jffs2_del_ino_cache(c, ic);
        }
 }
 
        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_nlink = f->inocache->pino_nlink;
 
        inode->i_blocks = (inode->i_size + 511) >> 9;
 
        case S_IFDIR:
        {
                struct jffs2_full_dirent *fd;
+               inode->i_nlink = 2; /* parent and '.' */
 
                for (fd=f->dents; fd; fd = fd->next) {
                        if (fd->type == DT_DIR && fd->ino)
                                inc_nlink(inode);
                }
-               /* and '..' */
-               inc_nlink(inode);
                /* Root dir gets i_nlink 3 for some reason */
                if (inode->i_ino == 1)
                        inc_nlink(inode);
 
                        continue;
                }
 
-               if (!ic->nlink) {
-                       D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
+               if (!ic->pino_nlink) {
+                       D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n",
                                  ic->ino));
                        spin_unlock(&c->inocache_lock);
                        jffs2_xattr_delete_inode(c, ic);
           it's vaguely possible. */
 
        inum = ic->ino;
-       nlink = ic->nlink;
+       nlink = ic->pino_nlink;
        spin_unlock(&c->inocache_lock);
 
        f = jffs2_gc_fetch_inode(c, inum, !nlink);
 
 #ifdef CONFIG_JFFS2_FS_XATTR
        struct jffs2_xattr_ref *xref;
 #endif
-       int nlink;
+       uint32_t pino_nlink;    /* Directories store parent inode
+                                  here; other inodes store nlink.
+                                  Zero always means that it's
+                                  completely unlinked. */
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
 
                                break;
 #endif
                        default:
-                               if (ic->nodes == (void *)ic && ic->nlink == 0)
+                               if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
                                        jffs2_del_ino_cache(c, ic);
                                break;
                }
 
        size_t retlen;
        int ret;
 
-       dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);
+       dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
+                     f->inocache->pino_nlink);
 
        memset(&rii, 0, sizeof(rii));
 
                }
                dbg_readinode("creating inocache for root inode\n");
                memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
-               f->inocache->ino = f->inocache->nlink = 1;
+               f->inocache->ino = f->inocache->pino_nlink = 1;
                f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
                f->inocache->state = INO_STATE_READING;
                jffs2_add_ino_cache(c, f->inocache);
        jffs2_clear_acl(f);
        jffs2_xattr_delete_inode(c, f->inocache);
        mutex_lock(&f->sem);
-       deleted = f->inocache && !f->inocache->nlink;
+       deleted = f->inocache && !f->inocache->pino_nlink;
 
        if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
                jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
 
        ic->nodes = (void *)ic;
        jffs2_add_ino_cache(c, ic);
        if (ino == 1)
-               ic->nlink = 1;
+               ic->pino_nlink = 1;
        return ic;
 }
 
 
                                /* If it's an in-core inode, then we have to adjust any
                                   full_dirent or full_dnode structure to point to the
                                   new version instead of the old */
-                               f = jffs2_gc_fetch_inode(c, ic->ino, !ic->nlink);
+                               f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
                                if (IS_ERR(f)) {
                                        /* Should never happen; it _must_ be present */
                                        JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
 
 #include "compr.h"
 
 
-int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                      uint32_t mode, struct jffs2_raw_inode *ri)
 {
        struct jffs2_inode_cache *ic;
 
        memset(ic, 0, sizeof(*ic));
 
        f->inocache = ic;
-       f->inocache->nlink = 1;
+       f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */
        f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
        f->inocache->state = INO_STATE_PRESENT;
 
                                        jffs2_mark_node_obsolete(c, fd->raw);
                                jffs2_free_full_dirent(fd);
                        }
-               }
-
-               dead_f->inocache->nlink--;
+                       dead_f->inocache->pino_nlink = 0;
+               } else
+                       dead_f->inocache->pino_nlink--;
                /* NB: Caller must set inode nlink if appropriate */
                mutex_unlock(&dead_f->sem);
        }
 
           When an inode with XATTR is removed, those XATTRs must be removed. */
        struct jffs2_xattr_ref *ref, *_ref;
 
-       if (!ic || ic->nlink > 0)
+       if (!ic || ic->pino_nlink > 0)
                return;
 
        down_write(&c->xattr_sem);
                           ref->xd and ref->ic are not valid yet. */
                        xd = jffs2_find_xattr_datum(c, ref->xid);
                        ic = jffs2_get_ino_cache(c, ref->ino);
-                       if (!xd || !ic || !ic->nlink) {
+                       if (!xd || !ic || !ic->pino_nlink) {
                                dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
                                          ref->ino, ref->xid, ref->xseqno);
                                ref->xseqno |= XREF_DELETE_MARKER;