static int lookup_all_xattrs(struct inode *inode, struct page *ipage, unsigned int index, unsigned int len, const char *name, struct f2fs_xattr_entry **xe, void **base_addr) { void *cur_addr, *txattr_addr, *last_addr = NULL; nid_t xnid = F2FS_I(inode)->i_xattr_nid; unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0; unsigned int inline_size = inline_xattr_size(inode); int err = 0; if (!size && !inline_size) return -ENODATA; txattr_addr = kzalloc(inline_size + size + XATTR_PADDING_SIZE, GFP_F2FS_ZERO); if (!txattr_addr) return -ENOMEM; /* read from inline xattr */ if (inline_size) { err = read_inline_xattr(inode, ipage, txattr_addr); if (err) goto out; *xe = __find_inline_xattr(inode, txattr_addr, &last_addr, index, len, name); if (*xe) goto check; } /* read from xattr node block */ if (xnid) { err = read_xattr_block(inode, txattr_addr); if (err) goto out; } if (last_addr) cur_addr = XATTR_HDR(last_addr) - 1; else cur_addr = txattr_addr; *xe = __find_xattr(cur_addr, index, len, name); check: if (IS_XATTR_LAST_ENTRY(*xe)) { err = -ENODATA; goto out; } *base_addr = txattr_addr; return 0; out: kzfree(txattr_addr); return err; }
int f2fs_getxattr(struct inode *inode, int index, const char *name, void *buffer, size_t buffer_size, struct page *ipage) { struct f2fs_xattr_entry *entry; void *base_addr; int error = 0; size_t size, len; if (name == NULL) return -EINVAL; len = strlen(name); if (len > F2FS_NAME_LEN) return -ERANGE; base_addr = read_all_xattrs(inode, ipage); if (!base_addr) return -ENOMEM; entry = __find_xattr(base_addr, index, len, name); if (IS_XATTR_LAST_ENTRY(entry)) { error = -ENODATA; goto cleanup; } size = le16_to_cpu(entry->e_value_size); if (buffer && size > buffer_size) { error = -ERANGE; goto cleanup; } if (buffer) { char *pval = entry->e_name + entry->e_name_len; memcpy(buffer, pval, size); } error = size; cleanup: kzfree(base_addr); return error; }
static int __hmfs_getxattr(struct inode *inode, int index, const char *name, void *buffer, size_t buffer_size) { struct hmfs_xattr_entry *entry; void *xattr_block; int error = 0; size_t value_len, name_len; if (name == NULL) return -EINVAL; name_len = strlen(name); if (name_len > HMFS_NAME_LEN) return -ERANGE; xattr_block = get_xattr_block(inode); if (!xattr_block) { return -ENODATA; } entry = __find_xattr(xattr_block, index, name_len, name); if (IS_XATTR_LAST_ENTRY(entry)) { error = -ENODATA; goto out; } value_len = entry->e_value_len; if (buffer && value_len > buffer_size) { error = -ERANGE; goto out; } if (buffer) { memcpy(buffer, entry->e_name + name_len, value_len); } error = value_len; out: return error; }
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; }
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; }
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; }