/** * write_leb - write update data. * @ubi: UBI device description object * @vol: volume description object * @lnum: logical eraseblock number * @buf: data to write * @len: data size * @used_ebs: how many logical eraseblocks will this volume contain (static * volumes only) * * This function writes update data to corresponding logical eraseblock. In * case of dynamic volume, this function checks if the data contains 0xFF bytes * at the end. If yes, the 0xFF bytes are cut and not written. So if the whole * buffer contains only 0xFF bytes, the LEB is left unmapped. * * The reason why we skip the trailing 0xFF bytes in case of dynamic volume is * that we want to make sure that more data may be appended to the logical * eraseblock in future. Indeed, writing 0xFF bytes may have side effects and * this PEB won't be writable anymore. So if one writes the file-system image * to the UBI volume where 0xFFs mean free space - UBI makes sure this free * space is writable after the update. * * We do not do this for static volumes because they are read-only. But this * also cannot be done because we have to store per-LEB CRC and the correct * data length. * * This function returns zero in case of success and a negative error code in * case of failure. */ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, void *buf, int len, int used_ebs) { int err; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { int l = ALIGN(len, ubi->min_io_size); memset(buf + len, 0xFF, l - len); len = ubi_calc_data_len(ubi, buf, l); if (len == 0) { dbg_gen("all %d bytes contain 0xFF - skip", len); return 0; } err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len); } else { /* * When writing static volume, and this is the last logical * eraseblock, the length (@len) does not have to be aligned to * the minimal flash I/O unit. The 'ubi_eba_write_leb_st()' * function accepts exact (unaligned) length and stores it in * the VID header. And it takes care of proper alignment by * padding the buffer. Here we just make sure the padding will * contain zeros, not random trash. */ memset(buf + len, 0, vol->usable_leb_size - len); err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, used_ebs); } return err; }
static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, void *buf, int len, int used_ebs) { int err; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { int l = ALIGN(len, ubi->min_io_size); memset(buf + len, 0xFF, l - len); len = ubi_calc_data_len(ubi, buf, l); if (len == 0) { dbg_gen("all %d bytes contain 0xFF - skip", len); return 0; } err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); } else { memset(buf + len, 0, vol->usable_leb_size - len); err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, UBI_UNKNOWN, used_ebs); } return err; }
/** * ubi_more_leb_change_data - accept more data for atomic LEB change. * @ubi: UBI device description object * @vol: volume description object * @buf: write data (user-space memory buffer) * @count: how much bytes to write * * This function accepts more data to the volume which is being under the * "atomic LEB change" operation. It may be called arbitrary number of times * until all data arrives. This function returns %0 in case of success, number * of bytes written during the last call if the whole "atomic LEB change" * operation has been successfully finished, and a negative error code in case * of failure. */ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, const void __user *buf, int count) { int err; dbg_gen("write %d of %lld bytes, %lld already passed", count, vol->upd_bytes, vol->upd_received); if (ubi->ro_mode) return -EROFS; if (vol->upd_received + count > vol->upd_bytes) count = vol->upd_bytes - vol->upd_received; err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count); if (err) return -EFAULT; vol->upd_received += count; if (vol->upd_received == vol->upd_bytes) { int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); len = ubi_calc_data_len(ubi, vol->upd_buf, len); err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, vol->upd_buf, len); if (err) return err; } ubi_assert(vol->upd_received <= vol->upd_bytes); if (vol->upd_received == vol->upd_bytes) { vol->changing_leb = 0; err = count; vfree(vol->upd_buf); } return err; }