c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
        c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
 
+       ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);
+
        c->calc_idx_sz = c->bi.old_idx_sz;
 
        if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
        c->mst_offs = offs;
        c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
 
+       ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
        err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
        if (err)
                return err;
 
  */
 static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
 {
-       return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt;
+       return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len + c->hash_len)
+                                  * child_cnt;
 }
 
 /**
                                      int bnum)
 {
        return (struct ubifs_branch *)((void *)idx->branches +
-                                      (UBIFS_BRANCH_SZ + c->key_len) * bnum);
+                       (UBIFS_BRANCH_SZ + c->key_len + c->hash_len) * bnum);
 }
 
 /**
 
        int lnum;
        int offs;
        int len;
+       u8 hash[UBIFS_HASH_ARR_SZ];
        unsigned int deletion:1;
        unsigned long long sqnum;
        struct list_head list;
                        err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
                else
                        err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
-                                              r->len, NULL, &r->nm);
+                                              r->len, r->hash, &r->nm);
        } else {
                if (r->deletion)
                        switch (key_type(c, &r->key)) {
                        }
                else
                        err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
-                                           r->len, NULL);
+                                           r->len, r->hash);
                if (err)
                        return err;
 
  * in case of success and a negative error code in case of failure.
  */
 static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
-                      union ubifs_key *key, unsigned long long sqnum,
-                      int deletion, int *used, loff_t old_size,
-                      loff_t new_size)
+                      const u8 *hash, union ubifs_key *key,
+                      unsigned long long sqnum, int deletion, int *used,
+                      loff_t old_size, loff_t new_size)
 {
        struct replay_entry *r;
 
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       ubifs_copy_hash(c, hash, r->hash);
        r->deletion = !!deletion;
        r->sqnum = sqnum;
        key_copy(c, key, &r->key);
  * negative error code in case of failure.
  */
 static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
-                      union ubifs_key *key, const char *name, int nlen,
-                      unsigned long long sqnum, int deletion, int *used)
+                      const u8 *hash, union ubifs_key *key,
+                      const char *name, int nlen, unsigned long long sqnum,
+                      int deletion, int *used)
 {
        struct replay_entry *r;
        char *nbuf;
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       ubifs_copy_hash(c, hash, r->hash);
        r->deletion = !!deletion;
        r->sqnum = sqnum;
        key_copy(c, key, &r->key);
         */
 
        list_for_each_entry(snod, &sleb->nodes, list) {
+               u8 hash[UBIFS_HASH_ARR_SZ];
                int deletion = 0;
 
                cond_resched();
                        goto out_dump;
                }
 
+               ubifs_node_calc_hash(c, snod->node, hash);
+
                if (snod->sqnum > c->max_sqnum)
                        c->max_sqnum = snod->sqnum;
 
 
                        if (le32_to_cpu(ino->nlink) == 0)
                                deletion = 1;
-                       err = insert_node(c, lnum, snod->offs, snod->len,
+                       err = insert_node(c, lnum, snod->offs, snod->len, hash,
                                          &snod->key, snod->sqnum, deletion,
                                          &used, 0, new_size);
                        break;
                                          key_block(c, &snod->key) *
                                          UBIFS_BLOCK_SIZE;
 
-                       err = insert_node(c, lnum, snod->offs, snod->len,
+                       err = insert_node(c, lnum, snod->offs, snod->len, hash,
                                          &snod->key, snod->sqnum, deletion,
                                          &used, 0, new_size);
                        break;
                        if (err)
                                goto out_dump;
 
-                       err = insert_dent(c, lnum, snod->offs, snod->len,
+                       err = insert_dent(c, lnum, snod->offs, snod->len, hash,
                                          &snod->key, dent->name,
                                          le16_to_cpu(dent->nlen), snod->sqnum,
                                          !le64_to_cpu(dent->inum), &used);
                         * functions which expect nodes to have keys.
                         */
                        trun_key_init(c, &key, le32_to_cpu(trun->inum));
-                       err = insert_node(c, lnum, snod->offs, snod->len,
+                       err = insert_node(c, lnum, snod->offs, snod->len, hash,
                                          &key, snod->sqnum, 1, &used,
                                          old_size, new_size);
                        break;
 
        if (crc != node_crc)
                return 0;
 
+       err = ubifs_node_check_hash(c, buf, zbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, buf, zbr->hash, lnum, offs);
+               return 0;
+       }
+
        return 1;
 }
 
                goto out;
        }
 
+       err = ubifs_node_check_hash(c, buf, zbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, buf, zbr->hash, zbr->lnum, zbr->offs);
+               return err;
+       }
+
        len = le32_to_cpu(ch->len);
        if (len != zbr->len) {
                ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
 
                         struct ubifs_znode *znode, int lnum, int offs, int len)
 {
        struct ubifs_znode *zp;
+       u8 hash[UBIFS_HASH_ARR_SZ];
        int i, err;
 
        /* Make index node */
                br->lnum = cpu_to_le32(zbr->lnum);
                br->offs = cpu_to_le32(zbr->offs);
                br->len = cpu_to_le32(zbr->len);
+               ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
                if (!zbr->lnum || !zbr->len) {
                        ubifs_err(c, "bad ref in znode");
                        ubifs_dump_znode(c, znode);
                }
        }
        ubifs_prepare_node(c, idx, len, 0);
+       ubifs_node_calc_hash(c, idx, hash);
 
        znode->lnum = lnum;
        znode->offs = offs;
                zbr->lnum = lnum;
                zbr->offs = offs;
                zbr->len = len;
+               ubifs_copy_hash(c, hash, zbr->hash);
        } else {
                c->zroot.lnum = lnum;
                c->zroot.offs = offs;
                c->zroot.len = len;
+               ubifs_copy_hash(c, hash, c->zroot.hash);
        }
        c->calc_idx_sz += ALIGN(len, 8);
 
                        znode->cnext = c->cnext;
                        break;
                }
+               znode->cparent = znode->parent;
+               znode->ciip = znode->iip;
                znode->cnext = cnext;
                znode = cnext;
                cnt += 1;
        }
 
        while (1) {
+               u8 hash[UBIFS_HASH_ARR_SZ];
+
                cond_resched();
 
                znode = cnext;
                        br->lnum = cpu_to_le32(zbr->lnum);
                        br->offs = cpu_to_le32(zbr->offs);
                        br->len = cpu_to_le32(zbr->len);
+                       ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
                        if (!zbr->lnum || !zbr->len) {
                                ubifs_err(c, "bad ref in znode");
                                ubifs_dump_znode(c, znode);
                }
                len = ubifs_idx_node_sz(c, znode->child_cnt);
                ubifs_prepare_node(c, idx, len, 0);
+               ubifs_node_calc_hash(c, idx, hash);
+
+               mutex_lock(&c->tnc_mutex);
+
+               if (znode->cparent)
+                       ubifs_copy_hash(c, hash,
+                                       znode->cparent->zbranch[znode->ciip].hash);
+
+               if (znode->parent) {
+                       if (!ubifs_zn_obsolete(znode))
+                               ubifs_copy_hash(c, hash,
+                                       znode->parent->zbranch[znode->iip].hash);
+               } else {
+                       ubifs_copy_hash(c, hash, c->zroot.hash);
+               }
+
+               mutex_unlock(&c->tnc_mutex);
 
                /* Determine the index node position */
                if (lnum == -1) {
 
                return err;
        }
 
+       err = ubifs_node_check_hash(c, idx, zzbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs);
+               return err;
+       }
+
        znode->child_cnt = le16_to_cpu(idx->child_cnt);
        znode->level = le16_to_cpu(idx->level);
 
        }
 
        for (i = 0; i < znode->child_cnt; i++) {
-               const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
+               struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
                struct ubifs_zbranch *zbr = &znode->zbranch[i];
 
                key_read(c, &br->key, &zbr->key);
                zbr->lnum = le32_to_cpu(br->lnum);
                zbr->offs = le32_to_cpu(br->offs);
                zbr->len  = le32_to_cpu(br->len);
+               ubifs_copy_hash(c, ubifs_branch_hash(c, br), zbr->hash);
                zbr->znode = NULL;
 
                /* Validate branch */
                return -EINVAL;
        }
 
+       err = ubifs_node_check_hash(c, node, zbr->hash);
+       if (err) {
+               ubifs_bad_hash(c, node, zbr->hash, zbr->lnum, zbr->offs);
+               return err;
+       }
+
        return 0;
 }
 
  * struct ubifs_znode - in-memory representation of an indexing node.
  * @parent: parent znode or NULL if it is the root
  * @cnext: next znode to commit
+ * @cparent: parent node for this commit
+ * @ciip: index in cparent's zbranch array
  * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
  * @time: last access time (seconds)
  * @level: level of the entry in the TNC tree
 struct ubifs_znode {
        struct ubifs_znode *parent;
        struct ubifs_znode *cnext;
+       struct ubifs_znode *cparent;
+       int ciip;
        unsigned long flags;
        time64_t time;
        int level;