Esempio n. 1
0
int ubi_finish_update(struct ubi_device *ubi, struct ubi_volume *vol)
{
	int err;

	/* The update is finished, clear the update marker */
	err = clear_update_marker(ubi, vol, vol->upd_bytes);
	if (err)
		return err;
	err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
	if (err == 0) {
		vol->updating = 0;
		vfree(vol->upd_buf);
	}

	return err;
}
Esempio n. 2
0
/**
 * 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,
		     long long bytes)
{
	int i, err;

	dbg_gen("start update of volume %d, %llu bytes", vol->vol_id, bytes);
	ubi_assert(!vol->updating && !vol->changing_leb);
	vol->updating = 1;

	vol->upd_buf = vmalloc(ubi->leb_size);
	if (!vol->upd_buf)
		return -ENOMEM;

	err = set_update_marker(ubi, vol);
	if (err)
		return err;

	/* Before updating - wipe out the volume */
	for (i = 0; i < vol->reserved_pebs; i++) {
		err = ubi_eba_unmap_leb(ubi, vol, i);
		if (err)
			return err;
	}

	if (bytes == 0) {
		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
		if (err)
			return err;

		err = clear_update_marker(ubi, vol, 0);
		if (err)
			return err;

		vfree(vol->upd_buf);
		vol->updating = 0;
		return 0;
	}

	vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1,
			       vol->usable_leb_size);
	vol->upd_bytes = bytes;
	vol->upd_received = 0;
	return 0;
}
Esempio n. 3
0
File: upd.c Progetto: 274914765/C
/**
 * 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,
             long long bytes)
{
    int i, err;
    uint64_t tmp;

    dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
    ubi_assert(!vol->updating && !vol->changing_leb);
    vol->updating = 1;

    err = set_update_marker(ubi, vol);
    if (err)
        return err;

    /* Before updating - wipe out the volume */
    for (i = 0; i < vol->reserved_pebs; i++) {
        err = ubi_eba_unmap_leb(ubi, vol, i);
        if (err)
            return err;
    }

    if (bytes == 0) {
        err = clear_update_marker(ubi, vol, 0);
        if (err)
            return err;
        err = ubi_wl_flush(ubi);
        if (!err)
            vol->updating = 0;
    }

    vol->upd_buf = vmalloc(ubi->leb_size);
    if (!vol->upd_buf)
        return -ENOMEM;

    tmp = bytes;
    vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size);
    vol->upd_ebs += tmp;
    vol->upd_bytes = bytes;
    vol->upd_received = 0;
    return 0;
}
Esempio n. 4
0
/**
 * 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,
			 const void __user *buf, int count)
{
#ifndef __UBOOT__
	int lnum, offs, err = 0, len, to_write = count;
#else
	int lnum, err = 0, len, to_write = count;
	u32 offs;
#endif

	dbg_gen("write %d of %lld bytes, %lld already passed",
		count, vol->upd_bytes, vol->upd_received);

	if (ubi->ro_mode)
		return -EROFS;

	lnum = div_u64_rem(vol->upd_received,  vol->usable_leb_size, &offs);
	if (vol->upd_received + count > vol->upd_bytes)
		to_write = count = vol->upd_bytes - vol->upd_received;

	/*
	 * 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;

		err = copy_from_user(vol->upd_buf + offs, buf, len);
		if (err)
			return -EFAULT;

		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;
		}

		vol->upd_received += len;
		count -= len;
		buf += len;
		lnum += 1;
	}

	/*
	 * 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;
		}

		vol->upd_received += len;
		count -= len;
		lnum += 1;
		buf += len;
	}

	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;
}
Esempio n. 5
0
int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
                         const void __user *buf, int count)
{
    int lnum, offs, err = 0, len, to_write = count;

    dbg_gen("write %d of %lld bytes, %lld already passed",
            count, vol->upd_bytes, vol->upd_received);

    if (ubi->ro_mode)
        return -EROFS;

    lnum = div_u64_rem(vol->upd_received,  vol->usable_leb_size, &offs);
    if (vol->upd_received + count > vol->upd_bytes)
        to_write = count = vol->upd_bytes - vol->upd_received;


    if (offs != 0) {


        len = vol->usable_leb_size - offs;
        if (len > count)
            len = count;

        err = copy_from_user(vol->upd_buf + offs, buf, len);
        if (err)
            return -EFAULT;

        if (offs + len == vol->usable_leb_size ||
                vol->upd_received + len == vol->upd_bytes) {
            int flush_len = offs + len;


            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;
        }

        vol->upd_received += len;
        count -= len;
        buf += len;
        lnum += 1;
    }


    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;
        }

        vol->upd_received += len;
        count -= len;
        lnum += 1;
        buf += len;
    }

    ubi_assert(vol->upd_received <= vol->upd_bytes);
    if (vol->upd_received == vol->upd_bytes) {
        err = ubi_wl_flush(ubi);
        if (err)
            return err;

        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;
}