/** * ubifs_search_zbranch - search znode branch. * @c: UBIFS file-system description object * @znode: znode to search in * @key: key to search for * @n: znode branch slot number is returned here * * This is a helper function which search branch with key @key in @znode using * binary search. The result of the search may be: * o exact match, then %1 is returned, and the slot number of the branch is * stored in @n; * o no exact match, then %0 is returned and the slot number of the left * closest branch is returned in @n; the slot if all keys in this znode are * greater than @key, then %-1 is returned in @n. */ int ubifs_search_zbranch(const struct ubifs_info *c, const struct ubifs_znode *znode, const union ubifs_key *key, int *n) { int beg = 0, end = znode->child_cnt, uninitialized_var(mid); int uninitialized_var(cmp); const struct ubifs_zbranch *zbr = &znode->zbranch[0]; ubifs_assert(end > beg); while (end > beg) { mid = (beg + end) >> 1; cmp = keys_cmp(c, key, &zbr[mid].key); if (cmp > 0) beg = mid + 1; else if (cmp < 0) end = mid; else { *n = mid; return 1; } } *n = end - 1; /* The insert point is after *n */ ubifs_assert(*n >= -1 && *n < znode->child_cnt); if (*n == -1) ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0); else ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0); if (*n + 1 < znode->child_cnt) ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0); return 0; }
/** * dbg_check_old_index - check the old copy of the index. * @c: UBIFS file-system description object * @zroot: root of the new index * * In order to be able to recover from an unclean unmount, a complete copy of * the index must exist on flash. This is the "old" index. The commit process * must write the "new" index to flash without overwriting or destroying any * part of the old index. This function is run at commit end in order to check * that the old index does indeed exist completely intact. * * This function returns %0 on success and a negative error code on failure. */ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot) { int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt; int first = 1, iip; struct ubifs_debug_info *d = c->dbg; union ubifs_key lower_key, upper_key, l_key, u_key; unsigned long long uninitialized_var(last_sqnum); struct ubifs_idx_node *idx; struct list_head list; struct idx_node *i; size_t sz; if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX)) goto out; INIT_LIST_HEAD(&list); sz = sizeof(struct idx_node) + ubifs_idx_node_sz(c, c->fanout) - UBIFS_IDX_NODE_SZ; /* Start at the old zroot */ lnum = d->old_zroot.lnum; offs = d->old_zroot.offs; len = d->old_zroot.len; iip = 0; /* * Traverse the index tree preorder depth-first i.e. do a node and then * its subtrees from left to right. */ while (1) { struct ubifs_branch *br; /* Get the next index node */ i = kmalloc(sz, GFP_NOFS); if (!i) { err = -ENOMEM; goto out_free; } i->iip = iip; /* Keep the index nodes on our path in a linked list */ list_add_tail(&i->list, &list); /* Read the index node */ idx = &i->idx; err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); if (err) goto out_free; /* Validate index node */ child_cnt = le16_to_cpu(idx->child_cnt); if (child_cnt < 1 || child_cnt > c->fanout) { err = 1; goto out_dump; } if (first) { first = 0; /* Check root level and sqnum */ if (le16_to_cpu(idx->level) != d->old_zroot_level) { err = 2; goto out_dump; } if (le64_to_cpu(idx->ch.sqnum) != d->old_zroot_sqnum) { err = 3; goto out_dump; } /* Set last values as though root had a parent */ last_level = le16_to_cpu(idx->level) + 1; last_sqnum = le64_to_cpu(idx->ch.sqnum) + 1; key_read(c, ubifs_idx_key(c, idx), &lower_key); highest_ino_key(c, &upper_key, INUM_WATERMARK); } key_copy(c, &upper_key, &i->upper_key); if (le16_to_cpu(idx->level) != last_level - 1) { err = 3; goto out_dump; } /* * The index is always written bottom up hence a child's sqnum * is always less than the parents. */ if (le64_to_cpu(idx->ch.sqnum) >= last_sqnum) { err = 4; goto out_dump; } /* Check key range */ key_read(c, ubifs_idx_key(c, idx), &l_key); br = ubifs_idx_branch(c, idx, child_cnt - 1); key_read(c, &br->key, &u_key); if (keys_cmp(c, &lower_key, &l_key) > 0) { err = 5; goto out_dump; } if (keys_cmp(c, &upper_key, &u_key) < 0) { err = 6; goto out_dump; } if (keys_cmp(c, &upper_key, &u_key) == 0) if (!is_hash_key(c, &u_key)) { err = 7; goto out_dump; } /* Go to next index node */ if (le16_to_cpu(idx->level) == 0) { /* At the bottom, so go up until can go right */ while (1) { /* Drop the bottom of the list */ list_del(&i->list); kfree(i); /* No more list means we are done */ if (list_empty(&list)) goto out; /* Look at the new bottom */ i = list_entry(list.prev, struct idx_node, list); idx = &i->idx; /* Can we go right */ if (iip + 1 < le16_to_cpu(idx->child_cnt)) { iip = iip + 1; break; } else /* Nope, so go up again */ iip = i->iip; } } else /* Go down left */ iip = 0; /* * We have the parent in 'idx' and now we set up for reading the * child pointed to by slot 'iip'. */ last_level = le16_to_cpu(idx->level); last_sqnum = le64_to_cpu(idx->ch.sqnum); br = ubifs_idx_branch(c, idx, iip); lnum = le32_to_cpu(br->lnum); offs = le32_to_cpu(br->offs); len = le32_to_cpu(br->len); key_read(c, &br->key, &lower_key); if (iip + 1 < le16_to_cpu(idx->child_cnt)) { br = ubifs_idx_branch(c, idx, iip + 1); key_read(c, &br->key, &upper_key); } else key_copy(c, &i->upper_key, &upper_key); }
/** * read_znode - read an indexing node from flash and fill znode. * @c: UBIFS file-system description object * @lnum: LEB of the indexing node to read * @offs: node offset * @len: node length * @znode: znode to read to * * This function reads an indexing node from the flash media and fills znode * with the read data. Returns zero in case of success and a negative error * code in case of failure. The read indexing node is validated and if anything * is wrong with it, this function prints complaint messages and returns * %-EINVAL. */ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, struct ubifs_znode *znode) { int i, err, type, cmp; struct ubifs_idx_node *idx; idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); if (!idx) return -ENOMEM; err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); if (err < 0) { kfree(idx); return err; } znode->child_cnt = le16_to_cpu(idx->child_cnt); znode->level = le16_to_cpu(idx->level); dbg_tnc("LEB %d:%d, level %d, %d branch", lnum, offs, znode->level, znode->child_cnt); if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) { dbg_err("current fanout %d, branch count %d", c->fanout, znode->child_cnt); dbg_err("max levels %d, znode level %d", UBIFS_MAX_LEVELS, znode->level); err = 1; goto out_dump; } for (i = 0; i < znode->child_cnt; i++) { const 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); zbr->znode = NULL; /* Validate branch */ if (zbr->lnum < c->main_first || zbr->lnum >= c->leb_cnt || zbr->offs < 0 || zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) { dbg_err("bad branch %d", i); err = 2; goto out_dump; } switch (key_type(c, &zbr->key)) { case UBIFS_INO_KEY: case UBIFS_DATA_KEY: case UBIFS_DENT_KEY: case UBIFS_XENT_KEY: break; default: dbg_msg("bad key type at slot %d: %s", i, DBGKEY(&zbr->key)); err = 3; goto out_dump; } if (znode->level) continue; type = key_type(c, &zbr->key); if (c->ranges[type].max_len == 0) { if (zbr->len != c->ranges[type].len) { dbg_err("bad target node (type %d) length (%d)", type, zbr->len); dbg_err("have to be %d", c->ranges[type].len); err = 4; goto out_dump; } } else if (zbr->len < c->ranges[type].min_len || zbr->len > c->ranges[type].max_len) { dbg_err("bad target node (type %d) length (%d)", type, zbr->len); dbg_err("have to be in range of %d-%d", c->ranges[type].min_len, c->ranges[type].max_len); err = 5; goto out_dump; } } /* * Ensure that the next key is greater or equivalent to the * previous one. */ for (i = 0; i < znode->child_cnt - 1; i++) { const union ubifs_key *key1, *key2; key1 = &znode->zbranch[i].key; key2 = &znode->zbranch[i + 1].key; cmp = keys_cmp(c, key1, key2); if (cmp > 0) { dbg_err("bad key order (keys %d and %d)", i, i + 1); err = 6; goto out_dump; } else if (cmp == 0 && !is_hash_key(c, key1)) { /* These can only be keys with colliding hash */ dbg_err("keys %d and %d are not hashed but equivalent", i, i + 1); err = 7; goto out_dump; } } kfree(idx); return 0; out_dump: ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err); dbg_dump_node(c, idx); kfree(idx); return -EINVAL; }