+/**
+ * dbg_chk_lpt_free_spc - check LPT free space is enough to write entire LPT.
+ * @c: the UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int dbg_chk_lpt_free_spc(struct ubifs_info *c)
+{
+ long long free = 0;
+ int i;
+
+ for (i = 0; i < c->lpt_lebs; i++) {
+ if (c->ltab[i].tgc || c->ltab[i].cmt)
+ continue;
+ if (i + c->lpt_first == c->nhead_lnum)
+ free += c->leb_size - c->nhead_offs;
+ else if (c->ltab[i].free == c->leb_size)
+ free += c->leb_size;
+ }
+ if (free < c->lpt_sz) {
+ dbg_err("LPT space error: free %lld lpt_sz %lld",
+ free, c->lpt_sz);
+ dbg_dump_lpt_info(c);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * dbg_chk_lpt_sz - check LPT does not write more than LPT size.
+ * @c: the UBIFS file-system description object
+ * @action: action
+ * @len: length written
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+{
+ long long chk_lpt_sz, lpt_sz;
+ int err = 0;
+
+ switch (action) {
+ case 0:
+ c->chk_lpt_sz = 0;
+ c->chk_lpt_sz2 = 0;
+ c->chk_lpt_lebs = 0;
+ c->chk_lpt_wastage = 0;
+ if (c->dirty_pn_cnt > c->pnode_cnt) {
+ dbg_err("dirty pnodes %d exceed max %d",
+ c->dirty_pn_cnt, c->pnode_cnt);
+ err = -EINVAL;
+ }
+ if (c->dirty_nn_cnt > c->nnode_cnt) {
+ dbg_err("dirty nnodes %d exceed max %d",
+ c->dirty_nn_cnt, c->nnode_cnt);
+ err = -EINVAL;
+ }
+ return err;
+ case 1:
+ c->chk_lpt_sz += len;
+ return 0;
+ case 2:
+ c->chk_lpt_sz += len;
+ c->chk_lpt_wastage += len;
+ c->chk_lpt_lebs += 1;
+ return 0;
+ case 3:
+ chk_lpt_sz = c->leb_size;
+ chk_lpt_sz *= c->chk_lpt_lebs;
+ chk_lpt_sz += len - c->nhead_offs;
+ if (c->chk_lpt_sz != chk_lpt_sz) {
+ dbg_err("LPT wrote %lld but space used was %lld",
+ c->chk_lpt_sz, chk_lpt_sz);
+ err = -EINVAL;
+ }
+ if (c->chk_lpt_sz > c->lpt_sz) {
+ dbg_err("LPT wrote %lld but lpt_sz is %lld",
+ c->chk_lpt_sz, c->lpt_sz);
+ err = -EINVAL;
+ }
+ if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) {
+ dbg_err("LPT layout size %lld but wrote %lld",
+ c->chk_lpt_sz, c->chk_lpt_sz2);
+ err = -EINVAL;
+ }
+ if (c->chk_lpt_sz2 && c->new_nhead_offs != len) {
+ dbg_err("LPT new nhead offs: expected %d was %d",
+ c->new_nhead_offs, len);
+ err = -EINVAL;
+ }
+ lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
+ lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
+ lpt_sz += c->ltab_sz;
+ if (c->big_lpt)
+ lpt_sz += c->lsave_sz;
+ if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) {
+ dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
+ c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz);
+ err = -EINVAL;
+ }
+ if (err)
+ dbg_dump_lpt_info(c);
+ c->chk_lpt_sz2 = c->chk_lpt_sz;
+ c->chk_lpt_sz = 0;
+ c->chk_lpt_wastage = 0;
+ c->chk_lpt_lebs = 0;
+ c->new_nhead_offs = len;
+ return err;
+ case 4:
+ c->chk_lpt_sz += len;
+ c->chk_lpt_wastage += len;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+