diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:48:46 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:50 -0400 |
commit | a22285a6a32390195235171b89d157ed1a1fe932 (patch) | |
tree | 3fabc88a029e1af4f2fdcc708e7b62ef3cf3703a /fs/btrfs/transaction.c | |
parent | f0486c68e4bd9a06a5904d3eeb3a0d73a83befb8 (diff) |
Btrfs: Integrate metadata reservation with start_transaction
Besides simplify the code, this change makes sure all metadata
reservation for normal metadata operations are released after
committing transaction.
Changes since V1:
Add code that check if unlink and rmdir will free space.
Add ENOSPC handling for clone ioctl.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 131 |
1 files changed, 90 insertions, 41 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 21ad37c05199..2616491a5c5b 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -165,53 +165,89 @@ enum btrfs_trans_type { | |||
165 | TRANS_USERSPACE, | 165 | TRANS_USERSPACE, |
166 | }; | 166 | }; |
167 | 167 | ||
168 | static int may_wait_transaction(struct btrfs_root *root, int type) | ||
169 | { | ||
170 | if (!root->fs_info->log_root_recovering && | ||
171 | ((type == TRANS_START && !root->fs_info->open_ioctl_trans) || | ||
172 | type == TRANS_USERSPACE)) | ||
173 | return 1; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
168 | static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, | 177 | static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, |
169 | int num_blocks, int type) | 178 | u64 num_items, int type) |
170 | { | 179 | { |
171 | struct btrfs_trans_handle *h = | 180 | struct btrfs_trans_handle *h; |
172 | kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | 181 | struct btrfs_transaction *cur_trans; |
182 | int retries = 0; | ||
173 | int ret; | 183 | int ret; |
184 | again: | ||
185 | h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); | ||
186 | if (!h) | ||
187 | return ERR_PTR(-ENOMEM); | ||
174 | 188 | ||
175 | mutex_lock(&root->fs_info->trans_mutex); | 189 | mutex_lock(&root->fs_info->trans_mutex); |
176 | if (!root->fs_info->log_root_recovering && | 190 | if (may_wait_transaction(root, type)) |
177 | ((type == TRANS_START && !root->fs_info->open_ioctl_trans) || | ||
178 | type == TRANS_USERSPACE)) | ||
179 | wait_current_trans(root); | 191 | wait_current_trans(root); |
192 | |||
180 | ret = join_transaction(root); | 193 | ret = join_transaction(root); |
181 | BUG_ON(ret); | 194 | BUG_ON(ret); |
182 | 195 | ||
183 | h->transid = root->fs_info->running_transaction->transid; | 196 | cur_trans = root->fs_info->running_transaction; |
184 | h->transaction = root->fs_info->running_transaction; | 197 | cur_trans->use_count++; |
185 | h->blocks_reserved = num_blocks; | 198 | mutex_unlock(&root->fs_info->trans_mutex); |
199 | |||
200 | h->transid = cur_trans->transid; | ||
201 | h->transaction = cur_trans; | ||
186 | h->blocks_used = 0; | 202 | h->blocks_used = 0; |
187 | h->block_group = 0; | 203 | h->block_group = 0; |
204 | h->bytes_reserved = 0; | ||
188 | h->delayed_ref_updates = 0; | 205 | h->delayed_ref_updates = 0; |
189 | h->block_rsv = NULL; | 206 | h->block_rsv = NULL; |
190 | 207 | ||
191 | if (!current->journal_info && type != TRANS_USERSPACE) | 208 | smp_mb(); |
192 | current->journal_info = h; | 209 | if (cur_trans->blocked && may_wait_transaction(root, type)) { |
210 | btrfs_commit_transaction(h, root); | ||
211 | goto again; | ||
212 | } | ||
213 | |||
214 | if (num_items > 0) { | ||
215 | ret = btrfs_trans_reserve_metadata(h, root, num_items, | ||
216 | &retries); | ||
217 | if (ret == -EAGAIN) { | ||
218 | btrfs_commit_transaction(h, root); | ||
219 | goto again; | ||
220 | } | ||
221 | if (ret < 0) { | ||
222 | btrfs_end_transaction(h, root); | ||
223 | return ERR_PTR(ret); | ||
224 | } | ||
225 | } | ||
193 | 226 | ||
194 | root->fs_info->running_transaction->use_count++; | 227 | mutex_lock(&root->fs_info->trans_mutex); |
195 | record_root_in_trans(h, root); | 228 | record_root_in_trans(h, root); |
196 | mutex_unlock(&root->fs_info->trans_mutex); | 229 | mutex_unlock(&root->fs_info->trans_mutex); |
230 | |||
231 | if (!current->journal_info && type != TRANS_USERSPACE) | ||
232 | current->journal_info = h; | ||
197 | return h; | 233 | return h; |
198 | } | 234 | } |
199 | 235 | ||
200 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | 236 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, |
201 | int num_blocks) | 237 | int num_items) |
202 | { | 238 | { |
203 | return start_transaction(root, num_blocks, TRANS_START); | 239 | return start_transaction(root, num_items, TRANS_START); |
204 | } | 240 | } |
205 | struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root, | 241 | struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root, |
206 | int num_blocks) | 242 | int num_blocks) |
207 | { | 243 | { |
208 | return start_transaction(root, num_blocks, TRANS_JOIN); | 244 | return start_transaction(root, 0, TRANS_JOIN); |
209 | } | 245 | } |
210 | 246 | ||
211 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, | 247 | struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r, |
212 | int num_blocks) | 248 | int num_blocks) |
213 | { | 249 | { |
214 | return start_transaction(r, num_blocks, TRANS_USERSPACE); | 250 | return start_transaction(r, 0, TRANS_USERSPACE); |
215 | } | 251 | } |
216 | 252 | ||
217 | /* wait for a transaction commit to be fully complete */ | 253 | /* wait for a transaction commit to be fully complete */ |
@@ -312,6 +348,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
312 | count++; | 348 | count++; |
313 | } | 349 | } |
314 | 350 | ||
351 | btrfs_trans_release_metadata(trans, root); | ||
352 | |||
315 | mutex_lock(&info->trans_mutex); | 353 | mutex_lock(&info->trans_mutex); |
316 | cur_trans = info->running_transaction; | 354 | cur_trans = info->running_transaction; |
317 | WARN_ON(cur_trans != trans->transaction); | 355 | WARN_ON(cur_trans != trans->transaction); |
@@ -757,47 +795,49 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
757 | struct btrfs_root *root = pending->root; | 795 | struct btrfs_root *root = pending->root; |
758 | struct btrfs_root *parent_root; | 796 | struct btrfs_root *parent_root; |
759 | struct inode *parent_inode; | 797 | struct inode *parent_inode; |
798 | struct dentry *dentry; | ||
760 | struct extent_buffer *tmp; | 799 | struct extent_buffer *tmp; |
761 | struct extent_buffer *old; | 800 | struct extent_buffer *old; |
762 | int ret; | 801 | int ret; |
763 | u64 objectid; | ||
764 | int namelen; | ||
765 | u64 index = 0; | 802 | u64 index = 0; |
766 | 803 | u64 objectid; | |
767 | parent_inode = pending->dentry->d_parent->d_inode; | ||
768 | parent_root = BTRFS_I(parent_inode)->root; | ||
769 | 804 | ||
770 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 805 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
771 | if (!new_root_item) { | 806 | if (!new_root_item) { |
772 | ret = -ENOMEM; | 807 | pending->error = -ENOMEM; |
773 | goto fail; | 808 | goto fail; |
774 | } | 809 | } |
810 | |||
775 | ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid); | 811 | ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid); |
776 | if (ret) | 812 | if (ret) { |
813 | pending->error = ret; | ||
777 | goto fail; | 814 | goto fail; |
815 | } | ||
778 | 816 | ||
779 | key.objectid = objectid; | 817 | key.objectid = objectid; |
780 | /* record when the snapshot was created in key.offset */ | 818 | key.offset = (u64)-1; |
781 | key.offset = trans->transid; | 819 | key.type = BTRFS_ROOT_ITEM_KEY; |
782 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||
783 | 820 | ||
784 | memcpy(&pending->root_key, &key, sizeof(key)); | 821 | trans->block_rsv = &pending->block_rsv; |
785 | pending->root_key.offset = (u64)-1; | ||
786 | 822 | ||
823 | dentry = pending->dentry; | ||
824 | parent_inode = dentry->d_parent->d_inode; | ||
825 | parent_root = BTRFS_I(parent_inode)->root; | ||
787 | record_root_in_trans(trans, parent_root); | 826 | record_root_in_trans(trans, parent_root); |
827 | |||
788 | /* | 828 | /* |
789 | * insert the directory item | 829 | * insert the directory item |
790 | */ | 830 | */ |
791 | namelen = strlen(pending->name); | ||
792 | ret = btrfs_set_inode_index(parent_inode, &index); | 831 | ret = btrfs_set_inode_index(parent_inode, &index); |
793 | BUG_ON(ret); | 832 | BUG_ON(ret); |
794 | ret = btrfs_insert_dir_item(trans, parent_root, | 833 | ret = btrfs_insert_dir_item(trans, parent_root, |
795 | pending->name, namelen, | 834 | dentry->d_name.name, dentry->d_name.len, |
796 | parent_inode->i_ino, | 835 | parent_inode->i_ino, &key, |
797 | &pending->root_key, BTRFS_FT_DIR, index); | 836 | BTRFS_FT_DIR, index); |
798 | BUG_ON(ret); | 837 | BUG_ON(ret); |
799 | 838 | ||
800 | btrfs_i_size_write(parent_inode, parent_inode->i_size + namelen * 2); | 839 | btrfs_i_size_write(parent_inode, parent_inode->i_size + |
840 | dentry->d_name.len * 2); | ||
801 | ret = btrfs_update_inode(trans, parent_root, parent_inode); | 841 | ret = btrfs_update_inode(trans, parent_root, parent_inode); |
802 | BUG_ON(ret); | 842 | BUG_ON(ret); |
803 | 843 | ||
@@ -814,22 +854,29 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
814 | free_extent_buffer(old); | 854 | free_extent_buffer(old); |
815 | 855 | ||
816 | btrfs_set_root_node(new_root_item, tmp); | 856 | btrfs_set_root_node(new_root_item, tmp); |
817 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | 857 | /* record when the snapshot was created in key.offset */ |
818 | new_root_item); | 858 | key.offset = trans->transid; |
819 | BUG_ON(ret); | 859 | ret = btrfs_insert_root(trans, tree_root, &key, new_root_item); |
820 | btrfs_tree_unlock(tmp); | 860 | btrfs_tree_unlock(tmp); |
821 | free_extent_buffer(tmp); | 861 | free_extent_buffer(tmp); |
862 | BUG_ON(ret); | ||
822 | 863 | ||
823 | ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root, | 864 | /* |
824 | pending->root_key.objectid, | 865 | * insert root back/forward references |
866 | */ | ||
867 | ret = btrfs_add_root_ref(trans, tree_root, objectid, | ||
825 | parent_root->root_key.objectid, | 868 | parent_root->root_key.objectid, |
826 | parent_inode->i_ino, index, pending->name, | 869 | parent_inode->i_ino, index, |
827 | namelen); | 870 | dentry->d_name.name, dentry->d_name.len); |
828 | BUG_ON(ret); | 871 | BUG_ON(ret); |
829 | 872 | ||
873 | key.offset = (u64)-1; | ||
874 | pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); | ||
875 | BUG_ON(IS_ERR(pending->snap)); | ||
830 | fail: | 876 | fail: |
831 | kfree(new_root_item); | 877 | kfree(new_root_item); |
832 | return ret; | 878 | btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); |
879 | return 0; | ||
833 | } | 880 | } |
834 | 881 | ||
835 | /* | 882 | /* |
@@ -898,6 +945,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
898 | ret = btrfs_run_delayed_refs(trans, root, 0); | 945 | ret = btrfs_run_delayed_refs(trans, root, 0); |
899 | BUG_ON(ret); | 946 | BUG_ON(ret); |
900 | 947 | ||
948 | btrfs_trans_release_metadata(trans, root); | ||
949 | |||
901 | cur_trans = trans->transaction; | 950 | cur_trans = trans->transaction; |
902 | /* | 951 | /* |
903 | * set the flushing flag so procs in this transaction have to | 952 | * set the flushing flag so procs in this transaction have to |