aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-03-27 11:05:53 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-03-27 11:05:53 -0400
commitf4b9aa8d3b877d0a6044a6d6d9a44b29cab9e265 (patch)
tree227c83dac6b68407e3396632866f5564391ca15d /fs
parent71951f35a6e413f2bfbd41829af8cf10a890aeb6 (diff)
btrfs_truncate
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c25
-rw-r--r--fs/btrfs/super.c107
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
159static 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;
217error:
218 return ret;
219}
220
154static void btrfs_delete_inode(struct inode *inode) 221static 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
177static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, 246static 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
693out: 764out:
@@ -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
798static 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
727static int btrfs_get_sb(struct file_system_type *fs_type, 822static 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
774static struct inode_operations btrfs_file_inode_operations = { 869static struct inode_operations btrfs_file_inode_operations = {
775 .truncate = NULL, 870 .truncate = btrfs_truncate,
776}; 871};
777 872
778static struct file_operations btrfs_file_operations = { 873static struct file_operations btrfs_file_operations = {