// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2006 * * Author: Artem Bityutskiy (Битюцкий Артём) * * Jan 2007: Alexander Schmidt, hacked per-volume update.
*/
/* * This file contains implementation of the volume update and atomic LEB change * functionality. * * The update operation is based on the per-volume update marker which is * stored in the volume table. The update marker is set before the update * starts, and removed after the update has been finished. So if the update was * interrupted by an unclean re-boot or due to some other reasons, the update * marker stays on the flash media and UBI finds it when it attaches the MTD * device next time. If the update marker is set for a volume, the volume is * treated as damaged and most I/O operations are prohibited. Only a new update * operation is allowed. * * Note, in general it is possible to implement the update operation as a * transaction with a roll-back capability.
*/
/** * set_update_marker - set update marker. * @ubi: UBI device description object * @vol: volume description object * * This function sets the update marker flag for volume @vol. Returns zero * in case of success and a negative error code in case of failure.
*/ staticint set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
{ int err; struct ubi_vtbl_record vtbl_rec;
dbg_gen("set update marker for volume %d", vol->vol_id);
if (vol->upd_marker) {
ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
dbg_gen("already set"); return 0;
}
/** * clear_update_marker - clear update marker. * @ubi: UBI device description object * @vol: volume description object * @bytes: new data size in bytes * * This function clears the update marker for volume @vol, sets new volume * data size and clears the "corrupted" flag (static volumes only). Returns * zero in case of success and a negative error code in case of failure.
*/ staticint clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, longlong bytes)
{ int err; struct ubi_vtbl_record vtbl_rec;
dbg_gen("clear update marker for volume %d", vol->vol_id);
/** * ubi_start_update - start volume update. * @ubi: UBI device description object * @vol: volume description object * @bytes: update bytes * * This function starts volume update operation. If @bytes is zero, the volume * is just wiped out. Returns zero in case of success and a negative error code * in case of failure.
*/ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, longlong bytes)
{ int i, err;
/** * ubi_start_leb_change - start atomic LEB change. * @ubi: UBI device description object * @vol: volume description object * @req: operation request * * This function starts atomic LEB change operation. Returns zero in case of * success and a negative error code in case of failure.
*/ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, conststruct ubi_leb_change_req *req)
{
ubi_assert(!vol->updating && !vol->changing_leb);
vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size)); if (!vol->upd_buf) return -ENOMEM;
return 0;
}
/** * 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.
*/ staticint 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;
}
/** * ubi_more_update_data - write more update data. * @ubi: UBI device description object * @vol: volume description object * @buf: write data (user-space memory buffer) * @count: how much bytes to write * * This function writes more data to the volume which is being updated. It may * be called arbitrary number of times until all the update data arriveis. This * function returns %0 in case of success, number of bytes written during the * last call if the whole volume update has been successfully finished, and a * negative error code in case of failure.
*/ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, constvoid __user *buf, int count)
{ int lnum, offs, err = 0, len, to_write = count;
/* * When updating volumes, we accumulate whole logical eraseblock of * data and write it at once.
*/ if (offs != 0) { /* * This is a write to the middle of the logical eraseblock. We * copy the data to our update buffer and wait for more data or * flush it if the whole eraseblock is written or the update * is finished.
*/
len = vol->usable_leb_size - offs; if (len > count)
len = count;
if (offs + len == vol->usable_leb_size ||
vol->upd_received + len == vol->upd_bytes) { int flush_len = offs + len;
/* * OK, we gathered either the whole eraseblock or this * is the last chunk, it's time to flush the buffer.
*/
ubi_assert(flush_len <= vol->usable_leb_size);
err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
vol->upd_ebs); if (err) return err;
}
/* * If we've got more to write, let's continue. At this point we know we * are starting from the beginning of an eraseblock.
*/ while (count) { if (count > vol->usable_leb_size)
len = vol->usable_leb_size; else
len = count;
err = copy_from_user(vol->upd_buf, buf, len); if (err) return -EFAULT;
if (len == vol->usable_leb_size ||
vol->upd_received + len == vol->upd_bytes) {
err = write_leb(ubi, vol, lnum, vol->upd_buf,
len, vol->upd_ebs); if (err) break;
}
ubi_assert(vol->upd_received <= vol->upd_bytes); if (vol->upd_received == vol->upd_bytes) {
err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); if (err) return err; /* The update is finished, clear the update marker */
err = clear_update_marker(ubi, vol, vol->upd_bytes); if (err) return err;
vol->updating = 0;
err = to_write;
vfree(vol->upd_buf);
}
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, constvoid __user *buf, int count)
{ int err;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.13Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.