Example #1
0
/**
 * paranoid_check_peb_vid_hdr - check volume identifier header.
 * @ubi: UBI device description object
 * @pnum: the physical eraseblock number to check
 *
 * This function returns zero if the volume identifier header is all right,
 * and a negative error code if not or if an error occurred.
 */
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
{
	int err;
	uint32_t crc, hdr_crc;
	struct ubi_vid_hdr *vid_hdr;
	void *p;

	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
	if (!vid_hdr)
		return -ENOMEM;

	p = (char *)vid_hdr - ubi->vid_hdr_shift;
	err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
			  ubi->vid_hdr_alsize);
	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
		goto exit;

	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
	hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
	if (hdr_crc != crc) {
		ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
			"read %#08x", pnum, crc, hdr_crc);
		ubi_err("paranoid check failed for PEB %d", pnum);
		ubi_dbg_dump_vid_hdr(vid_hdr);
		ubi_dbg_dump_stack();
		err = -EINVAL;
		goto exit;
	}

	err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);

exit:
	ubi_free_vid_hdr(ubi, vid_hdr);
	return err;
}
Example #2
0
/**
 * compare_lebs - find out which logical eraseblock is newer.
 * @ubi: UBI device description object
 * @seb: first logical eraseblock to compare
 * @pnum: physical eraseblock number of the second logical eraseblock to
 * compare
 * @vid_hdr: volume identifier header of the second logical eraseblock
 *
 * This function compares 2 copies of a LEB and informs which one is newer. In
 * case of success this function returns a positive value, in case of failure, a
 * negative error code is returned. The success return codes use the following
 * bits:
 *     o bit 0 is cleared: the first PEB (described by @seb) is newer than the
 *       second PEB (described by @pnum and @vid_hdr);
 *     o bit 0 is set: the second PEB is newer;
 *     o bit 1 is cleared: no bit-flips were detected in the newer LEB;
 *     o bit 1 is set: bit-flips were detected in the newer LEB;
 *     o bit 2 is cleared: the older LEB is not corrupted;
 *     o bit 2 is set: the older LEB is corrupted.
 */
static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
			int pnum, const struct ubi_vid_hdr *vid_hdr)
{
	void *buf;
	int len, err, second_is_newer, bitflips = 0, corrupted = 0;
	uint32_t data_crc, crc;
	struct ubi_vid_hdr *vh = NULL;
	unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);

	if (sqnum2 == seb->sqnum) {
		/*
		 * This must be a really ancient UBI image which has been
		 * created before sequence numbers support has been added. At
		 * that times we used 32-bit LEB versions stored in logical
		 * eraseblocks. That was before UBI got into mainline. We do not
		 * support these images anymore. Well, those images still work,
		 * but only if no unclean reboots happened.
		 */
		ubi_err("unsupported on-flash UBI format\n");
		return -EINVAL;
	}

	/* Obviously the LEB with lower sequence counter is older */
	second_is_newer = !!(sqnum2 > seb->sqnum);

	/*
	 * Now we know which copy is newer. If the copy flag of the PEB with
	 * newer version is not set, then we just return, otherwise we have to
	 * check data CRC. For the second PEB we already have the VID header,
	 * for the first one - we'll need to re-read it from flash.
	 *
	 * Note: this may be optimized so that we wouldn't read twice.
	 */

	if (second_is_newer) {
		if (!vid_hdr->copy_flag) {
			/* It is not a copy, so it is newer */
			dbg_bld("second PEB %d is newer, copy_flag is unset",
				pnum);
			return 1;
		}
	} else {
		if (!seb->copy_flag) {
			/* It is not a copy, so it is newer */
			dbg_bld("first PEB %d is newer, copy_flag is unset",
				pnum);
			return bitflips << 1;
		}

		vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
		if (!vh)
			return -ENOMEM;

		pnum = seb->pnum;
		err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
		if (err) {
			if (err == UBI_IO_BITFLIPS)
				bitflips = 1;
			else {
				dbg_err("VID of PEB %d header is bad, but it "
					"was OK earlier, err %d", pnum, err);
				if (err > 0)
					err = -EIO;

				goto out_free_vidh;
			}
		}

		vid_hdr = vh;
	}

	/* Read the data of the copy and check the CRC */

	len = be32_to_cpu(vid_hdr->data_size);
	buf = vmalloc(len);
	if (!buf) {
		err = -ENOMEM;
		goto out_free_vidh;
	}

	err = ubi_io_read_data(ubi, buf, pnum, 0, len);
	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
		goto out_free_buf;

	data_crc = be32_to_cpu(vid_hdr->data_crc);
	crc = crc32(UBI_CRC32_INIT, buf, len);
	if (crc != data_crc) {
		dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
			pnum, crc, data_crc);
		corrupted = 1;
		bitflips = 0;
		second_is_newer = !second_is_newer;
	} else {
		dbg_bld("PEB %d CRC is OK", pnum);
		bitflips = !!err;
	}

	vfree(buf);
	ubi_free_vid_hdr(ubi, vh);

	if (second_is_newer)
		dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
	else
		dbg_bld("first PEB %d is newer, copy_flag is set", pnum);

	return second_is_newer | (bitflips << 1) | (corrupted << 2);

out_free_buf:
	vfree(buf);
out_free_vidh:
	ubi_free_vid_hdr(ubi, vh);
	return err;
}
Example #3
0
/**
 * compare_lebs - find out which logical eraseblock is newer.
 * @ubi: UBI device description object
 * @seb: first logical eraseblock to compare
 * @pnum: physical eraseblock number of the second logical eraseblock to
 * compare
 * @vid_hdr: volume identifier header of the second logical eraseblock
 *
 * This function compares 2 copies of a LEB and informs which one is newer. In
 * case of success this function returns a positive value, in case of failure, a
 * negative error code is returned. The success return codes use the following
 * bits:
 *     o bit 0 is cleared: the first PEB (described by @seb) is newer then the
 *       second PEB (described by @pnum and @vid_hdr);
 *     o bit 0 is set: the second PEB is newer;
 *     o bit 1 is cleared: no bit-flips were detected in the newer LEB;
 *     o bit 1 is set: bit-flips were detected in the newer LEB;
 *     o bit 2 is cleared: the older LEB is not corrupted;
 *     o bit 2 is set: the older LEB is corrupted.
 */
static int compare_lebs(const struct ubi_device *ubi,
                        const struct ubi_scan_leb *seb, int pnum,
                        const struct ubi_vid_hdr *vid_hdr)
{
    void *buf;
    int len, err, second_is_newer, bitflips = 0, corrupted = 0;
    uint32_t data_crc, crc;
    struct ubi_vid_hdr *vidh = NULL;
    unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);

    if (seb->sqnum == 0 && sqnum2 == 0) {
        long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);

        /*
         * UBI constantly increases the logical eraseblock version
         * number and it can overflow. Thus, we have to bear in mind
         * that versions that are close to %0xFFFFFFFF are less then
         * versions that are close to %0.
         *
         * The UBI WL unit guarantees that the number of pending tasks
         * is not greater then %0x7FFFFFFF. So, if the difference
         * between any two versions is greater or equivalent to
         * %0x7FFFFFFF, there was an overflow and the logical
         * eraseblock with lower version is actually newer then the one
         * with higher version.
         *
         * FIXME: but this is anyway obsolete and will be removed at
         * some point.
         */

        dbg_bld("using old crappy leb_ver stuff");

        abs = v1 - v2;
        if (abs < 0)
            abs = -abs;

        if (abs < 0x7FFFFFFF)
            /* Non-overflow situation */
            second_is_newer = (v2 > v1);
        else
            second_is_newer = (v2 < v1);
    } else
        /* Obviously the LEB with lower sequence counter is older */
        second_is_newer = sqnum2 > seb->sqnum;

    /*
     * Now we know which copy is newer. If the copy flag of the PEB with
     * newer version is not set, then we just return, otherwise we have to
     * check data CRC. For the second PEB we already have the VID header,
     * for the first one - we'll need to re-read it from flash.
     *
     * FIXME: this may be optimized so that we wouldn't read twice.
     */

    if (second_is_newer) {
        if (!vid_hdr->copy_flag) {
            /* It is not a copy, so it is newer */
            dbg_bld("second PEB %d is newer, copy_flag is unset",
                    pnum);
            return 1;
        }
    } else {
        pnum = seb->pnum;

        vidh = ubi_zalloc_vid_hdr(ubi);
        if (!vidh)
            return -ENOMEM;

        err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
        if (err) {
            if (err == UBI_IO_BITFLIPS)
                bitflips = 1;
            else {
                dbg_err("VID of PEB %d header is bad, but it "
                        "was OK earlier", pnum);
                if (err > 0)
                    err = -EIO;

                goto out_free_vidh;
            }
        }

        if (!vidh->copy_flag) {
            /* It is not a copy, so it is newer */
            dbg_bld("first PEB %d is newer, copy_flag is unset",
                    pnum);
            err = bitflips << 1;
            goto out_free_vidh;
        }

        vid_hdr = vidh;
    }

    /* Read the data of the copy and check the CRC */

    len = be32_to_cpu(vid_hdr->data_size);
    buf = vmalloc(len);
    if (!buf) {
        err = -ENOMEM;
        goto out_free_vidh;
    }

    err = ubi_io_read_data(ubi, buf, pnum, 0, len);
    if (err && err != UBI_IO_BITFLIPS)
        goto out_free_buf;

    data_crc = be32_to_cpu(vid_hdr->data_crc);
    crc = crc32(UBI_CRC32_INIT, buf, len);
    if (crc != data_crc) {
        dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
                pnum, crc, data_crc);
        corrupted = 1;
        bitflips = 0;
        second_is_newer = !second_is_newer;
    } else {
        dbg_bld("PEB %d CRC is OK", pnum);
        bitflips = !!err;
    }

    vfree(buf);
    ubi_free_vid_hdr(ubi, vidh);

    if (second_is_newer)
        dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
    else
        dbg_bld("first PEB %d is newer, copy_flag is set", pnum);

    return second_is_newer | (bitflips << 1) | (corrupted << 2);

out_free_buf:
    vfree(buf);
out_free_vidh:
    ubi_free_vid_hdr(ubi, vidh);
    ubi_assert(err < 0);
    return err;
}