/** * ubifs_log_post_commit - things to do after commit is completed. * @c: UBIFS file-system description object * @old_ltail_lnum: old log tail LEB number * * Release buds only after commit is completed, because they must be unchanged * if recovery is needed. * * Unmap log LEBs only after commit is completed, because they may be needed for * recovery. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum) { int lnum, err = 0; while (!list_empty(&c->old_buds)) { struct ubifs_bud *bud; bud = list_entry(c->old_buds.next, struct ubifs_bud, list); err = ubifs_return_leb(c, bud->lnum); if (err) return err; list_del(&bud->list); kfree(bud); } mutex_lock(&c->log_mutex); for (lnum = old_ltail_lnum; lnum != c->ltail_lnum; lnum = ubifs_next_log_lnum(c, lnum)) { dbg_log("unmap log LEB %d", lnum); err = ubifs_leb_unmap(c, lnum); if (err) goto out; } out: mutex_unlock(&c->log_mutex); return err; }
/** * fixup_free_space - find & remap all LEBs containing free space. * @c: UBIFS file-system description object * * This function walks through all LEBs in the filesystem and fiexes up those * containing free/empty space. */ static int fixup_free_space(struct ubifs_info *c) { int lnum, err = 0; struct ubifs_lprops *lprops; ubifs_get_lprops(c); /* Fixup LEBs in the master area */ for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) { err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz); if (err) goto out; } /* Unmap unused log LEBs */ lnum = ubifs_next_log_lnum(c, c->lhead_lnum); while (lnum != c->ltail_lnum) { err = fixup_leb(c, lnum, 0); if (err) goto out; lnum = ubifs_next_log_lnum(c, lnum); } /* * Fixup the log head which contains the only a CS node at the * beginning. */ err = fixup_leb(c, c->lhead_lnum, ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size)); if (err) goto out; /* Fixup LEBs in the LPT area */ for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) { int free = c->ltab[lnum - c->lpt_first].free; if (free > 0) { err = fixup_leb(c, lnum, c->leb_size - free); if (err) goto out; } } /* Unmap LEBs in the orphans area */ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { err = fixup_leb(c, lnum, 0); if (err) goto out; } /* Fixup LEBs in the main area */ for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) { lprops = ubifs_lpt_lookup(c, lnum); if (IS_ERR(lprops)) { err = PTR_ERR(lprops); goto out; } if (lprops->free > 0) { err = fixup_leb(c, lnum, c->leb_size - lprops->free); if (err) goto out; } } out: ubifs_release_lprops(c); return err; }
/** * ubifs_log_start_commit - start commit. * @c: UBIFS file-system description object * @ltail_lnum: return new log tail LEB number * * The commit operation starts with writing "commit start" node to the log and * reference nodes for all journal heads which will define new journal after * the commit has been finished. The commit start and reference nodes are * written in one go to the nearest empty log LEB (hence, when commit is * finished UBIFS may safely unmap all the previous log LEBs). This function * returns zero in case of success and a negative error code in case of * failure. */ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) { void *buf; struct ubifs_cs_node *cs; struct ubifs_ref_node *ref; int err, i, max_len, len; err = dbg_check_bud_bytes(c); if (err) return err; max_len = UBIFS_CS_NODE_SZ + c->jhead_cnt * UBIFS_REF_NODE_SZ; max_len = ALIGN(max_len, c->min_io_size); buf = cs = kmalloc(max_len, GFP_NOFS); if (!buf) return -ENOMEM; cs->ch.node_type = UBIFS_CS_NODE; cs->cmt_no = cpu_to_le64(c->cmt_no); ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); /* * Note, we do not lock 'c->log_mutex' because this is the commit start * phase and we are exclusively using the log. And we do not lock * write-buffer because nobody can write to the file-system at this * phase. */ len = UBIFS_CS_NODE_SZ; for (i = 0; i < c->jhead_cnt; i++) { int lnum = c->jheads[i].wbuf.lnum; int offs = c->jheads[i].wbuf.offs; if (lnum == -1 || offs == c->leb_size) continue; dbg_log("add ref to LEB %d:%d for jhead %s", lnum, offs, dbg_jhead(i)); ref = buf + len; ref->ch.node_type = UBIFS_REF_NODE; ref->lnum = cpu_to_le32(lnum); ref->offs = cpu_to_le32(offs); ref->jhead = cpu_to_le32(i); ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0); len += UBIFS_REF_NODE_SZ; } ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len); #ifdef CONFIG_UBIFS_FS_FULL_USE_LOG /* Not Switch to next log LEB, programming next available page in the same log LEB continuously*/ /* if available page is in the end of the LEB, switch to next LEB*/ if(c->lhead_offs >= (c->leb_size - (c->min_io_size * 4)) ) { int old_lnum = c->lhead_lnum; int old_offs = c->lhead_offs; c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum); c->lhead_offs = 0; ubifs_msg("switch log LEB %d:%d to %d:%d\n", old_lnum, old_offs, c->lhead_lnum, c->lhead_offs); } #else /* Switch to the next log LEB */ if (c->lhead_offs) { int old_lnum = c->lhead_lnum; int old_offs = c->lhead_offs; c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum); c->lhead_offs = 0; ubifs_msg("switch log LEB %d:%d to %d:%d\n", old_lnum, old_offs, c->lhead_lnum, c->lhead_offs); } #endif if (c->lhead_offs == 0) { /* Must ensure next LEB has been unmapped */ err = ubifs_leb_unmap(c, c->lhead_lnum); if (err) goto out; } len = ALIGN(len, c->min_io_size); dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len); err = ubifs_leb_write(c, c->lhead_lnum, cs, c->lhead_offs, len); //MTK, modify offset 0 -> c->lhead_offs if (err) goto out; *ltail_lnum = c->lhead_lnum; c->lhead_offs += len; if (c->lhead_offs == c->leb_size) { c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum); c->lhead_offs = 0; } remove_buds(c); /* * We have started the commit and now users may use the rest of the log * for new writes. */ c->min_log_bytes = 0; out: kfree(buf); return err; }
/** * ubifs_add_bud_to_log - add a new bud to the log. * @c: UBIFS file-system description object * @jhead: journal head the bud belongs to * @lnum: LEB number of the bud * @offs: starting offset of the bud * * This function writes reference node for the new bud LEB @lnum it to the log, * and adds it to the buds tress. It also makes sure that log size does not * exceed the 'c->max_bud_bytes' limit. Returns zero in case of success, * %-EAGAIN if commit is required, and a negative error codes in case of * failure. */ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) { int err; struct ubifs_bud *bud; struct ubifs_ref_node *ref; bud = kmalloc(sizeof(struct ubifs_bud), GFP_NOFS); if (!bud) return -ENOMEM; ref = kzalloc(c->ref_node_alsz, GFP_NOFS); if (!ref) { kfree(bud); return -ENOMEM; } mutex_lock(&c->log_mutex); ubifs_assert(!c->ro_media && !c->ro_mount); if (c->ro_error) { err = -EROFS; goto out_unlock; } /* Make sure we have enough space in the log */ if (empty_log_bytes(c) - c->ref_node_alsz < c->min_log_bytes) { dbg_log("not enough log space - %lld, required %d", empty_log_bytes(c), c->min_log_bytes); ubifs_commit_required(c); err = -EAGAIN; goto out_unlock; } /* * Make sure the amount of space in buds will not exceed the * 'c->max_bud_bytes' limit, because we want to guarantee mount time * limits. * * It is not necessary to hold @c->buds_lock when reading @c->bud_bytes * because we are holding @c->log_mutex. All @c->bud_bytes take place * when both @c->log_mutex and @c->bud_bytes are locked. */ if (c->bud_bytes + c->leb_size - offs > c->max_bud_bytes) { dbg_log("bud bytes %lld (%lld max), require commit", c->bud_bytes, c->max_bud_bytes); ubifs_commit_required(c); err = -EAGAIN; goto out_unlock; } /* * If the journal is full enough - start background commit. Note, it is * OK to read 'c->cmt_state' without spinlock because integer reads * are atomic in the kernel. */ if (c->bud_bytes >= c->bg_bud_bytes && c->cmt_state == COMMIT_RESTING) { dbg_log("bud bytes %lld (%lld max), initiate BG commit", c->bud_bytes, c->max_bud_bytes); ubifs_request_bg_commit(c); } bud->lnum = lnum; bud->start = offs; bud->jhead = jhead; ref->ch.node_type = UBIFS_REF_NODE; ref->lnum = cpu_to_le32(bud->lnum); ref->offs = cpu_to_le32(bud->start); ref->jhead = cpu_to_le32(jhead); if (c->lhead_offs > c->leb_size - c->ref_node_alsz) { c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum); c->lhead_offs = 0; } if (c->lhead_offs == 0) { /* Must ensure next log LEB has been unmapped */ err = ubifs_leb_unmap(c, c->lhead_lnum); if (err) goto out_unlock; } if (bud->start == 0) { /* * Before writing the LEB reference which refers an empty LEB * to the log, we have to make sure it is mapped, because * otherwise we'd risk to refer an LEB with garbage in case of * an unclean reboot, because the target LEB might have been * unmapped, but not yet physically erased. */ err = ubifs_leb_map(c, bud->lnum); if (err) goto out_unlock; } dbg_log("write ref LEB %d:%d", c->lhead_lnum, c->lhead_offs); err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum, c->lhead_offs); if (err) goto out_unlock; c->lhead_offs += c->ref_node_alsz; ubifs_add_bud(c, bud); mutex_unlock(&c->log_mutex); kfree(ref); return 0; out_unlock: mutex_unlock(&c->log_mutex); kfree(ref); kfree(bud); return err; }