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); 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(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; }
static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, u64 num_items, int type) { struct btrfs_trans_handle *h; struct btrfs_transaction *cur_trans; int retries = 0; int ret; again: h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); if (!h) return ERR_PTR(-ENOMEM); mutex_lock(&root->fs_info->trans_mutex); if (may_wait_transaction(root, type)) wait_current_trans(root); ret = join_transaction(root); BUG_ON(ret); cur_trans = root->fs_info->running_transaction; cur_trans->use_count++; mutex_unlock(&root->fs_info->trans_mutex); h->transid = cur_trans->transid; h->transaction = cur_trans; h->blocks_used = 0; h->block_group = 0; h->bytes_reserved = 0; h->delayed_ref_updates = 0; h->block_rsv = NULL; smp_mb(); if (cur_trans->blocked && may_wait_transaction(root, type)) { btrfs_commit_transaction(h, root); goto again; } if (num_items > 0) { ret = btrfs_trans_reserve_metadata(h, root, num_items, &retries); if (ret == -EAGAIN) { btrfs_commit_transaction(h, root); goto again; } if (ret < 0) { btrfs_end_transaction(h, root); return ERR_PTR(ret); } } mutex_lock(&root->fs_info->trans_mutex); record_root_in_trans(h, root); mutex_unlock(&root->fs_info->trans_mutex); if (!current->journal_info && type != TRANS_USERSPACE) current->journal_info = h; return h; }
int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) { struct btrfs_trans_handle *trans; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *free_space_root; struct btrfs_block_group_cache *block_group; struct rb_node *node; int ret; trans = btrfs_start_transaction(tree_root, 0); if (IS_ERR(trans)) return PTR_ERR(trans); fs_info->creating_free_space_tree = 1; free_space_root = btrfs_create_tree(trans, fs_info, BTRFS_FREE_SPACE_TREE_OBJECTID); if (IS_ERR(free_space_root)) { ret = PTR_ERR(free_space_root); goto abort; } fs_info->free_space_root = free_space_root; node = rb_first(&fs_info->block_group_cache_tree); while (node) { block_group = rb_entry(node, struct btrfs_block_group_cache, cache_node); ret = populate_free_space_tree(trans, fs_info, block_group); if (ret) goto abort; node = rb_next(node); } btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); fs_info->creating_free_space_tree = 0; ret = btrfs_commit_transaction(trans, tree_root); if (ret) return ret; return 0; abort: fs_info->creating_free_space_tree = 0; btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans, tree_root); return ret; }
static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info, struct btrfs_pending_snapshot *pending) { int ret; int namelen; u64 index = 0; struct btrfs_trans_handle *trans; struct inode *parent_inode; struct inode *inode; struct btrfs_root *parent_root; parent_inode = pending->dentry->d_parent->d_inode; parent_root = BTRFS_I(parent_inode)->root; trans = btrfs_join_transaction(parent_root, 1); /* * insert the directory item */ namelen = strlen(pending->name); ret = btrfs_set_inode_index(parent_inode, &index); ret = btrfs_insert_dir_item(trans, parent_root, pending->name, namelen, parent_inode->i_ino, &pending->root_key, BTRFS_FT_DIR, index); if (ret) goto fail; btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); ret = btrfs_update_inode(trans, parent_root, parent_inode); BUG_ON(ret); ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, pending->root_key.objectid, parent_root->root_key.objectid, parent_inode->i_ino, index, pending->name, namelen); BUG_ON(ret); inode = btrfs_lookup_dentry(parent_inode, pending->dentry); d_instantiate(pending->dentry, inode); fail: btrfs_end_transaction(trans, fs_info->fs_root); return ret; }
int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) { struct btrfs_trans_handle *trans; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *free_space_root = fs_info->free_space_root; int ret; trans = btrfs_start_transaction(tree_root, 0); if (IS_ERR(trans)) return PTR_ERR(trans); btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); fs_info->free_space_root = NULL; ret = clear_free_space_tree(trans, free_space_root); if (ret) goto abort; ret = btrfs_del_root(trans, tree_root, &free_space_root->root_key); if (ret) goto abort; list_del(&free_space_root->dirty_list); btrfs_tree_lock(free_space_root->node); clean_tree_block(trans, tree_root->fs_info, free_space_root->node); btrfs_tree_unlock(free_space_root->node); btrfs_free_tree_block(trans, free_space_root, free_space_root->node, 0, 1); free_extent_buffer(free_space_root->node); free_extent_buffer(free_space_root->commit_root); kfree(free_space_root); ret = btrfs_commit_transaction(trans, tree_root); if (ret) return ret; return 0; abort: btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans, tree_root); return ret; }
static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type, u64 subid) { struct btrfs_trans_handle *trans; int ret; /* 1 - for the uuid item */ trans = btrfs_start_transaction(uuid_root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } ret = btrfs_uuid_tree_remove(trans, uuid, type, subid); btrfs_end_transaction(trans); out: return ret; }
static int generic_search(struct inode *inode, u64 file_pos, struct btrfs_dedup_hash *hash) { int ret; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_trans_handle *trans; struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_head *head; struct btrfs_dedup_info *dedup_info = fs_info->dedup_info; u64 bytenr; u64 tmp_bytenr; u32 num_bytes; trans = btrfs_join_transaction(root); if (IS_ERR(trans)) return PTR_ERR(trans); again: mutex_lock(&dedup_info->lock); ret = generic_search_hash(dedup_info, hash->hash, &bytenr, &num_bytes); if (ret <= 0) goto out; delayed_refs = &trans->transaction->delayed_refs; spin_lock(&delayed_refs->lock); head = btrfs_find_delayed_ref_head(trans, bytenr); if (!head) { /* * We can safely insert a new delayed_ref as long as we * hold delayed_refs->lock. * Only need to use atomic inc_extent_ref() */ ret = btrfs_inc_extent_ref_atomic(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, btrfs_ino(inode), file_pos); spin_unlock(&delayed_refs->lock); if (ret == 0) { hash->bytenr = bytenr; hash->num_bytes = num_bytes; ret = 1; } goto out; } /* * We can't lock ref head with dedup_info->lock hold or we will cause * ABBA dead lock. */ mutex_unlock(&dedup_info->lock); ret = btrfs_delayed_ref_lock(trans, head); spin_unlock(&delayed_refs->lock); if (ret == -EAGAIN) goto again; mutex_lock(&dedup_info->lock); /* * Search again to ensure the hash is still here and bytenr didn't * change */ ret = generic_search_hash(dedup_info, hash->hash, &tmp_bytenr, &num_bytes); if (ret <= 0) { mutex_unlock(&head->mutex); goto out; } if (tmp_bytenr != bytenr) { mutex_unlock(&head->mutex); mutex_unlock(&dedup_info->lock); goto again; } hash->bytenr = bytenr; hash->num_bytes = num_bytes; /* * Increase the extent ref right now, to avoid delayed ref run * Or we may increase ref on non-exist extent. */ btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, root->root_key.objectid, btrfs_ino(inode), file_pos); mutex_unlock(&head->mutex); out: mutex_unlock(&dedup_info->lock); btrfs_end_transaction(trans, root); return ret; }
static int btrfs_ioctl_setflags(struct file *file, void __user *arg) { struct inode *inode = file->f_path.dentry->d_inode; struct btrfs_inode *ip = BTRFS_I(inode); struct btrfs_root *root = ip->root; struct btrfs_trans_handle *trans; unsigned int flags, oldflags; int ret; if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL | FS_DIRSYNC_FL)) return -EOPNOTSUPP; if (!is_owner_or_cap(inode)) return -EACCES; mutex_lock(&inode->i_mutex); flags = btrfs_mask_flags(inode->i_mode, flags); oldflags = btrfs_flags_to_ioctl(ip->flags); if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { if (!capable(CAP_LINUX_IMMUTABLE)) { ret = -EPERM; goto out_unlock; } } ret = mnt_want_write(file->f_path.mnt); if (ret) goto out_unlock; if (flags & FS_SYNC_FL) ip->flags |= BTRFS_INODE_SYNC; else ip->flags &= ~BTRFS_INODE_SYNC; if (flags & FS_IMMUTABLE_FL) ip->flags |= BTRFS_INODE_IMMUTABLE; else ip->flags &= ~BTRFS_INODE_IMMUTABLE; if (flags & FS_APPEND_FL) ip->flags |= BTRFS_INODE_APPEND; else ip->flags &= ~BTRFS_INODE_APPEND; if (flags & FS_NODUMP_FL) ip->flags |= BTRFS_INODE_NODUMP; else ip->flags &= ~BTRFS_INODE_NODUMP; if (flags & FS_NOATIME_FL) ip->flags |= BTRFS_INODE_NOATIME; else ip->flags &= ~BTRFS_INODE_NOATIME; if (flags & FS_DIRSYNC_FL) ip->flags |= BTRFS_INODE_DIRSYNC; else ip->flags &= ~BTRFS_INODE_DIRSYNC; trans = btrfs_join_transaction(root, 1); BUG_ON(!trans); ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); btrfs_update_iflags(inode); inode->i_ctime = CURRENT_TIME; btrfs_end_transaction(trans, root); mnt_drop_write(file->f_path.mnt); out_unlock: mutex_unlock(&inode->i_mutex); return 0; }
/* * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on * all of them */ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, struct list_head *list) { struct btrfs_dirty_root *dirty; struct btrfs_trans_handle *trans; unsigned long nr; u64 num_bytes; u64 bytes_used; u64 max_useless; int ret = 0; int err; while (!list_empty(list)) { struct btrfs_root *root; dirty = list_entry(list->prev, struct btrfs_dirty_root, list); list_del_init(&dirty->list); num_bytes = btrfs_root_used(&dirty->root->root_item); root = dirty->latest_root; atomic_inc(&root->fs_info->throttles); while (1) { /* * we don't want to jump in and create a bunch of * delayed refs if the transaction is starting to close */ wait_transaction_pre_flush(tree_root->fs_info); trans = btrfs_start_transaction(tree_root, 1); /* * we've joined a transaction, make sure it isn't * closing right now */ if (trans->transaction->delayed_refs.flushing) { btrfs_end_transaction(trans, tree_root); continue; } mutex_lock(&root->fs_info->drop_mutex); ret = btrfs_drop_snapshot(trans, dirty->root); if (ret != -EAGAIN) break; mutex_unlock(&root->fs_info->drop_mutex); err = btrfs_update_root(trans, tree_root, &dirty->root->root_key, &dirty->root->root_item); if (err) ret = err; nr = trans->blocks_used; ret = btrfs_end_transaction(trans, tree_root); BUG_ON(ret); btrfs_btree_balance_dirty(tree_root, nr); cond_resched(); } BUG_ON(ret); atomic_dec(&root->fs_info->throttles); wake_up(&root->fs_info->transaction_throttle); num_bytes -= btrfs_root_used(&dirty->root->root_item); bytes_used = btrfs_root_used(&root->root_item); if (num_bytes) { mutex_lock(&root->fs_info->trans_mutex); btrfs_record_root_in_trans(root); mutex_unlock(&root->fs_info->trans_mutex); btrfs_set_root_used(&root->root_item, bytes_used - num_bytes); } ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key); if (ret) { BUG(); break; } mutex_unlock(&root->fs_info->drop_mutex); spin_lock(&root->list_lock); list_del_init(&dirty->root->dead_list); if (!list_empty(&root->dead_list)) { struct btrfs_root *oldest; oldest = list_entry(root->dead_list.prev, struct btrfs_root, dead_list); max_useless = oldest->root_key.offset - 1; } else { max_useless = root->root_key.offset - 1; } spin_unlock(&root->list_lock); nr = trans->blocks_used; ret = btrfs_end_transaction(trans, tree_root); BUG_ON(ret); ret = btrfs_remove_leaf_refs(root, max_useless, 0); BUG_ON(ret); free_extent_buffer(dirty->root->node); kfree(dirty->root); kfree(dirty); btrfs_btree_balance_dirty(tree_root, nr); cond_resched(); }
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; }
/* * calls iterate() for every inode that references the extent identified by * the given parameters. * when the iterator function returns a non-zero value, iteration stops. */ int iterate_extent_inodes(struct btrfs_fs_info *fs_info, u64 extent_item_objectid, u64 extent_item_pos, int search_commit_root, iterate_extent_inodes_t *iterate, void *ctx) { int ret; struct btrfs_trans_handle *trans = NULL; struct ulist *refs = NULL; struct ulist *roots = NULL; struct ulist_node *ref_node = NULL; struct ulist_node *root_node = NULL; struct seq_list tree_mod_seq_elem = {}; struct ulist_iterator ref_uiter; struct ulist_iterator root_uiter; pr_debug("resolving all inodes for extent %llu\n", extent_item_objectid); if (!search_commit_root) { trans = btrfs_join_transaction(fs_info->extent_root); if (IS_ERR(trans)) return PTR_ERR(trans); btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); } else { down_read(&fs_info->commit_root_sem); } ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, tree_mod_seq_elem.seq, &refs, &extent_item_pos); if (ret) goto out; ULIST_ITER_INIT(&ref_uiter); while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val, tree_mod_seq_elem.seq, &roots); if (ret) break; ULIST_ITER_INIT(&root_uiter); while (!ret && (root_node = ulist_next(roots, &root_uiter))) { pr_debug("root %llu references leaf %llu, data list " "%#llx\n", root_node->val, ref_node->val, ref_node->aux); ret = iterate_leaf_refs((struct extent_inode_elem *) (uintptr_t)ref_node->aux, root_node->val, extent_item_objectid, iterate, ctx); } ulist_free(roots); } free_leaf_list(refs); out: if (!search_commit_root) { btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); btrfs_end_transaction(trans, fs_info->extent_root); } else { up_read(&fs_info->commit_root_sem); } return ret; }