diff options
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 107 |
1 files changed, 101 insertions, 6 deletions
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 = { |