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; }
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; }
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 struct export_node * AddEntryToNode(struct export_node *node, struct export_entry *entry) { struct export_node *retval = NULL; size_t indx; /* * If entry->network_count is 0, this is a default entry. * We need to see if there is already a default entry. */ if (entry->network_count == 0) { // Default entry, but let's see if the node already has one if (node->default_export.export_path) { errno = EEXIST; } else { node->default_export = *entry; retval = node; } goto done; } /* * Next thing we can do is see if this is just adding another * network_entry to the export_entry list. To do that, we check * all of the export entries, and compare the values. * This also will check to see if the network/mask is already on * the list, and do nothing in that case. */ for (indx = 0; indx < node->export_count; indx++) { struct export_entry *ep = node->exports[indx]; if (strcmp(entry->export_path, ep->export_path) == 0 && entry->export_flags == ep->export_flags && entry->args.ex_flags == ep->args.ex_flags && entry->args.ex_root == ep->args.ex_root && memcmp(&entry->args.ex_anon, &ep->args.ex_anon, sizeof(ep->args.ex_anon)) == 0) { /* * We want to merge entry, into ep. * To do this, we iterate through entry->exports, and compare each * entry to ep->exports. Note that when we realloc, we need * change node->exports[indx] * * You know, for now, let's just add them all. */ size_t new_size; size_t new_index; new_size = ENTRY_SIZE(entry) + entry->network_count * sizeof(struct network_entry); ep = realloc(ep, new_size); if (ep == NULL) { warn("Could not add new entries to node, sorry"); out_of_mem(); } node->exports[indx] = ep; for (new_index = 0; new_index < entry->network_count; new_index++) { ep->entries[ep->network_count++] = entry->entries[new_index]; } free(entry); return node; } } retval = realloc(node, NODE_SIZE(node) + ENTRY_SIZE(entry)); if (retval == NULL) { errno = ENOMEM; goto done; } node = retval; node->exports[node->export_count] = entry; node->export_count++; done: return retval; }