/** * ubifs_wbuf_sync_nolock - synchronize write-buffer. * @wbuf: write-buffer to synchronize * * This function synchronizes write-buffer @buf and returns zero in case of * success or a negative error code in case of failure. */ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) { struct ubifs_info *c = wbuf->c; int err, dirt; cancel_wbuf_timer_nolock(wbuf); if (!wbuf->used || wbuf->lnum == -1) /* Write-buffer is empty or not seeked */ return 0; dbg_io("LEB %d:%d, %d bytes", wbuf->lnum, wbuf->offs, wbuf->used); ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); ubifs_assert(!(wbuf->avail & 7)); ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); if (c->ro_media) return -EROFS; ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail); err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, c->min_io_size, wbuf->dtype); if (err) { ubifs_err("cannot write %d bytes to LEB %d:%d", c->min_io_size, wbuf->lnum, wbuf->offs); dbg_dump_stack(); return err; } dirt = wbuf->avail; spin_lock(&wbuf->lock); wbuf->offs += c->min_io_size; wbuf->avail = c->min_io_size; wbuf->used = 0; wbuf->next_ino = 0; spin_unlock(&wbuf->lock); if (wbuf->sync_callback) err = wbuf->sync_callback(c, wbuf->lnum, c->leb_size - wbuf->offs, dirt); return err; }
/** * ubifs_prepare_node - prepare node to be written to flash. * @c: UBIFS file-system description object * @node: the node to pad * @len: node length * @pad: if the buffer has to be padded * * This function prepares node at @node to be written to the media - it * calculates node CRC, fills the common header, and adds proper padding up to * the next minimum I/O unit if @pad is not zero. */ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) { uint32_t crc; struct ubifs_ch *ch = node; unsigned long long sqnum = next_sqnum(c); ubifs_assert(len >= UBIFS_CH_SZ); ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); ch->len = cpu_to_le32(len); ch->group_type = UBIFS_NO_NODE_GROUP; ch->sqnum = cpu_to_le64(sqnum); ch->padding[0] = ch->padding[1] = 0; crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); ch->crc = cpu_to_le32(crc); if (pad) { len = ALIGN(len, 8); pad = ALIGN(len, c->min_io_size) - len; ubifs_pad(c, node + len, pad); } }
/** * ubifs_wbuf_sync_nolock - synchronize write-buffer. * @wbuf: write-buffer to synchronize * * This function synchronizes write-buffer @buf and returns zero in case of * success or a negative error code in case of failure. * * Note, although write-buffers are of @c->max_write_size, this function does * not necessarily writes all @c->max_write_size bytes to the flash. Instead, * if the write-buffer is only partially filled with data, only the used part * of the write-buffer (aligned on @c->min_io_size boundary) is synchronized. * This way we waste less space. */ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) { struct ubifs_info *c = wbuf->c; int err, dirt, sync_len; cancel_wbuf_timer_nolock(wbuf); if (!wbuf->used || wbuf->lnum == -1) /* Write-buffer is empty or not seeked */ return 0; dbg_io("LEB %d:%d, %d bytes, jhead %s", wbuf->lnum, wbuf->offs, wbuf->used, dbg_jhead(wbuf->jhead)); ubifs_assert(!(wbuf->avail & 7)); ubifs_assert(wbuf->offs + wbuf->size <= c->leb_size); ubifs_assert(wbuf->size >= c->min_io_size); ubifs_assert(wbuf->size <= c->max_write_size); ubifs_assert(wbuf->size % c->min_io_size == 0); ubifs_assert(!c->ro_media && !c->ro_mount); if (c->leb_size - wbuf->offs >= c->max_write_size) ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size)); if (c->ro_error) return -EROFS; /* * Do not write whole write buffer but write only the minimum necessary * amount of min. I/O units. */ sync_len = ALIGN(wbuf->used, c->min_io_size); dirt = sync_len - wbuf->used; if (dirt) ubifs_pad(c, wbuf->buf + wbuf->used, dirt); #if defined(FEATURE_UBIFS_PERF_INDEX) if(wbuf->jhead == DATAHD) err = ubifs_leb_write_log(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len); else #endif err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len); if (err) return err; wbuf->w_count += sync_len; //MTK spin_lock(&wbuf->lock); wbuf->offs += sync_len; /* * Now @wbuf->offs is not necessarily aligned to @c->max_write_size. * But our goal is to optimize writes and make sure we write in * @c->max_write_size chunks and to @c->max_write_size-aligned offset. * Thus, if @wbuf->offs is not aligned to @c->max_write_size now, make * sure that @wbuf->offs + @wbuf->size is aligned to * @c->max_write_size. This way we make sure that after next * write-buffer flush we are again at the optimal offset (aligned to * @c->max_write_size). */ if (c->leb_size - wbuf->offs < c->max_write_size) wbuf->size = c->leb_size - wbuf->offs; else if (wbuf->offs & (c->max_write_size - 1)) wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs; else wbuf->size = c->max_write_size; wbuf->avail = wbuf->size; wbuf->used = 0; wbuf->next_ino = 0; spin_unlock(&wbuf->lock); if (wbuf->sync_callback) err = wbuf->sync_callback(c, wbuf->lnum, c->leb_size - wbuf->offs, dirt); 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; }