Exemplo n.º 1
0
static struct f2fs_xattr_entry *__find_inline_xattr(struct inode *inode,
				void *base_addr, void **last_addr, int index,
				size_t len, const char *name)
{
	struct f2fs_xattr_entry *entry;
	unsigned int inline_size = inline_xattr_size(inode);

	list_for_each_xattr(entry, base_addr) {
		if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
			(void *)XATTR_NEXT_ENTRY(entry) + sizeof(__u32) >
			base_addr + inline_size) {
			*last_addr = entry;
			return NULL;
		}
		if (entry->e_name_index != index)
			continue;
		if (entry->e_name_len != len)
			continue;
		if (!memcmp(entry->e_name, name, len))
			break;
	}
	return entry;
}
Exemplo n.º 2
0
static int __f2fs_setxattr(struct inode *inode, int index,
			const char *name, const void *value, size_t size,
			struct page *ipage, int flags)
{
	struct f2fs_xattr_entry *here, *last;
	void *base_addr;
	int found, newsize;
	size_t len;
	__u32 new_hsize;
	int error = 0;

	if (name == NULL)
		return -EINVAL;

	if (value == NULL)
		size = 0;

	len = strlen(name);

	if (len > F2FS_NAME_LEN)
		return -ERANGE;

	if (size > MAX_VALUE_LEN(inode))
		return -E2BIG;

	base_addr = read_all_xattrs(inode, ipage);
	if (!base_addr)
		return -ENOMEM;

	/* find entry with wanted name. */
	here = __find_xattr(base_addr, index, len, name);

	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;

	if ((flags & XATTR_REPLACE) && !found) {
		error = -ENODATA;
		goto exit;
	} else if ((flags & XATTR_CREATE) && found) {
		error = -EEXIST;
		goto exit;
	}

	last = here;
	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);

	/* 1. Check space */
	if (value) {
		int free;
		/*
		 * If value is NULL, it is remove operation.
		 * In case of update operation, we calculate free.
		 */
		free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
		if (found)
			free = free + ENTRY_SIZE(here);

		if (unlikely(free < newsize)) {
			error = -E2BIG;
			goto exit;
		}
	}

	/* 2. Remove old entry */
	if (found) {
		/*
		 * If entry is found, remove old entry.
		 * If not found, remove operation is not needed.
		 */
		struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
		int oldsize = ENTRY_SIZE(here);

		memmove(here, next, (char *)last - (char *)next);
		last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
		memset(last, 0, oldsize);
	}

	new_hsize = (char *)last - (char *)base_addr;

	/* 3. Write new entry */
	if (value) {
		char *pval;
		/*
		 * Before we come here, old entry is removed.
		 * We just write new entry.
		 */
		last->e_name_index = index;
		last->e_name_len = len;
		memcpy(last->e_name, name, len);
		pval = last->e_name + len;
		memcpy(pval, value, size);
		last->e_value_size = cpu_to_le16(size);
		new_hsize += newsize;
	}

	error = write_all_xattrs(inode, new_hsize, base_addr, ipage);
	if (error)
		goto exit;

	if (is_inode_flag_set(inode, FI_ACL_MODE)) {
		inode->i_mode = F2FS_I(inode)->i_acl_mode;
		inode->i_ctime = CURRENT_TIME;
		clear_inode_flag(inode, FI_ACL_MODE);
	}
	if (index == F2FS_XATTR_INDEX_ENCRYPTION &&
			!strcmp(name, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT))
		f2fs_set_encrypted_inode(inode);
	f2fs_mark_inode_dirty_sync(inode);
exit:
	kzfree(base_addr);
	return error;
}
Exemplo n.º 3
0
static int __f2fs_setxattr(struct inode *inode, int name_index,
			const char *name, const void *value, size_t value_len,
			struct page *ipage)
{
	struct f2fs_inode_info *fi = F2FS_I(inode);
	struct f2fs_xattr_entry *here, *last;
	void *base_addr;
	int found, newsize;
	size_t name_len;
	__u32 new_hsize;
	int error = -ENOMEM;

	if (name == NULL)
		return -EINVAL;

	if (value == NULL)
		value_len = 0;

	name_len = strlen(name);

	if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN(inode))
		return -ERANGE;

	base_addr = read_all_xattrs(inode, ipage);
	if (!base_addr)
		goto exit;

	/* find entry with wanted name. */
	here = __find_xattr(base_addr, name_index, name_len, name);

	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
	last = here;

	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) +
			name_len + value_len);

	/* 1. Check space */
	if (value) {
		int free;
		/*
		 * If value is NULL, it is remove operation.
		 * In case of update operation, we caculate free.
		 */
		free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
		if (found)
			free = free + ENTRY_SIZE(here);

		if (unlikely(free < newsize)) {
			error = -ENOSPC;
			goto exit;
		}
	}

	/* 2. Remove old entry */
	if (found) {
		/*
		 * If entry is found, remove old entry.
		 * If not found, remove operation is not needed.
		 */
		struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
		int oldsize = ENTRY_SIZE(here);

		memmove(here, next, (char *)last - (char *)next);
		last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
		memset(last, 0, oldsize);
	}

	new_hsize = (char *)last - (char *)base_addr;

	/* 3. Write new entry */
	if (value) {
		char *pval;
		/*
		 * Before we come here, old entry is removed.
		 * We just write new entry.
		 */
		memset(last, 0, newsize);
		last->e_name_index = name_index;
		last->e_name_len = name_len;
		memcpy(last->e_name, name, name_len);
		pval = last->e_name + name_len;
		memcpy(pval, value, value_len);
		last->e_value_size = cpu_to_le16(value_len);
		new_hsize += newsize;
	}

	error = write_all_xattrs(inode, new_hsize, base_addr, ipage);
	if (error)
		goto exit;

	if (is_inode_flag_set(fi, FI_ACL_MODE)) {
		inode->i_mode = fi->i_acl_mode;
		inode->i_ctime = CURRENT_TIME;
		clear_inode_flag(fi, FI_ACL_MODE);
	}

	if (ipage)
		update_inode(inode, ipage);
	else
		update_inode_page(inode);
exit:
	kzfree(base_addr);
	return error;
}
Exemplo n.º 4
0
int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
			const void *value, size_t value_len, struct page *ipage)
{
	struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
	struct f2fs_inode_info *fi = F2FS_I(inode);
	struct f2fs_xattr_header *header = NULL;
	struct f2fs_xattr_entry *here, *last;
	struct page *page;
	void *base_addr;
	int error, found, free, newsize;
	size_t name_len;
	char *pval;
	int ilock;

	if (name == NULL)
		return -EINVAL;

	if (value == NULL)
		value_len = 0;

	name_len = strlen(name);

	if (name_len > F2FS_NAME_LEN || value_len > MAX_VALUE_LEN)
		return -ERANGE;

	f2fs_balance_fs(sbi);

	ilock = mutex_lock_op(sbi);

	if (!fi->i_xattr_nid) {
		/* Allocate new attribute block */
		struct dnode_of_data dn;

		if (!alloc_nid(sbi, &fi->i_xattr_nid)) {
			error = -ENOSPC;
			goto exit;
		}
		set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid);
		mark_inode_dirty(inode);

		page = new_node_page(&dn, XATTR_NODE_OFFSET, ipage);
		if (IS_ERR(page)) {
			alloc_nid_failed(sbi, fi->i_xattr_nid);
			fi->i_xattr_nid = 0;
			error = PTR_ERR(page);
			goto exit;
		}

		alloc_nid_done(sbi, fi->i_xattr_nid);
		base_addr = page_address(page);
		header = XATTR_HDR(base_addr);
		header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
		header->h_refcount = cpu_to_le32(1);
	} else {
		/* The inode already has an extended attribute block. */
		page = get_node_page(sbi, fi->i_xattr_nid);
		if (IS_ERR(page)) {
			error = PTR_ERR(page);
			goto exit;
		}

		base_addr = page_address(page);
		header = XATTR_HDR(base_addr);
	}

	if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
		error = -EIO;
		goto cleanup;
	}

	/* find entry with wanted name. */
	found = 0;
	list_for_each_xattr(here, base_addr) {
		if (here->e_name_index != name_index)
			continue;
		if (here->e_name_len != name_len)
			continue;
		if (!memcmp(here->e_name, name, name_len)) {
			found = 1;
			break;
		}
	}

	last = here;

	while (!IS_XATTR_LAST_ENTRY(last))
		last = XATTR_NEXT_ENTRY(last);

	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) +
			name_len + value_len);

	/* 1. Check space */
	if (value) {
		/* If value is NULL, it is remove operation.
		 * In case of update operation, we caculate free.
		 */
		free = MIN_OFFSET - ((char *)last - (char *)header);
		if (found)
			free = free - ENTRY_SIZE(here);

		if (free < newsize) {
			error = -ENOSPC;
			goto cleanup;
		}
	}

	/* 2. Remove old entry */
	if (found) {
		/* If entry is found, remove old entry.
		 * If not found, remove operation is not needed.
		 */
		struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
		int oldsize = ENTRY_SIZE(here);

		memmove(here, next, (char *)last - (char *)next);
		last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
		memset(last, 0, oldsize);
	}

	/* 3. Write new entry */
	if (value) {
		/* Before we come here, old entry is removed.
		 * We just write new entry. */
		memset(last, 0, newsize);
		last->e_name_index = name_index;
		last->e_name_len = name_len;
		memcpy(last->e_name, name, name_len);
		pval = last->e_name + name_len;
		memcpy(pval, value, value_len);
		last->e_value_size = cpu_to_le16(value_len);
	}

	set_page_dirty(page);
	f2fs_put_page(page, 1);

	if (is_inode_flag_set(fi, FI_ACL_MODE)) {
		inode->i_mode = fi->i_acl_mode;
		inode->i_ctime = CURRENT_TIME;
		clear_inode_flag(fi, FI_ACL_MODE);
	}
	if (ipage)
		update_inode(inode, ipage);
	else
		update_inode_page(inode);
	mutex_unlock_op(sbi, ilock);

	return 0;
cleanup:
	f2fs_put_page(page, 1);
exit:
	mutex_unlock_op(sbi, ilock);
	return error;
}
Exemplo n.º 5
0
static int __hmfs_setxattr(struct inode *inode, int index,
                           const char *name, const void *value, size_t size,
                           int flags)
{
    struct hmfs_xattr_entry *this, *last, *next;
    void *base_addr, *new_xattr_blk;
    int newsize, cpy_size;
    size_t name_len;
    int error = -ENOMEM;

    if (name == NULL)
        return -EINVAL;

    if (value == NULL)
        size = 0;

    name_len = strlen(name);

    if (name_len > HMFS_NAME_LEN)
        return -ERANGE;

    if (name_len + size > HMFS_XATTR_VALUE_LEN)
        return -E2BIG;

    base_addr = get_xattr_block(inode);
    if (!base_addr) {
        error = -ENODATA;
        goto out;
    }

    if (!base_addr) {
        if (flags & XATTR_CREATE)
            goto create;
        error = -ENODATA;
        goto out;
    }
    this = __find_xattr(base_addr, index, name_len, name);

    if (this->e_name_index == HMFS_XATTR_INDEX_END &&
            (flags & XATTR_REPLACE)) {
        error = -ENODATA;
        goto out;
    } else if ((flags & XATTR_CREATE) && this->e_name_index !=
               HMFS_XATTR_INDEX_END) {
        error = -EEXIST;
        goto out;
    }

    newsize = XATTR_RAW_SIZE + name_len + size;

    /* Check Space */
    if (value) {
        /* If value is NULL, it's a remove operation */
        /* Add another hmfs_xattr_entry for end entry */
        last = XATTR_ENTRY(JUMP(this, newsize + XATTR_RAW_SIZE));

        if (DISTANCE(base_addr, last) > HMFS_XATTR_BLOCK_SIZE) {
            error = -ENOSPC;
            goto out;
        }
    }

create:
    /* Allocate new xattr block */
    new_xattr_blk = alloc_new_x_block(inode, HMFS_X_BLOCK_TAG_XATTR, false);
    init_xattr_block(new_xattr_blk);

    /* Remove old entry in old xattr block */
    if (base_addr) {
        /* Copy first part */
        next = XATTR_FIRST_ENTRY(base_addr);
        cpy_size = DISTANCE(next, this);
        hmfs_memcpy(XATTR_FIRST_ENTRY(new_xattr_blk), next, cpy_size);

        /* Get last xattr in source xattr block */
        last = this;
        while (!IS_XATTR_LAST_ENTRY(last))
            last = XATTR_NEXT_ENTRY(last);

        /* Copy second part */
        next = XATTR_NEXT_ENTRY(this);
        cpy_size = DISTANCE(next, last);
        next = XATTR_ENTRY(JUMP(new_xattr_blk, DISTANCE(base_addr, this)));
        hmfs_memcpy(next, XATTR_NEXT_ENTRY(this), cpy_size);
        next = XATTR_ENTRY(JUMP(next, cpy_size));
    } else {
        next = XATTR_FIRST_ENTRY(new_xattr_blk);
    }

    /* Write new entry */
    if (value) {
        next->e_name_index = index;
        next->e_name_len = name_len;
        next->e_value_len = size;
        memcpy(next->e_name, name, name_len);
        memcpy(next->e_name + name_len, value, size);
        next = XATTR_ENTRY(next->e_name + name_len + size);
    }

    /* Write End entry */
    next->e_name_index = HMFS_XATTR_INDEX_END;
    hmfs_bug_on(HMFS_I_SB(inode), DISTANCE(new_xattr_blk,
                                           JUMP(next, XATTR_RAW_SIZE)) > HMFS_XATTR_BLOCK_SIZE);

    inode->i_ctime = CURRENT_TIME;
    mark_inode_dirty(inode);
out:
    return error;
}