int __btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_root *root = BTRFS_I(inode)->root; int ret; if (trans) return do_setxattr(trans, inode, name, value, size, flags); trans = btrfs_start_transaction(root, 2); if (IS_ERR(trans)) return PTR_ERR(trans); btrfs_set_trans_block_group(trans, inode); ret = do_setxattr(trans, inode, name, value, size, flags); if (ret) goto out; inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); out: btrfs_end_transaction_throttle(trans, root); return ret; }
/* * after copy_from_user, pages need to be dirtied and we need to make * sure holes are created between the current EOF and the start of * any next extents (if required). * * this also makes the decision about creating an inline extent vs * doing real data extents, marking pages dirty and delalloc as required. */ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct file *file, struct page **pages, size_t num_pages, loff_t pos, size_t write_bytes) { int err = 0; int i; struct inode *inode = fdentry(file)->d_inode; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; u64 hint_byte; u64 num_bytes; u64 start_pos; u64 end_of_last_block; u64 end_pos = pos + write_bytes; loff_t isize = i_size_read(inode); start_pos = pos & ~((u64)root->sectorsize - 1); num_bytes = (write_bytes + pos - start_pos + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); end_of_last_block = start_pos + num_bytes - 1; lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); trans = btrfs_join_transaction(root, 1); if (!trans) { err = -ENOMEM; goto out_unlock; } btrfs_set_trans_block_group(trans, inode); hint_byte = 0; set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS); /* check for reserved extents on each page, we don't want * to reset the delalloc bit on things that already have * extents reserved. */ btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block); for (i = 0; i < num_pages; i++) { struct page *p = pages[i]; SetPageUptodate(p); ClearPageChecked(p); set_page_dirty(p); } if (end_pos > isize) { i_size_write(inode, end_pos); /* we've only changed i_size in ram, and we haven't updated * the disk i_size. There is no need to log the inode * at this time. */ } err = btrfs_end_transaction(trans, root); out_unlock: unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); return err; }
int __btrfs_setxattr(struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; struct btrfs_path *path; int ret = 0, mod = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; trans = btrfs_join_transaction(root, 1); btrfs_set_trans_block_group(trans, inode); /* first lets see if we already have this xattr */ di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name, strlen(name), -1); if (IS_ERR(di)) { ret = PTR_ERR(di); goto out; } /* ok we already have this xattr, lets remove it */ if (di) { /* if we want create only exit */ if (flags & XATTR_CREATE) { ret = -EEXIST; goto out; } ret = btrfs_delete_one_dir_name(trans, root, path, di); if (ret) goto out; btrfs_release_path(root, path); /* if we don't have a value then we are removing the xattr */ if (!value) { mod = 1; goto out; } } else { btrfs_release_path(root, path); if (flags & XATTR_REPLACE) { /* we couldn't find the attr to replace */ ret = -ENODATA; goto out; } } /* ok we have to create a completely new xattr */ ret = btrfs_insert_xattr_item(trans, root, name, strlen(name), value, size, inode->i_ino); if (ret) goto out; mod = 1; out: if (mod) { inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); } btrfs_end_transaction(trans, root); btrfs_free_path(path); return ret; }