コード例 #1
0
ファイル: tnc_misc.c プロジェクト: CSCLOG/beaglebone
/**
 * ubifs_tnc_read_node - read a leaf node from the flash media.
 * @c: UBIFS file-system description object
 * @zbr: key and position of the node
 * @node: node is returned here
 *
 * This function reads a node defined by @zbr from the flash media. Returns
 * zero in case of success or a negative negative error code in case of
 * failure.
 */
int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
			void *node)
{
	union ubifs_key key1, *key = &zbr->key;
	int err, type = key_type(c, key);
	struct ubifs_wbuf *wbuf;

	/*
	 * 'zbr' has to point to on-flash node. The node may sit in a bud and
	 * may even be in a write buffer, so we have to take care about this.
	 */
	wbuf = ubifs_get_wbuf(c, zbr->lnum);
	if (wbuf)
		err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len,
					   zbr->lnum, zbr->offs);
	else
		err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
				      zbr->offs);

	if (err) {
		dbg_tnc("key %s", DBGKEY(key));
		return err;
	}

	/* Make sure the key of the read node is correct */
	key_read(c, node + UBIFS_KEY_OFFSET, &key1);
	if (!keys_eq(c, key, &key1)) {
		ubifs_err("bad key in node at LEB %d:%d",
			  zbr->lnum, zbr->offs);
		dbg_tnc("looked for key %s found node's key %s",
			DBGKEY(key), DBGKEY1(&key1));
		dbg_dump_node(c, node);
		return -EINVAL;
	}

	return 0;
}
コード例 #2
0
ファイル: journal.c プロジェクト: heroistired/jzcode-x11
/**
 * ubifs_jnl_truncate - update the journal for a truncation.
 * @c: UBIFS file-system description object
 * @inum: inode number of inode being truncated
 * @old_size: old size
 * @new_size: new size
 *
 * When the size of a file decreases due to truncation, a truncation node is
 * written, the journal tree is updated, and the last data block is re-written
 * if it has been affected.
 *
 * This function returns %0 in the case of success, and a negative error code in
 * case of failure.
 */
int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum,
                       loff_t old_size, loff_t new_size)
{
    union ubifs_key key, to_key;
    struct ubifs_trun_node *trun;
    struct ubifs_data_node *uninitialized_var(dn);
    int err, dlen, len, lnum, offs, bit, sz;
    unsigned int blk;

    dbg_jnl("ino %lu, size %lld -> %lld", inum, old_size, new_size);

    sz = UBIFS_TRUN_NODE_SZ + UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR;
    trun = kmalloc(sz, GFP_NOFS);
    if (!trun)
        return -ENOMEM;

    trun->ch.node_type = UBIFS_TRUN_NODE;
    trun_key_init_flash(c, &trun->key, inum);
    trun->old_size = cpu_to_le64(old_size);
    trun->new_size = cpu_to_le64(new_size);

    dlen = new_size & (UBIFS_BLOCK_SIZE - 1);

    if (dlen) {
        /* Get last data block so it can be truncated */
        dn = (void *)trun + ALIGN(UBIFS_TRUN_NODE_SZ, 8);
        blk = new_size / UBIFS_BLOCK_SIZE;
        data_key_init(c, &key, inum, blk);
        dbg_jnl("last block key %s", DBGKEY(&key));
        err = ubifs_tnc_lookup(c, &key, dn);
        if (err == -ENOENT)
            dlen = 0; /* Not found (so it is a hole) */
        else if (err)
            goto out_free;
        else {
            if (le32_to_cpu(dn->size) <= dlen)
                dlen = 0; /* Nothing to do */
            else {
                int compr_type = le16_to_cpu(dn->compr_type);

                if (compr_type != UBIFS_COMPR_NONE) {
                    err = recomp_data_node(dn, &dlen);
                    if (err)
                        goto out_free;
                } else {
                    dn->size = cpu_to_le32(dlen);
                    dlen += UBIFS_DATA_NODE_SZ;
                }
                zero_data_node_unused(dn);
            }
        }
    }

    if (dlen)
        len = ALIGN(UBIFS_TRUN_NODE_SZ, 8) + dlen;
    else
        len = UBIFS_TRUN_NODE_SZ;

    /* Must make reservation before allocating sequence numbers */
    err = make_reservation(c, BASEHD, len);
    if (err)
        goto out_free;

    ubifs_prepare_node(c, trun, UBIFS_TRUN_NODE_SZ, 0);
    if (dlen)
        ubifs_prepare_node(c, dn, dlen, 0);

    err = write_head(c, BASEHD, trun, len, &lnum, &offs, 0);
    if (!err)
        ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum);
    release_head(c, BASEHD);
    if (err)
        goto out_ro;

    if (dlen) {
        offs += ALIGN(UBIFS_TRUN_NODE_SZ, 8);
        err = ubifs_tnc_add(c, &key, lnum, offs, dlen);
        if (err)
            goto out_ro;
    }

    err = ubifs_add_dirt(c, lnum, UBIFS_TRUN_NODE_SZ);
    if (err)
        goto out_ro;

    bit = new_size & (UBIFS_BLOCK_SIZE - 1);

    blk = new_size / UBIFS_BLOCK_SIZE + (bit ? 1 : 0);
    data_key_init(c, &key, inum, blk);

    bit = old_size & (UBIFS_BLOCK_SIZE - 1);

    blk = old_size / UBIFS_BLOCK_SIZE - (bit ? 0: 1);
    data_key_init(c, &to_key, inum, blk);

    err = ubifs_tnc_remove_range(c, &key, &to_key);
    if (err)
        goto out_ro;

    finish_reservation(c);
    kfree(trun);
    return 0;

out_ro:
    ubifs_ro_mode(c, err);
    finish_reservation(c);
out_free:
    kfree(trun);
    return err;
}
コード例 #3
0
ファイル: tnc_misc.c プロジェクト: CSCLOG/beaglebone
/**
 * read_znode - read an indexing node from flash and fill znode.
 * @c: UBIFS file-system description object
 * @lnum: LEB of the indexing node to read
 * @offs: node offset
 * @len: node length
 * @znode: znode to read to
 *
 * This function reads an indexing node from the flash media and fills znode
 * with the read data. Returns zero in case of success and a negative error
 * code in case of failure. The read indexing node is validated and if anything
 * is wrong with it, this function prints complaint messages and returns
 * %-EINVAL.
 */
static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
		      struct ubifs_znode *znode)
{
	int i, err, type, cmp;
	struct ubifs_idx_node *idx;

	idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
	if (!idx)
		return -ENOMEM;

	err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
	if (err < 0) {
		kfree(idx);
		return err;
	}

	znode->child_cnt = le16_to_cpu(idx->child_cnt);
	znode->level = le16_to_cpu(idx->level);

	dbg_tnc("LEB %d:%d, level %d, %d branch",
		lnum, offs, znode->level, znode->child_cnt);

	if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
		dbg_err("current fanout %d, branch count %d",
			c->fanout, znode->child_cnt);
		dbg_err("max levels %d, znode level %d",
			UBIFS_MAX_LEVELS, znode->level);
		err = 1;
		goto out_dump;
	}

	for (i = 0; i < znode->child_cnt; i++) {
		const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
		struct ubifs_zbranch *zbr = &znode->zbranch[i];

		key_read(c, &br->key, &zbr->key);
		zbr->lnum = le32_to_cpu(br->lnum);
		zbr->offs = le32_to_cpu(br->offs);
		zbr->len  = le32_to_cpu(br->len);
		zbr->znode = NULL;

		/* Validate branch */

		if (zbr->lnum < c->main_first ||
		    zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
		    zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
			dbg_err("bad branch %d", i);
			err = 2;
			goto out_dump;
		}

		switch (key_type(c, &zbr->key)) {
		case UBIFS_INO_KEY:
		case UBIFS_DATA_KEY:
		case UBIFS_DENT_KEY:
		case UBIFS_XENT_KEY:
			break;
		default:
			dbg_msg("bad key type at slot %d: %s", i,
				DBGKEY(&zbr->key));
			err = 3;
			goto out_dump;
		}

		if (znode->level)
			continue;

		type = key_type(c, &zbr->key);
		if (c->ranges[type].max_len == 0) {
			if (zbr->len != c->ranges[type].len) {
				dbg_err("bad target node (type %d) length (%d)",
					type, zbr->len);
				dbg_err("have to be %d", c->ranges[type].len);
				err = 4;
				goto out_dump;
			}
		} else if (zbr->len < c->ranges[type].min_len ||
			   zbr->len > c->ranges[type].max_len) {
			dbg_err("bad target node (type %d) length (%d)",
				type, zbr->len);
			dbg_err("have to be in range of %d-%d",
				c->ranges[type].min_len,
				c->ranges[type].max_len);
			err = 5;
			goto out_dump;
		}
	}

	/*
	 * Ensure that the next key is greater or equivalent to the
	 * previous one.
	 */
	for (i = 0; i < znode->child_cnt - 1; i++) {
		const union ubifs_key *key1, *key2;

		key1 = &znode->zbranch[i].key;
		key2 = &znode->zbranch[i + 1].key;

		cmp = keys_cmp(c, key1, key2);
		if (cmp > 0) {
			dbg_err("bad key order (keys %d and %d)", i, i + 1);
			err = 6;
			goto out_dump;
		} else if (cmp == 0 && !is_hash_key(c, key1)) {
			/* These can only be keys with colliding hash */
			dbg_err("keys %d and %d are not hashed but equivalent",
				i, i + 1);
			err = 7;
			goto out_dump;
		}
	}

	kfree(idx);
	return 0;

out_dump:
	ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
	dbg_dump_node(c, idx);
	kfree(idx);
	return -EINVAL;
}
コード例 #4
0
ファイル: journal.c プロジェクト: heroistired/jzcode-x11
/**
 * ubifs_jnl_write_data - write a data node to the journal.
 * @c: UBIFS file-system description object
 * @inode: inode the data node belongs to
 * @key: node key
 * @buf: buffer to write
 * @len: data length (must not exceed %UBIFS_BLOCK_SIZE)
 *
 * This function writes a data node to the journal. Returns %0 if the data node
 * was successfully written, and a negative error code in case of failure.
 */
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
                         const union ubifs_key *key, const void *buf, int len)
{
    int err, lnum, offs, compr_type, out_len;
    int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR;
    const struct ubifs_inode *ui = ubifs_inode(inode);
    struct ubifs_data_node *data;

    dbg_jnl("ino %lu, blk %u, len %d, key %s", key_ino(c, key),
            key_block(c, key), len, DBGKEY(key));
    ubifs_assert(len <= UBIFS_BLOCK_SIZE);

    data = kmalloc(dlen, GFP_NOFS);
    if (!data)
        return -ENOMEM;

    data->ch.node_type = UBIFS_DATA_NODE;
    key_write(c, key, &data->key);
    data->size = cpu_to_le32(len);
    zero_data_node_unused(data);

    if (!(ui->flags && UBIFS_COMPR_FL))
        /* Compression is disabled for this inode */
        compr_type = UBIFS_COMPR_NONE;
    else
        compr_type = ui->compr_type;

    out_len = dlen - UBIFS_DATA_NODE_SZ;
    ubifs_compress(buf, len, &data->data, &out_len, &compr_type);
    ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);

    dlen = UBIFS_DATA_NODE_SZ + out_len;
    data->compr_type = cpu_to_le16(compr_type);

    /* Make reservation before allocating sequence numbers */
    err = make_reservation(c, DATAHD, dlen);
    if (err)
        goto out_free;

    err = write_node(c, DATAHD, data, dlen, &lnum, &offs);
    if (!err)
        ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf,
                                  key_ino(c, key));
    release_head(c, DATAHD);
    if (err)
        goto out_ro;

    err = ubifs_tnc_add(c, key, lnum, offs, dlen);
    if (err)
        goto out_ro;

    finish_reservation(c);
    kfree(data);
    return 0;

out_ro:
    ubifs_ro_mode(c, err);
    finish_reservation(c);
out_free:
    kfree(data);
    return err;
}