diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-27 11:05:53 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-27 11:05:53 -0400 |
commit | f4b9aa8d3b877d0a6044a6d6d9a44b29cab9e265 (patch) | |
tree | 227c83dac6b68407e3396632866f5564391ca15d /fs | |
parent | 71951f35a6e413f2bfbd41829af8cf10a890aeb6 (diff) |
btrfs_truncate
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 25 | ||||
-rw-r--r-- | fs/btrfs/super.c | 107 |
2 files changed, 114 insertions, 18 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4d4fc48c0a31..176c6dc534ba 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -171,20 +171,21 @@ static int pin_down_block(struct btrfs_root *root, u64 blocknr, int pending) | |||
171 | struct btrfs_header *header; | 171 | struct btrfs_header *header; |
172 | struct buffer_head *bh; | 172 | struct buffer_head *bh; |
173 | 173 | ||
174 | bh = sb_find_get_block(root->fs_info->sb, blocknr); | 174 | if (!pending) { |
175 | if (bh) { | 175 | bh = sb_find_get_block(root->fs_info->sb, blocknr); |
176 | header = btrfs_buffer_header(bh); | 176 | if (bh) { |
177 | if (btrfs_header_generation(header) == | 177 | header = btrfs_buffer_header(bh); |
178 | root->fs_info->running_transaction->transid) { | 178 | if (btrfs_header_generation(header) == |
179 | root->fs_info->running_transaction->transid) { | ||
180 | brelse(bh); | ||
181 | return 0; | ||
182 | } | ||
179 | brelse(bh); | 183 | brelse(bh); |
180 | return 0; | ||
181 | } | 184 | } |
182 | brelse(bh); | ||
183 | } | ||
184 | if (pending) | ||
185 | err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr); | ||
186 | else | ||
187 | err = set_radix_bit(&root->fs_info->pinned_radix, blocknr); | 185 | err = set_radix_bit(&root->fs_info->pinned_radix, blocknr); |
186 | } else { | ||
187 | err = set_radix_bit(&root->fs_info->pending_del_radix, blocknr); | ||
188 | } | ||
188 | BUG_ON(err); | 189 | BUG_ON(err); |
189 | return 0; | 190 | return 0; |
190 | } | 191 | } |
@@ -223,6 +224,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
223 | BUG_ON(ei->refs == 0); | 224 | BUG_ON(ei->refs == 0); |
224 | refs = btrfs_extent_refs(ei) - 1; | 225 | refs = btrfs_extent_refs(ei) - 1; |
225 | btrfs_set_extent_refs(ei, refs); | 226 | btrfs_set_extent_refs(ei, refs); |
227 | mark_buffer_dirty(path.nodes[0]); | ||
226 | if (refs == 0) { | 228 | if (refs == 0) { |
227 | u64 super_blocks_used; | 229 | u64 super_blocks_used; |
228 | 230 | ||
@@ -240,7 +242,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
240 | if (ret) | 242 | if (ret) |
241 | BUG(); | 243 | BUG(); |
242 | } | 244 | } |
243 | mark_buffer_dirty(path.nodes[0]); | ||
244 | btrfs_release_path(extent_root, &path); | 245 | btrfs_release_path(extent_root, &path); |
245 | finish_current_insert(trans, extent_root); | 246 | finish_current_insert(trans, extent_root); |
246 | return ret; | 247 | return ret; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 487da5a213c0..fd3d9d616ff9 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -28,11 +28,15 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
28 | struct btrfs_inode_item *inode_item; | 28 | struct btrfs_inode_item *inode_item; |
29 | struct btrfs_root *root = btrfs_sb(inode->i_sb); | 29 | struct btrfs_root *root = btrfs_sb(inode->i_sb); |
30 | int ret; | 30 | int ret; |
31 | |||
31 | btrfs_init_path(&path); | 32 | btrfs_init_path(&path); |
33 | mutex_lock(&root->fs_info->fs_mutex); | ||
34 | |||
32 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); | 35 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); |
33 | if (ret) { | 36 | if (ret) { |
34 | make_bad_inode(inode); | ||
35 | btrfs_release_path(root, &path); | 37 | btrfs_release_path(root, &path); |
38 | mutex_unlock(&root->fs_info->fs_mutex); | ||
39 | make_bad_inode(inode); | ||
36 | return; | 40 | return; |
37 | } | 41 | } |
38 | inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), | 42 | inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), |
@@ -53,6 +57,7 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
53 | inode->i_blocks = btrfs_inode_nblocks(inode_item); | 57 | inode->i_blocks = btrfs_inode_nblocks(inode_item); |
54 | inode->i_generation = btrfs_inode_generation(inode_item); | 58 | inode->i_generation = btrfs_inode_generation(inode_item); |
55 | btrfs_release_path(root, &path); | 59 | btrfs_release_path(root, &path); |
60 | mutex_unlock(&root->fs_info->fs_mutex); | ||
56 | switch (inode->i_mode & S_IFMT) { | 61 | switch (inode->i_mode & S_IFMT) { |
57 | #if 0 | 62 | #if 0 |
58 | default: | 63 | default: |
@@ -151,20 +156,85 @@ error: | |||
151 | return ret; | 156 | return ret; |
152 | } | 157 | } |
153 | 158 | ||
159 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | ||
160 | struct btrfs_root *root, | ||
161 | struct inode *inode) | ||
162 | { | ||
163 | int ret; | ||
164 | struct btrfs_path path; | ||
165 | struct btrfs_key key; | ||
166 | struct btrfs_disk_key *found_key; | ||
167 | struct btrfs_leaf *leaf; | ||
168 | struct btrfs_file_extent_item *fi; | ||
169 | u64 extent_start; | ||
170 | u64 extent_num_blocks; | ||
171 | |||
172 | /* FIXME, add redo link to tree so we don't leak on crash */ | ||
173 | key.objectid = inode->i_ino; | ||
174 | key.offset = (u64)-1; | ||
175 | key.flags = 0; | ||
176 | btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); | ||
177 | while(1) { | ||
178 | btrfs_init_path(&path); | ||
179 | ret = btrfs_search_slot(trans, root, &key, &path, -1, 1); | ||
180 | if (ret < 0) { | ||
181 | btrfs_release_path(root, &path); | ||
182 | goto error; | ||
183 | } | ||
184 | if (ret > 0) { | ||
185 | BUG_ON(path.slots[0] == 0); | ||
186 | path.slots[0]--; | ||
187 | } | ||
188 | leaf = btrfs_buffer_leaf(path.nodes[0]); | ||
189 | found_key = &leaf->items[path.slots[0]].key; | ||
190 | if (btrfs_disk_key_objectid(found_key) != inode->i_ino) | ||
191 | break; | ||
192 | if (btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY) | ||
193 | break; | ||
194 | if (btrfs_disk_key_offset(found_key) < inode->i_size) | ||
195 | break; | ||
196 | /* FIXME: add extent truncation */ | ||
197 | if (btrfs_disk_key_offset(found_key) < inode->i_size) | ||
198 | break; | ||
199 | fi = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), | ||
200 | path.slots[0], | ||
201 | struct btrfs_file_extent_item); | ||
202 | extent_start = btrfs_file_extent_disk_blocknr(fi); | ||
203 | extent_num_blocks = btrfs_file_extent_disk_num_blocks(fi); | ||
204 | key.offset = btrfs_disk_key_offset(found_key) - 1; | ||
205 | ret = btrfs_del_item(trans, root, &path); | ||
206 | BUG_ON(ret); | ||
207 | inode->i_blocks -= btrfs_file_extent_num_blocks(fi) >> 9; | ||
208 | btrfs_release_path(root, &path); | ||
209 | ret = btrfs_free_extent(trans, root, extent_start, | ||
210 | extent_num_blocks, 0); | ||
211 | BUG_ON(ret); | ||
212 | if (btrfs_disk_key_offset(found_key) == 0) | ||
213 | break; | ||
214 | } | ||
215 | btrfs_release_path(root, &path); | ||
216 | ret = 0; | ||
217 | error: | ||
218 | return ret; | ||
219 | } | ||
220 | |||
154 | static void btrfs_delete_inode(struct inode *inode) | 221 | static void btrfs_delete_inode(struct inode *inode) |
155 | { | 222 | { |
156 | struct btrfs_trans_handle *trans; | 223 | struct btrfs_trans_handle *trans; |
157 | struct btrfs_root *root = btrfs_sb(inode->i_sb); | 224 | struct btrfs_root *root = btrfs_sb(inode->i_sb); |
225 | int ret; | ||
226 | |||
158 | truncate_inode_pages(&inode->i_data, 0); | 227 | truncate_inode_pages(&inode->i_data, 0); |
159 | if (is_bad_inode(inode)) { | 228 | if (is_bad_inode(inode)) { |
160 | goto no_delete; | 229 | goto no_delete; |
161 | } | 230 | } |
162 | inode->i_size = 0; | 231 | inode->i_size = 0; |
163 | if (inode->i_blocks) | ||
164 | WARN_ON(1); | ||
165 | |||
166 | mutex_lock(&root->fs_info->fs_mutex); | 232 | mutex_lock(&root->fs_info->fs_mutex); |
167 | trans = btrfs_start_transaction(root, 1); | 233 | trans = btrfs_start_transaction(root, 1); |
234 | if (S_ISREG(inode->i_mode)) { | ||
235 | ret = btrfs_truncate_in_trans(trans, root, inode); | ||
236 | BUG_ON(ret); | ||
237 | } | ||
168 | btrfs_free_inode(trans, root, inode); | 238 | btrfs_free_inode(trans, root, inode); |
169 | btrfs_end_transaction(trans, root); | 239 | btrfs_end_transaction(trans, root); |
170 | mutex_unlock(&root->fs_info->fs_mutex); | 240 | mutex_unlock(&root->fs_info->fs_mutex); |
@@ -173,7 +243,6 @@ no_delete: | |||
173 | clear_inode(inode); | 243 | clear_inode(inode); |
174 | } | 244 | } |
175 | 245 | ||
176 | |||
177 | static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, | 246 | static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, |
178 | ino_t *ino) | 247 | ino_t *ino) |
179 | { | 248 | { |
@@ -688,6 +757,8 @@ allocate: | |||
688 | err = ret; | 757 | err = ret; |
689 | goto out; | 758 | goto out; |
690 | } | 759 | } |
760 | inode->i_blocks += inode->i_sb->s_blocksize >> 9; | ||
761 | set_buffer_new(result); | ||
691 | map_bh(result, inode->i_sb, blocknr); | 762 | map_bh(result, inode->i_sb, blocknr); |
692 | 763 | ||
693 | out: | 764 | out: |
@@ -724,6 +795,30 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc) | |||
724 | return nobh_writepage(page, btrfs_get_block, wbc); | 795 | return nobh_writepage(page, btrfs_get_block, wbc); |
725 | } | 796 | } |
726 | 797 | ||
798 | static void btrfs_truncate(struct inode *inode) | ||
799 | { | ||
800 | struct btrfs_root *root = btrfs_sb(inode->i_sb); | ||
801 | int ret; | ||
802 | struct btrfs_trans_handle *trans; | ||
803 | |||
804 | if (!S_ISREG(inode->i_mode)) | ||
805 | return; | ||
806 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
807 | return; | ||
808 | |||
809 | nobh_truncate_page(inode->i_mapping, inode->i_size); | ||
810 | |||
811 | /* FIXME, add redo link to tree so we don't leak on crash */ | ||
812 | mutex_lock(&root->fs_info->fs_mutex); | ||
813 | trans = btrfs_start_transaction(root, 1); | ||
814 | ret = btrfs_truncate_in_trans(trans, root, inode); | ||
815 | BUG_ON(ret); | ||
816 | ret = btrfs_end_transaction(trans, root); | ||
817 | BUG_ON(ret); | ||
818 | mutex_unlock(&root->fs_info->fs_mutex); | ||
819 | mark_inode_dirty(inode); | ||
820 | } | ||
821 | |||
727 | static int btrfs_get_sb(struct file_system_type *fs_type, | 822 | static int btrfs_get_sb(struct file_system_type *fs_type, |
728 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 823 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
729 | { | 824 | { |
@@ -772,7 +867,7 @@ static struct address_space_operations btrfs_aops = { | |||
772 | }; | 867 | }; |
773 | 868 | ||
774 | static struct inode_operations btrfs_file_inode_operations = { | 869 | static struct inode_operations btrfs_file_inode_operations = { |
775 | .truncate = NULL, | 870 | .truncate = btrfs_truncate, |
776 | }; | 871 | }; |
777 | 872 | ||
778 | static struct file_operations btrfs_file_operations = { | 873 | static struct file_operations btrfs_file_operations = { |