コード例 #1
0
ファイル: ubifs.c プロジェクト: dhs-shine/sprd_project
static int read_block(struct inode *inode, void *addr, unsigned int block,
		      struct ubifs_data_node *dn)
{
	struct ubifs_info *c = inode->i_sb->s_fs_info;
	int err, len, out_len;
	union ubifs_key key;
	unsigned int dlen;

	data_key_init(c, &key, inode->i_ino, block);
	err = ubifs_tnc_lookup(c, &key, dn);
	if (err) {
		if (err == -ENOENT)
			/* Not found, so it must be a hole */
			memset(addr, 0, UBIFS_BLOCK_SIZE);
		return err;
	}

	ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);

	len = le32_to_cpu(dn->size);
	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
		goto dump;

	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
	out_len = UBIFS_BLOCK_SIZE;
	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
			       le16_to_cpu(dn->compr_type));
	if (err || len != out_len)
		goto dump;

	/*
	 * Data length can be less than a full block, even for blocks that are
	 * not the last in the file (e.g., as a result of making a hole and
	 * appending data). Ensure that the remainder is zeroed out.
	 */
	if (len < UBIFS_BLOCK_SIZE)
		memset(addr + len, 0, UBIFS_BLOCK_SIZE - len);

	return 0;

dump:
	ubifs_err("bad data node (block %u, inode %lu)",
		  block, inode->i_ino);
	dbg_dump_node(c, dn);
	return -EINVAL;
}
コード例 #2
0
/**
 * ubifs_jrn_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_jrn_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 *dn;
	int err, dlen, len, lnum, offs, bit, sz;
	unsigned int blk;

	dbg_jrn("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);
	ubifs_prepare_node(c, trun, UBIFS_TRUN_NODE_SZ, 0);

	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_jrn_key(c, &key, "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);
				ubifs_prepare_node(c, dn, dlen, 0);
			}
		}
	}

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

	err = make_reservation(c, BASEHD, len);
	if (err)
		goto out_free;

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