blob: a10e902d31025b29deace9200ba64f58bab4d2df [file] [log] [blame]
Chris Mason2e635a22007-03-21 11:12:56 -04001#include <linux/module.h>
Chris Masone20d96d2007-03-22 12:13:20 -04002#include <linux/buffer_head.h>
Chris Mason2e635a22007-03-21 11:12:56 -04003#include <linux/fs.h>
4#include <linux/pagemap.h>
5#include <linux/highmem.h>
6#include <linux/time.h>
7#include <linux/init.h>
8#include <linux/string.h>
9#include <linux/smp_lock.h>
10#include <linux/backing-dev.h>
Chris Masondee26a92007-03-26 16:00:06 -040011#include <linux/mpage.h>
Chris Mason75dfe392007-03-29 11:56:46 -040012#include <linux/swap.h>
13#include <linux/writeback.h>
Chris Mason8fd17792007-04-19 21:01:03 -040014#include <linux/statfs.h>
Chris Mason2e635a22007-03-21 11:12:56 -040015#include "ctree.h"
Chris Masone20d96d2007-03-22 12:13:20 -040016#include "disk-io.h"
Chris Masond5719762007-03-23 10:01:08 -040017#include "transaction.h"
Chris Mason2c90e5d2007-04-02 10:50:19 -040018#include "btrfs_inode.h"
Chris Masonc5739bb2007-04-10 09:27:04 -040019#include "ioctl.h"
Chris Mason2e635a22007-03-21 11:12:56 -040020
Chris Masond6e4a422007-04-06 15:37:36 -040021void btrfs_fsinfo_release(struct kobject *obj)
22{
23 struct btrfs_fs_info *fsinfo = container_of(obj,
24 struct btrfs_fs_info, kobj);
25 kfree(fsinfo);
26}
27
28struct kobj_type btrfs_fsinfo_ktype = {
29 .release = btrfs_fsinfo_release,
30};
31
Chris Masonc5739bb2007-04-10 09:27:04 -040032struct btrfs_iget_args {
33 u64 ino;
34 struct btrfs_root *root;
35};
36
Chris Masond6e4a422007-04-06 15:37:36 -040037decl_subsys(btrfs, &btrfs_fsinfo_ktype, NULL);
38
Chris Mason2e635a22007-03-21 11:12:56 -040039#define BTRFS_SUPER_MAGIC 0x9123682E
Chris Masone20d96d2007-03-22 12:13:20 -040040
41static struct inode_operations btrfs_dir_inode_operations;
Chris Masond6e4a422007-04-06 15:37:36 -040042static struct inode_operations btrfs_dir_ro_inode_operations;
Chris Masone20d96d2007-03-22 12:13:20 -040043static struct super_operations btrfs_super_ops;
44static struct file_operations btrfs_dir_file_operations;
Chris Masondee26a92007-03-26 16:00:06 -040045static struct inode_operations btrfs_file_inode_operations;
46static struct address_space_operations btrfs_aops;
47static struct file_operations btrfs_file_operations;
Chris Masone20d96d2007-03-22 12:13:20 -040048
Chris Masone20d96d2007-03-22 12:13:20 -040049static void btrfs_read_locked_inode(struct inode *inode)
Chris Mason2e635a22007-03-21 11:12:56 -040050{
Chris Mason5caf2a02007-04-02 11:20:42 -040051 struct btrfs_path *path;
Chris Masone20d96d2007-03-22 12:13:20 -040052 struct btrfs_inode_item *inode_item;
Chris Masond6e4a422007-04-06 15:37:36 -040053 struct btrfs_root *root = BTRFS_I(inode)->root;
54 struct btrfs_key location;
Chris Masone20d96d2007-03-22 12:13:20 -040055 int ret;
Chris Masonf4b9aa82007-03-27 11:05:53 -040056
Chris Mason5caf2a02007-04-02 11:20:42 -040057 path = btrfs_alloc_path();
58 BUG_ON(!path);
59 btrfs_init_path(path);
Chris Masonf4b9aa82007-03-27 11:05:53 -040060 mutex_lock(&root->fs_info->fs_mutex);
61
Chris Masond6e4a422007-04-06 15:37:36 -040062 memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
63 ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
Chris Masone20d96d2007-03-22 12:13:20 -040064 if (ret) {
Chris Mason7cfcc172007-04-02 14:53:59 -040065 btrfs_free_path(path);
Chris Masond6e4a422007-04-06 15:37:36 -040066 goto make_bad;
Chris Mason2e635a22007-03-21 11:12:56 -040067 }
Chris Mason5caf2a02007-04-02 11:20:42 -040068 inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
69 path->slots[0],
Chris Masone20d96d2007-03-22 12:13:20 -040070 struct btrfs_inode_item);
71
Chris Masone20d96d2007-03-22 12:13:20 -040072 inode->i_mode = btrfs_inode_mode(inode_item);
73 inode->i_nlink = btrfs_inode_nlink(inode_item);
74 inode->i_uid = btrfs_inode_uid(inode_item);
75 inode->i_gid = btrfs_inode_gid(inode_item);
76 inode->i_size = btrfs_inode_size(inode_item);
77 inode->i_atime.tv_sec = btrfs_timespec_sec(&inode_item->atime);
78 inode->i_atime.tv_nsec = btrfs_timespec_nsec(&inode_item->atime);
79 inode->i_mtime.tv_sec = btrfs_timespec_sec(&inode_item->mtime);
80 inode->i_mtime.tv_nsec = btrfs_timespec_nsec(&inode_item->mtime);
81 inode->i_ctime.tv_sec = btrfs_timespec_sec(&inode_item->ctime);
82 inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime);
83 inode->i_blocks = btrfs_inode_nblocks(inode_item);
84 inode->i_generation = btrfs_inode_generation(inode_item);
Chris Mason5caf2a02007-04-02 11:20:42 -040085
Chris Mason5caf2a02007-04-02 11:20:42 -040086 btrfs_free_path(path);
87 inode_item = NULL;
88
Chris Masonf4b9aa82007-03-27 11:05:53 -040089 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason1b05da22007-04-10 12:13:09 -040090
Chris Masone20d96d2007-03-22 12:13:20 -040091 switch (inode->i_mode & S_IFMT) {
92#if 0
93 default:
94 init_special_inode(inode, inode->i_mode,
95 btrfs_inode_rdev(inode_item));
96 break;
97#endif
98 case S_IFREG:
Chris Masondee26a92007-03-26 16:00:06 -040099 inode->i_mapping->a_ops = &btrfs_aops;
100 inode->i_fop = &btrfs_file_operations;
101 inode->i_op = &btrfs_file_inode_operations;
Chris Masone20d96d2007-03-22 12:13:20 -0400102 break;
103 case S_IFDIR:
Chris Masone20d96d2007-03-22 12:13:20 -0400104 inode->i_fop = &btrfs_dir_file_operations;
Chris Masond6e4a422007-04-06 15:37:36 -0400105 if (root == root->fs_info->tree_root)
106 inode->i_op = &btrfs_dir_ro_inode_operations;
107 else
108 inode->i_op = &btrfs_dir_inode_operations;
Chris Masone20d96d2007-03-22 12:13:20 -0400109 break;
110 case S_IFLNK:
Chris Masone20d96d2007-03-22 12:13:20 -0400111 // inode->i_op = &page_symlink_inode_operations;
112 break;
113 }
Chris Masone20d96d2007-03-22 12:13:20 -0400114 return;
Chris Masond6e4a422007-04-06 15:37:36 -0400115
116make_bad:
117 btrfs_release_path(root, path);
118 btrfs_free_path(path);
119 mutex_unlock(&root->fs_info->fs_mutex);
120 make_bad_inode(inode);
Chris Mason2e635a22007-03-21 11:12:56 -0400121}
122
Chris Masonf68cad02007-04-24 12:44:26 -0400123static void fill_inode_item(struct btrfs_inode_item *item,
124 struct inode *inode)
125{
126 btrfs_set_inode_uid(item, inode->i_uid);
127 btrfs_set_inode_gid(item, inode->i_gid);
128 btrfs_set_inode_size(item, inode->i_size);
129 btrfs_set_inode_mode(item, inode->i_mode);
130 btrfs_set_inode_nlink(item, inode->i_nlink);
131 btrfs_set_timespec_sec(&item->atime, inode->i_atime.tv_sec);
132 btrfs_set_timespec_nsec(&item->atime, inode->i_atime.tv_nsec);
133 btrfs_set_timespec_sec(&item->mtime, inode->i_mtime.tv_sec);
134 btrfs_set_timespec_nsec(&item->mtime, inode->i_mtime.tv_nsec);
135 btrfs_set_timespec_sec(&item->ctime, inode->i_ctime.tv_sec);
136 btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
137 btrfs_set_inode_nblocks(item, inode->i_blocks);
138 btrfs_set_inode_generation(item, inode->i_generation);
139}
140
141
142static int btrfs_update_inode(struct btrfs_trans_handle *trans,
143 struct btrfs_root *root,
144 struct inode *inode)
145{
146 struct btrfs_inode_item *inode_item;
147 struct btrfs_path *path;
148 int ret;
149
150 path = btrfs_alloc_path();
151 BUG_ON(!path);
152 btrfs_init_path(path);
153 ret = btrfs_lookup_inode(trans, root, path,
154 &BTRFS_I(inode)->location, 1);
155 if (ret) {
156 if (ret > 0)
157 ret = -ENOENT;
158 goto failed;
159 }
160
161 inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
162 path->slots[0],
163 struct btrfs_inode_item);
164
165 fill_inode_item(inode_item, inode);
166 btrfs_mark_buffer_dirty(path->nodes[0]);
167 ret = 0;
168failed:
169 btrfs_release_path(root, path);
170 btrfs_free_path(path);
171 return ret;
172}
173
174
Chris Mason5f443fd2007-03-27 13:42:32 -0400175static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
176 struct btrfs_root *root,
177 struct inode *dir,
178 struct dentry *dentry)
Chris Mason134e9732007-03-25 13:44:56 -0400179{
Chris Mason5caf2a02007-04-02 11:20:42 -0400180 struct btrfs_path *path;
Chris Mason134e9732007-03-25 13:44:56 -0400181 const char *name = dentry->d_name.name;
182 int name_len = dentry->d_name.len;
Chris Mason7e381802007-04-19 15:36:27 -0400183 int ret = 0;
Chris Mason134e9732007-03-25 13:44:56 -0400184 u64 objectid;
185 struct btrfs_dir_item *di;
186
Chris Mason5caf2a02007-04-02 11:20:42 -0400187 path = btrfs_alloc_path();
188 BUG_ON(!path);
189 btrfs_init_path(path);
Chris Mason7e381802007-04-19 15:36:27 -0400190 di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
Chris Mason134e9732007-03-25 13:44:56 -0400191 name, name_len, -1);
Chris Mason7e381802007-04-19 15:36:27 -0400192 if (IS_ERR(di)) {
193 ret = PTR_ERR(di);
Chris Mason134e9732007-03-25 13:44:56 -0400194 goto err;
Chris Mason7e381802007-04-19 15:36:27 -0400195 }
196 if (!di) {
Chris Mason134e9732007-03-25 13:44:56 -0400197 ret = -ENOENT;
198 goto err;
199 }
Chris Masond6e4a422007-04-06 15:37:36 -0400200 objectid = btrfs_disk_key_objectid(&di->location);
Chris Mason7e381802007-04-19 15:36:27 -0400201 ret = btrfs_delete_one_dir_name(trans, root, path, di);
202 BUG_ON(ret);
203 btrfs_release_path(root, path);
Chris Mason134e9732007-03-25 13:44:56 -0400204
Chris Mason7e381802007-04-19 15:36:27 -0400205 di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
206 objectid, name, name_len, -1);
207 if (IS_ERR(di)) {
208 ret = PTR_ERR(di);
209 goto err;
210 }
211 if (!di) {
212 ret = -ENOENT;
213 goto err;
214 }
215 ret = btrfs_delete_one_dir_name(trans, root, path, di);
Chris Mason134e9732007-03-25 13:44:56 -0400216 BUG_ON(ret);
Chris Mason5f26f772007-04-05 10:38:44 -0400217
Chris Mason134e9732007-03-25 13:44:56 -0400218 dentry->d_inode->i_ctime = dir->i_ctime;
219err:
Chris Mason5caf2a02007-04-02 11:20:42 -0400220 btrfs_free_path(path);
Chris Masonf68cad02007-04-24 12:44:26 -0400221 if (!ret) {
Chris Mason5f26f772007-04-05 10:38:44 -0400222 dir->i_size -= name_len * 2;
Chris Masonf68cad02007-04-24 12:44:26 -0400223 btrfs_update_inode(trans, root, dir);
224 drop_nlink(dentry->d_inode);
225 btrfs_update_inode(trans, root, dentry->d_inode);
Chris Masoncd1bc462007-04-27 10:08:34 -0400226 dir->i_sb->s_dirt = 1;
Chris Masond4dbff92007-04-04 14:08:15 -0400227 }
Chris Mason134e9732007-03-25 13:44:56 -0400228 return ret;
229}
230
Chris Mason5f443fd2007-03-27 13:42:32 -0400231static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
232{
233 struct btrfs_root *root;
234 struct btrfs_trans_handle *trans;
235 int ret;
236
Chris Masond6e4a422007-04-06 15:37:36 -0400237 root = BTRFS_I(dir)->root;
Chris Mason5f443fd2007-03-27 13:42:32 -0400238 mutex_lock(&root->fs_info->fs_mutex);
239 trans = btrfs_start_transaction(root, 1);
240 ret = btrfs_unlink_trans(trans, root, dir, dentry);
241 btrfs_end_transaction(trans, root);
242 mutex_unlock(&root->fs_info->fs_mutex);
243 return ret;
244}
245
246static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
247{
248 struct inode *inode = dentry->d_inode;
249 int err;
250 int ret;
Chris Masond6e4a422007-04-06 15:37:36 -0400251 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Mason5caf2a02007-04-02 11:20:42 -0400252 struct btrfs_path *path;
Chris Mason5f443fd2007-03-27 13:42:32 -0400253 struct btrfs_key key;
254 struct btrfs_trans_handle *trans;
Chris Mason5f26f772007-04-05 10:38:44 -0400255 struct btrfs_key found_key;
256 int found_type;
Chris Mason5f443fd2007-03-27 13:42:32 -0400257 struct btrfs_leaf *leaf;
Chris Mason5f26f772007-04-05 10:38:44 -0400258 char *goodnames = "..";
Chris Mason5f443fd2007-03-27 13:42:32 -0400259
Chris Mason5caf2a02007-04-02 11:20:42 -0400260 path = btrfs_alloc_path();
261 BUG_ON(!path);
262 btrfs_init_path(path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400263 mutex_lock(&root->fs_info->fs_mutex);
264 trans = btrfs_start_transaction(root, 1);
265 key.objectid = inode->i_ino;
266 key.offset = (u64)-1;
Chris Mason5f26f772007-04-05 10:38:44 -0400267 key.flags = (u32)-1;
268 while(1) {
269 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
270 if (ret < 0) {
271 err = ret;
272 goto out;
273 }
274 BUG_ON(ret == 0);
275 if (path->slots[0] == 0) {
276 err = -ENOENT;
277 goto out;
278 }
279 path->slots[0]--;
280 leaf = btrfs_buffer_leaf(path->nodes[0]);
281 btrfs_disk_key_to_cpu(&found_key,
282 &leaf->items[path->slots[0]].key);
283 found_type = btrfs_key_type(&found_key);
284 if (found_key.objectid != inode->i_ino) {
285 err = -ENOENT;
286 goto out;
287 }
288 if ((found_type != BTRFS_DIR_ITEM_KEY &&
289 found_type != BTRFS_DIR_INDEX_KEY) ||
290 (!btrfs_match_dir_item_name(root, path, goodnames, 2) &&
291 !btrfs_match_dir_item_name(root, path, goodnames, 1))) {
292 err = -ENOTEMPTY;
293 goto out;
294 }
295 ret = btrfs_del_item(trans, root, path);
296 BUG_ON(ret);
Chris Mason5f443fd2007-03-27 13:42:32 -0400297
Chris Mason5f26f772007-04-05 10:38:44 -0400298 if (found_type == BTRFS_DIR_ITEM_KEY && found_key.offset == 1)
299 break;
300 btrfs_release_path(root, path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400301 }
Chris Mason5f26f772007-04-05 10:38:44 -0400302 ret = 0;
Chris Mason5caf2a02007-04-02 11:20:42 -0400303 btrfs_release_path(root, path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400304
305 /* now the directory is empty */
306 err = btrfs_unlink_trans(trans, root, dir, dentry);
307 if (!err) {
308 inode->i_size = 0;
309 }
310out:
Chris Mason7cfcc172007-04-02 14:53:59 -0400311 btrfs_release_path(root, path);
312 btrfs_free_path(path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400313 mutex_unlock(&root->fs_info->fs_mutex);
314 ret = btrfs_end_transaction(trans, root);
315 if (ret && !err)
316 err = ret;
317 return err;
318}
319
Chris Mason134e9732007-03-25 13:44:56 -0400320static int btrfs_free_inode(struct btrfs_trans_handle *trans,
321 struct btrfs_root *root,
322 struct inode *inode)
323{
Chris Mason5caf2a02007-04-02 11:20:42 -0400324 struct btrfs_path *path;
Chris Mason134e9732007-03-25 13:44:56 -0400325 int ret;
Chris Mason5caf2a02007-04-02 11:20:42 -0400326
Chris Mason134e9732007-03-25 13:44:56 -0400327 clear_inode(inode);
Chris Mason5caf2a02007-04-02 11:20:42 -0400328
329 path = btrfs_alloc_path();
330 BUG_ON(!path);
331 btrfs_init_path(path);
Chris Masond6e4a422007-04-06 15:37:36 -0400332 ret = btrfs_lookup_inode(trans, root, path,
333 &BTRFS_I(inode)->location, -1);
Chris Mason134e9732007-03-25 13:44:56 -0400334 BUG_ON(ret);
Chris Mason5caf2a02007-04-02 11:20:42 -0400335 ret = btrfs_del_item(trans, root, path);
Chris Mason134e9732007-03-25 13:44:56 -0400336 BUG_ON(ret);
Chris Mason5caf2a02007-04-02 11:20:42 -0400337 btrfs_free_path(path);
Chris Mason134e9732007-03-25 13:44:56 -0400338 return ret;
339}
340
Chris Masonf4b9aa82007-03-27 11:05:53 -0400341static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
342 struct btrfs_root *root,
343 struct inode *inode)
344{
345 int ret;
Chris Mason5caf2a02007-04-02 11:20:42 -0400346 struct btrfs_path *path;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400347 struct btrfs_key key;
348 struct btrfs_disk_key *found_key;
349 struct btrfs_leaf *leaf;
Chris Masonf254e522007-03-29 15:15:27 -0400350 struct btrfs_file_extent_item *fi = NULL;
351 u64 extent_start = 0;
352 u64 extent_num_blocks = 0;
353 int found_extent;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400354
Chris Mason5caf2a02007-04-02 11:20:42 -0400355 path = btrfs_alloc_path();
356 BUG_ON(!path);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400357 /* FIXME, add redo link to tree so we don't leak on crash */
358 key.objectid = inode->i_ino;
359 key.offset = (u64)-1;
360 key.flags = 0;
Chris Masond4dbff92007-04-04 14:08:15 -0400361 /*
362 * use BTRFS_CSUM_ITEM_KEY because it is larger than inline keys
363 * or extent data
364 */
Chris Masonf254e522007-03-29 15:15:27 -0400365 btrfs_set_key_type(&key, BTRFS_CSUM_ITEM_KEY);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400366 while(1) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400367 btrfs_init_path(path);
368 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400369 if (ret < 0) {
Chris Masonf4b9aa82007-03-27 11:05:53 -0400370 goto error;
371 }
372 if (ret > 0) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400373 BUG_ON(path->slots[0] == 0);
374 path->slots[0]--;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400375 }
Chris Mason5caf2a02007-04-02 11:20:42 -0400376 leaf = btrfs_buffer_leaf(path->nodes[0]);
377 found_key = &leaf->items[path->slots[0]].key;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400378 if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
379 break;
Chris Masonf254e522007-03-29 15:15:27 -0400380 if (btrfs_disk_key_type(found_key) != BTRFS_CSUM_ITEM_KEY &&
381 btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY)
Chris Masonf4b9aa82007-03-27 11:05:53 -0400382 break;
383 if (btrfs_disk_key_offset(found_key) < inode->i_size)
384 break;
Chris Mason236454d2007-04-19 13:37:44 -0400385 found_extent = 0;
Chris Masonf254e522007-03-29 15:15:27 -0400386 if (btrfs_disk_key_type(found_key) == BTRFS_EXTENT_DATA_KEY) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400387 fi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
388 path->slots[0],
Chris Masonf254e522007-03-29 15:15:27 -0400389 struct btrfs_file_extent_item);
Chris Mason236454d2007-04-19 13:37:44 -0400390 if (btrfs_file_extent_type(fi) !=
391 BTRFS_FILE_EXTENT_INLINE) {
392 extent_start =
393 btrfs_file_extent_disk_blocknr(fi);
394 extent_num_blocks =
395 btrfs_file_extent_disk_num_blocks(fi);
396 /* FIXME blocksize != 4096 */
397 inode->i_blocks -=
398 btrfs_file_extent_num_blocks(fi) << 3;
399 found_extent = 1;
400 }
Chris Masonf254e522007-03-29 15:15:27 -0400401 }
Chris Mason5caf2a02007-04-02 11:20:42 -0400402 ret = btrfs_del_item(trans, root, path);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400403 BUG_ON(ret);
Chris Mason5caf2a02007-04-02 11:20:42 -0400404 btrfs_release_path(root, path);
Chris Masonf254e522007-03-29 15:15:27 -0400405 if (found_extent) {
406 ret = btrfs_free_extent(trans, root, extent_start,
407 extent_num_blocks, 0);
408 BUG_ON(ret);
409 }
Chris Masonf4b9aa82007-03-27 11:05:53 -0400410 }
Chris Masonf4b9aa82007-03-27 11:05:53 -0400411 ret = 0;
412error:
Chris Mason5caf2a02007-04-02 11:20:42 -0400413 btrfs_release_path(root, path);
414 btrfs_free_path(path);
Chris Masoncd1bc462007-04-27 10:08:34 -0400415 inode->i_sb->s_dirt = 1;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400416 return ret;
417}
418
Chris Mason134e9732007-03-25 13:44:56 -0400419static void btrfs_delete_inode(struct inode *inode)
420{
421 struct btrfs_trans_handle *trans;
Chris Masond6e4a422007-04-06 15:37:36 -0400422 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400423 int ret;
424
Chris Mason134e9732007-03-25 13:44:56 -0400425 truncate_inode_pages(&inode->i_data, 0);
426 if (is_bad_inode(inode)) {
427 goto no_delete;
428 }
429 inode->i_size = 0;
Chris Mason134e9732007-03-25 13:44:56 -0400430 mutex_lock(&root->fs_info->fs_mutex);
431 trans = btrfs_start_transaction(root, 1);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400432 if (S_ISREG(inode->i_mode)) {
433 ret = btrfs_truncate_in_trans(trans, root, inode);
434 BUG_ON(ret);
435 }
Chris Mason134e9732007-03-25 13:44:56 -0400436 btrfs_free_inode(trans, root, inode);
437 btrfs_end_transaction(trans, root);
438 mutex_unlock(&root->fs_info->fs_mutex);
439 return;
440no_delete:
441 clear_inode(inode);
442}
443
Chris Masone20d96d2007-03-22 12:13:20 -0400444static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
Chris Masond6e4a422007-04-06 15:37:36 -0400445 struct btrfs_key *location)
Chris Masone20d96d2007-03-22 12:13:20 -0400446{
447 const char *name = dentry->d_name.name;
448 int namelen = dentry->d_name.len;
449 struct btrfs_dir_item *di;
Chris Mason5caf2a02007-04-02 11:20:42 -0400450 struct btrfs_path *path;
Chris Masond6e4a422007-04-06 15:37:36 -0400451 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Masone20d96d2007-03-22 12:13:20 -0400452 int ret;
453
Chris Mason5caf2a02007-04-02 11:20:42 -0400454 path = btrfs_alloc_path();
455 BUG_ON(!path);
456 btrfs_init_path(path);
Chris Mason7e381802007-04-19 15:36:27 -0400457 di = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name,
Chris Masone20d96d2007-03-22 12:13:20 -0400458 namelen, 0);
Chris Mason7e381802007-04-19 15:36:27 -0400459 if (!di || IS_ERR(di)) {
Chris Masond6e4a422007-04-06 15:37:36 -0400460 location->objectid = 0;
Chris Mason2c90e5d2007-04-02 10:50:19 -0400461 ret = 0;
Chris Masone20d96d2007-03-22 12:13:20 -0400462 goto out;
463 }
Chris Masond6e4a422007-04-06 15:37:36 -0400464 btrfs_disk_key_to_cpu(location, &di->location);
Chris Masone20d96d2007-03-22 12:13:20 -0400465out:
Chris Mason5caf2a02007-04-02 11:20:42 -0400466 btrfs_release_path(root, path);
467 btrfs_free_path(path);
Chris Masone20d96d2007-03-22 12:13:20 -0400468 return ret;
469}
470
Chris Masond6e4a422007-04-06 15:37:36 -0400471int fixup_tree_root_location(struct btrfs_root *root,
472 struct btrfs_key *location,
473 struct btrfs_root **sub_root)
474{
475 struct btrfs_path *path;
476 struct btrfs_root_item *ri;
Chris Masond6e4a422007-04-06 15:37:36 -0400477
478 if (btrfs_key_type(location) != BTRFS_ROOT_ITEM_KEY)
479 return 0;
480 if (location->objectid == BTRFS_ROOT_TREE_OBJECTID)
481 return 0;
482
483 path = btrfs_alloc_path();
484 BUG_ON(!path);
485 mutex_lock(&root->fs_info->fs_mutex);
486
Chris Mason0f7d52f2007-04-09 10:42:37 -0400487 *sub_root = btrfs_read_fs_root(root->fs_info, location);
488 if (IS_ERR(*sub_root))
489 return PTR_ERR(*sub_root);
490
491 ri = &(*sub_root)->root_item;
Chris Masond6e4a422007-04-06 15:37:36 -0400492 location->objectid = btrfs_root_dirid(ri);
493 location->flags = 0;
494 btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
495 location->offset = 0;
Chris Mason0f7d52f2007-04-09 10:42:37 -0400496
Chris Masond6e4a422007-04-06 15:37:36 -0400497 btrfs_free_path(path);
498 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason0f7d52f2007-04-09 10:42:37 -0400499 return 0;
Chris Masond6e4a422007-04-06 15:37:36 -0400500}
501
Chris Masonc5739bb2007-04-10 09:27:04 -0400502int btrfs_init_locked_inode(struct inode *inode, void *p)
503{
504 struct btrfs_iget_args *args = p;
505 inode->i_ino = args->ino;
506 BTRFS_I(inode)->root = args->root;
507 return 0;
508}
509
510int btrfs_find_actor(struct inode *inode, void *opaque)
511{
512 struct btrfs_iget_args *args = opaque;
513 return (args->ino == inode->i_ino &&
514 args->root == BTRFS_I(inode)->root);
515}
516
517struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
518 struct btrfs_root *root)
519{
520 struct inode *inode;
521 struct btrfs_iget_args args;
522 args.ino = objectid;
523 args.root = root;
524
525 inode = iget5_locked(s, objectid, btrfs_find_actor,
526 btrfs_init_locked_inode,
527 (void *)&args);
528 return inode;
529}
Chris Masond6e4a422007-04-06 15:37:36 -0400530
Chris Masone20d96d2007-03-22 12:13:20 -0400531static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
532 struct nameidata *nd)
533{
534 struct inode * inode;
Chris Masond6e4a422007-04-06 15:37:36 -0400535 struct btrfs_inode *bi = BTRFS_I(dir);
536 struct btrfs_root *root = bi->root;
537 struct btrfs_root *sub_root = root;
538 struct btrfs_key location;
Chris Masone20d96d2007-03-22 12:13:20 -0400539 int ret;
540
541 if (dentry->d_name.len > BTRFS_NAME_LEN)
542 return ERR_PTR(-ENAMETOOLONG);
Chris Mason22b0ebd2007-03-30 08:47:31 -0400543 mutex_lock(&root->fs_info->fs_mutex);
Chris Masond6e4a422007-04-06 15:37:36 -0400544 ret = btrfs_inode_by_name(dir, dentry, &location);
Chris Mason22b0ebd2007-03-30 08:47:31 -0400545 mutex_unlock(&root->fs_info->fs_mutex);
Chris Masone20d96d2007-03-22 12:13:20 -0400546 if (ret < 0)
547 return ERR_PTR(ret);
548 inode = NULL;
Chris Masond6e4a422007-04-06 15:37:36 -0400549 if (location.objectid) {
550 ret = fixup_tree_root_location(root, &location, &sub_root);
551 if (ret < 0)
552 return ERR_PTR(ret);
553 if (ret > 0)
554 return ERR_PTR(-ENOENT);
Chris Masonc5739bb2007-04-10 09:27:04 -0400555 inode = btrfs_iget_locked(dir->i_sb, location.objectid,
556 sub_root);
Chris Masone20d96d2007-03-22 12:13:20 -0400557 if (!inode)
558 return ERR_PTR(-EACCES);
Chris Masond6e4a422007-04-06 15:37:36 -0400559 if (inode->i_state & I_NEW) {
Chris Mason0f7d52f2007-04-09 10:42:37 -0400560 if (sub_root != root) {
Chris Masonc5739bb2007-04-10 09:27:04 -0400561printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root);
Chris Mason0f7d52f2007-04-09 10:42:37 -0400562 igrab(inode);
563 sub_root->inode = inode;
564 }
Chris Masond6e4a422007-04-06 15:37:36 -0400565 BTRFS_I(inode)->root = sub_root;
566 memcpy(&BTRFS_I(inode)->location, &location,
567 sizeof(location));
568 btrfs_read_locked_inode(inode);
569 unlock_new_inode(inode);
570 }
Chris Masone20d96d2007-03-22 12:13:20 -0400571 }
572 return d_splice_alias(inode, dentry);
573}
574
575static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
576{
577 struct inode *inode = filp->f_path.dentry->d_inode;
Chris Masond6e4a422007-04-06 15:37:36 -0400578 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masone20d96d2007-03-22 12:13:20 -0400579 struct btrfs_item *item;
580 struct btrfs_dir_item *di;
581 struct btrfs_key key;
Chris Mason5caf2a02007-04-02 11:20:42 -0400582 struct btrfs_path *path;
Chris Masone20d96d2007-03-22 12:13:20 -0400583 int ret;
584 u32 nritems;
585 struct btrfs_leaf *leaf;
586 int slot;
587 int advance;
588 unsigned char d_type = DT_UNKNOWN;
Chris Mason7f5c1512007-03-23 15:56:19 -0400589 int over = 0;
Chris Mason7e381802007-04-19 15:36:27 -0400590 u32 di_cur;
591 u32 di_total;
592 u32 di_len;
593 int key_type = BTRFS_DIR_INDEX_KEY;
Chris Masond6e4a422007-04-06 15:37:36 -0400594
595 /* FIXME, use a real flag for deciding about the key type */
596 if (root->fs_info->tree_root == root)
597 key_type = BTRFS_DIR_ITEM_KEY;
Chris Mason22b0ebd2007-03-30 08:47:31 -0400598 mutex_lock(&root->fs_info->fs_mutex);
Chris Masone20d96d2007-03-22 12:13:20 -0400599 key.objectid = inode->i_ino;
Chris Masone20d96d2007-03-22 12:13:20 -0400600 key.flags = 0;
Chris Masond6e4a422007-04-06 15:37:36 -0400601 btrfs_set_key_type(&key, key_type);
Chris Masone20d96d2007-03-22 12:13:20 -0400602 key.offset = filp->f_pos;
Chris Mason5caf2a02007-04-02 11:20:42 -0400603 path = btrfs_alloc_path();
604 btrfs_init_path(path);
605 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
Chris Mason1b05da22007-04-10 12:13:09 -0400606 if (ret < 0)
Chris Masone20d96d2007-03-22 12:13:20 -0400607 goto err;
Chris Mason7f5c1512007-03-23 15:56:19 -0400608 advance = 0;
Chris Masone20d96d2007-03-22 12:13:20 -0400609 while(1) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400610 leaf = btrfs_buffer_leaf(path->nodes[0]);
Chris Masone20d96d2007-03-22 12:13:20 -0400611 nritems = btrfs_header_nritems(&leaf->header);
Chris Mason5caf2a02007-04-02 11:20:42 -0400612 slot = path->slots[0];
Chris Masondee26a92007-03-26 16:00:06 -0400613 if (advance || slot >= nritems) {
614 if (slot >= nritems -1) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400615 ret = btrfs_next_leaf(root, path);
Chris Masone20d96d2007-03-22 12:13:20 -0400616 if (ret)
617 break;
Chris Mason5caf2a02007-04-02 11:20:42 -0400618 leaf = btrfs_buffer_leaf(path->nodes[0]);
Chris Masone20d96d2007-03-22 12:13:20 -0400619 nritems = btrfs_header_nritems(&leaf->header);
Chris Mason5caf2a02007-04-02 11:20:42 -0400620 slot = path->slots[0];
Chris Masone20d96d2007-03-22 12:13:20 -0400621 } else {
622 slot++;
Chris Mason5caf2a02007-04-02 11:20:42 -0400623 path->slots[0]++;
Chris Masone20d96d2007-03-22 12:13:20 -0400624 }
625 }
626 advance = 1;
627 item = leaf->items + slot;
Chris Masone20d96d2007-03-22 12:13:20 -0400628 if (btrfs_disk_key_objectid(&item->key) != key.objectid)
629 break;
Chris Masond6e4a422007-04-06 15:37:36 -0400630 if (btrfs_disk_key_type(&item->key) != key_type)
Chris Masona429e512007-04-18 16:15:28 -0400631 break;
Chris Mason7f5c1512007-03-23 15:56:19 -0400632 if (btrfs_disk_key_offset(&item->key) < filp->f_pos)
633 continue;
Chris Mason7fcde0e2007-04-05 12:13:21 -0400634 filp->f_pos = btrfs_disk_key_offset(&item->key);
Chris Masondee26a92007-03-26 16:00:06 -0400635 advance = 1;
Chris Masone20d96d2007-03-22 12:13:20 -0400636 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
Chris Mason7e381802007-04-19 15:36:27 -0400637 di_cur = 0;
638 di_total = btrfs_item_size(leaf->items + slot);
639 while(di_cur < di_total) {
640 over = filldir(dirent, (const char *)(di + 1),
641 btrfs_dir_name_len(di),
642 btrfs_disk_key_offset(&item->key),
643 btrfs_disk_key_objectid(&di->location),
644 d_type);
645 if (over)
646 goto nopos;
647 di_len = btrfs_dir_name_len(di) + sizeof(*di);
648 di_cur += di_len;
649 di = (struct btrfs_dir_item *)((char *)di + di_len);
650 }
Chris Masone20d96d2007-03-22 12:13:20 -0400651 }
Chris Mason7fcde0e2007-04-05 12:13:21 -0400652 filp->f_pos++;
653nopos:
Chris Masone20d96d2007-03-22 12:13:20 -0400654 ret = 0;
655err:
Chris Mason5caf2a02007-04-02 11:20:42 -0400656 btrfs_release_path(root, path);
657 btrfs_free_path(path);
Chris Mason22b0ebd2007-03-30 08:47:31 -0400658 mutex_unlock(&root->fs_info->fs_mutex);
Chris Masone20d96d2007-03-22 12:13:20 -0400659 return ret;
660}
661
662static void btrfs_put_super (struct super_block * sb)
663{
664 struct btrfs_root *root = btrfs_sb(sb);
665 int ret;
666
667 ret = close_ctree(root);
668 if (ret) {
669 printk("close ctree returns %d\n", ret);
670 }
671 sb->s_fs_info = NULL;
672}
Chris Mason2e635a22007-03-21 11:12:56 -0400673
674static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
675{
676 struct inode * inode;
Chris Masone20d96d2007-03-22 12:13:20 -0400677 struct dentry * root_dentry;
678 struct btrfs_super_block *disk_super;
Chris Mason0f7d52f2007-04-09 10:42:37 -0400679 struct btrfs_root *tree_root;
Chris Masond6e4a422007-04-06 15:37:36 -0400680 struct btrfs_inode *bi;
Chris Mason2e635a22007-03-21 11:12:56 -0400681
682 sb->s_maxbytes = MAX_LFS_FILESIZE;
Chris Mason2e635a22007-03-21 11:12:56 -0400683 sb->s_magic = BTRFS_SUPER_MAGIC;
Chris Masone20d96d2007-03-22 12:13:20 -0400684 sb->s_op = &btrfs_super_ops;
Chris Mason2e635a22007-03-21 11:12:56 -0400685 sb->s_time_gran = 1;
Chris Masone20d96d2007-03-22 12:13:20 -0400686
Chris Mason0f7d52f2007-04-09 10:42:37 -0400687 tree_root = open_ctree(sb);
Chris Masond98237b2007-03-28 13:57:48 -0400688
Chris Mason0f7d52f2007-04-09 10:42:37 -0400689 if (!tree_root) {
Chris Masone20d96d2007-03-22 12:13:20 -0400690 printk("btrfs: open_ctree failed\n");
691 return -EIO;
692 }
Chris Mason0f7d52f2007-04-09 10:42:37 -0400693 sb->s_fs_info = tree_root;
694 disk_super = tree_root->fs_info->disk_super;
Chris Masone20d96d2007-03-22 12:13:20 -0400695 printk("read in super total blocks %Lu root %Lu\n",
696 btrfs_super_total_blocks(disk_super),
697 btrfs_super_root_dir(disk_super));
698
Chris Masonc5739bb2007-04-10 09:27:04 -0400699 inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super),
700 tree_root);
Chris Masond6e4a422007-04-06 15:37:36 -0400701 bi = BTRFS_I(inode);
702 bi->location.objectid = inode->i_ino;
703 bi->location.offset = 0;
704 bi->location.flags = 0;
Chris Mason0f7d52f2007-04-09 10:42:37 -0400705 bi->root = tree_root;
Chris Masond6e4a422007-04-06 15:37:36 -0400706 btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY);
707
Chris Mason2e635a22007-03-21 11:12:56 -0400708 if (!inode)
709 return -ENOMEM;
Chris Masone20d96d2007-03-22 12:13:20 -0400710 if (inode->i_state & I_NEW) {
711 btrfs_read_locked_inode(inode);
712 unlock_new_inode(inode);
713 }
Chris Mason2e635a22007-03-21 11:12:56 -0400714
Chris Masone20d96d2007-03-22 12:13:20 -0400715 root_dentry = d_alloc_root(inode);
716 if (!root_dentry) {
Chris Mason2e635a22007-03-21 11:12:56 -0400717 iput(inode);
718 return -ENOMEM;
719 }
Chris Masone20d96d2007-03-22 12:13:20 -0400720 sb->s_root = root_dentry;
721
Chris Mason2e635a22007-03-21 11:12:56 -0400722 return 0;
723}
724
Chris Mason4730a4b2007-03-26 12:00:39 -0400725static int btrfs_write_inode(struct inode *inode, int wait)
726{
Chris Masond6e4a422007-04-06 15:37:36 -0400727 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Mason4730a4b2007-03-26 12:00:39 -0400728 struct btrfs_trans_handle *trans;
Chris Masonb5133862007-04-24 11:52:22 -0400729 int ret = 0;
730
731 if (wait) {
732 mutex_lock(&root->fs_info->fs_mutex);
733 trans = btrfs_start_transaction(root, 1);
734 ret = btrfs_commit_transaction(trans, root);
735 mutex_unlock(&root->fs_info->fs_mutex);
736 }
737 return ret;
738}
739
740static void btrfs_dirty_inode(struct inode *inode)
741{
742 struct btrfs_root *root = BTRFS_I(inode)->root;
743 struct btrfs_trans_handle *trans;
Chris Mason4730a4b2007-03-26 12:00:39 -0400744
745 mutex_lock(&root->fs_info->fs_mutex);
746 trans = btrfs_start_transaction(root, 1);
Chris Masonb5133862007-04-24 11:52:22 -0400747 btrfs_update_inode(trans, root, inode);
748 btrfs_end_transaction(trans, root);
Chris Mason4730a4b2007-03-26 12:00:39 -0400749 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason4730a4b2007-03-26 12:00:39 -0400750}
751
Chris Masond5719762007-03-23 10:01:08 -0400752static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
Chris Mason2619ba12007-04-10 16:58:11 -0400753 struct btrfs_root *root,
754 u64 objectid, int mode)
Chris Masond5719762007-03-23 10:01:08 -0400755{
756 struct inode *inode;
757 struct btrfs_inode_item inode_item;
Chris Mason1b05da22007-04-10 12:13:09 -0400758 struct btrfs_key *location;
Chris Masond5719762007-03-23 10:01:08 -0400759 int ret;
Chris Masond5719762007-03-23 10:01:08 -0400760
Chris Mason2619ba12007-04-10 16:58:11 -0400761 inode = new_inode(root->fs_info->sb);
Chris Masond5719762007-03-23 10:01:08 -0400762 if (!inode)
763 return ERR_PTR(-ENOMEM);
764
Chris Mason2619ba12007-04-10 16:58:11 -0400765 BTRFS_I(inode)->root = root;
Chris Masond5719762007-03-23 10:01:08 -0400766
767 inode->i_uid = current->fsuid;
768 inode->i_gid = current->fsgid;
769 inode->i_mode = mode;
770 inode->i_ino = objectid;
771 inode->i_blocks = 0;
Chris Masonc5739bb2007-04-10 09:27:04 -0400772 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
Chris Masond5719762007-03-23 10:01:08 -0400773 fill_inode_item(&inode_item, inode);
Chris Mason1b05da22007-04-10 12:13:09 -0400774 location = &BTRFS_I(inode)->location;
775 location->objectid = objectid;
776 location->flags = 0;
777 location->offset = 0;
778 btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
Chris Masond5719762007-03-23 10:01:08 -0400779
780 ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
781 BUG_ON(ret);
782
783 insert_inode_hash(inode);
Chris Masond5719762007-03-23 10:01:08 -0400784 return inode;
785}
786
787static int btrfs_add_link(struct btrfs_trans_handle *trans,
788 struct dentry *dentry, struct inode *inode)
789{
790 int ret;
Chris Masond6e4a422007-04-06 15:37:36 -0400791 struct btrfs_key key;
792 struct btrfs_root *root = BTRFS_I(dentry->d_parent->d_inode)->root;
793 key.objectid = inode->i_ino;
794 key.flags = 0;
795 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
796 key.offset = 0;
797
798 ret = btrfs_insert_dir_item(trans, root,
Chris Masond5719762007-03-23 10:01:08 -0400799 dentry->d_name.name, dentry->d_name.len,
800 dentry->d_parent->d_inode->i_ino,
Chris Masond6e4a422007-04-06 15:37:36 -0400801 &key, 0);
Chris Mason4730a4b2007-03-26 12:00:39 -0400802 if (ret == 0) {
Chris Mason5f26f772007-04-05 10:38:44 -0400803 dentry->d_parent->d_inode->i_size += dentry->d_name.len * 2;
Chris Masond6e4a422007-04-06 15:37:36 -0400804 ret = btrfs_update_inode(trans, root,
Chris Mason4730a4b2007-03-26 12:00:39 -0400805 dentry->d_parent->d_inode);
806 }
Chris Masond5719762007-03-23 10:01:08 -0400807 return ret;
808}
809
810static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
811 struct dentry *dentry, struct inode *inode)
812{
813 int err = btrfs_add_link(trans, dentry, inode);
814 if (!err) {
815 d_instantiate(dentry, inode);
816 return 0;
817 }
Chris Mason2c90e5d2007-04-02 10:50:19 -0400818 if (err > 0)
819 err = -EEXIST;
Chris Masond5719762007-03-23 10:01:08 -0400820 return err;
821}
822
823static int btrfs_create(struct inode *dir, struct dentry *dentry,
824 int mode, struct nameidata *nd)
825{
826 struct btrfs_trans_handle *trans;
Chris Masond6e4a422007-04-06 15:37:36 -0400827 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Masond5719762007-03-23 10:01:08 -0400828 struct inode *inode;
829 int err;
Chris Mason134e9732007-03-25 13:44:56 -0400830 int drop_inode = 0;
Chris Mason2619ba12007-04-10 16:58:11 -0400831 u64 objectid;
Chris Masond5719762007-03-23 10:01:08 -0400832
Chris Masond561c022007-03-23 19:47:49 -0400833 mutex_lock(&root->fs_info->fs_mutex);
Chris Masond5719762007-03-23 10:01:08 -0400834 trans = btrfs_start_transaction(root, 1);
Chris Mason2619ba12007-04-10 16:58:11 -0400835
836 err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
837 if (err) {
838 err = -ENOSPC;
839 goto out_unlock;
840 }
841
842 inode = btrfs_new_inode(trans, root, objectid, mode);
Chris Masond5719762007-03-23 10:01:08 -0400843 err = PTR_ERR(inode);
844 if (IS_ERR(inode))
Chris Masond561c022007-03-23 19:47:49 -0400845 goto out_unlock;
Chris Masond5719762007-03-23 10:01:08 -0400846 // FIXME mark the inode dirty
847 err = btrfs_add_nondir(trans, dentry, inode);
Chris Mason134e9732007-03-25 13:44:56 -0400848 if (err)
849 drop_inode = 1;
Chris Masondee26a92007-03-26 16:00:06 -0400850 else {
851 inode->i_mapping->a_ops = &btrfs_aops;
852 inode->i_fop = &btrfs_file_operations;
853 inode->i_op = &btrfs_file_inode_operations;
854 }
Chris Masond5719762007-03-23 10:01:08 -0400855 dir->i_sb->s_dirt = 1;
Chris Masond561c022007-03-23 19:47:49 -0400856out_unlock:
Chris Mason22b0ebd2007-03-30 08:47:31 -0400857 btrfs_end_transaction(trans, root);
Chris Masond561c022007-03-23 19:47:49 -0400858 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason2c90e5d2007-04-02 10:50:19 -0400859
Chris Mason134e9732007-03-25 13:44:56 -0400860 if (drop_inode) {
861 inode_dec_link_count(inode);
862 iput(inode);
863 }
Chris Masond5719762007-03-23 10:01:08 -0400864 return err;
865}
866
Chris Masonf7922032007-03-25 20:17:36 -0400867static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans,
Chris Mason2619ba12007-04-10 16:58:11 -0400868 struct btrfs_root *root,
869 u64 objectid, u64 dirid)
Chris Masonf7922032007-03-25 20:17:36 -0400870{
Chris Masonf7922032007-03-25 20:17:36 -0400871 int ret;
872 char buf[2];
Chris Masond6e4a422007-04-06 15:37:36 -0400873 struct btrfs_key key;
874
Chris Masonf7922032007-03-25 20:17:36 -0400875 buf[0] = '.';
876 buf[1] = '.';
877
Chris Mason2619ba12007-04-10 16:58:11 -0400878 key.objectid = objectid;
Chris Masond6e4a422007-04-06 15:37:36 -0400879 key.offset = 0;
880 key.flags = 0;
881 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
882
Chris Mason2619ba12007-04-10 16:58:11 -0400883 ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid,
Chris Masond6e4a422007-04-06 15:37:36 -0400884 &key, 1);
Chris Masonf7922032007-03-25 20:17:36 -0400885 if (ret)
886 goto error;
Chris Mason2619ba12007-04-10 16:58:11 -0400887 key.objectid = dirid;
888 ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid,
Chris Masond6e4a422007-04-06 15:37:36 -0400889 &key, 1);
Chris Mason4730a4b2007-03-26 12:00:39 -0400890 if (ret)
891 goto error;
Chris Masonf7922032007-03-25 20:17:36 -0400892error:
893 return ret;
894}
895
896static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
897{
898 struct inode *inode;
899 struct btrfs_trans_handle *trans;
Chris Masond6e4a422007-04-06 15:37:36 -0400900 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Masonf7922032007-03-25 20:17:36 -0400901 int err = 0;
902 int drop_on_err = 0;
Chris Mason2619ba12007-04-10 16:58:11 -0400903 u64 objectid;
Chris Masonf7922032007-03-25 20:17:36 -0400904
905 mutex_lock(&root->fs_info->fs_mutex);
906 trans = btrfs_start_transaction(root, 1);
907 if (IS_ERR(trans)) {
908 err = PTR_ERR(trans);
909 goto out_unlock;
910 }
Chris Mason2619ba12007-04-10 16:58:11 -0400911
912 err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
913 if (err) {
914 err = -ENOSPC;
915 goto out_unlock;
916 }
917
918 inode = btrfs_new_inode(trans, root, objectid, S_IFDIR | mode);
Chris Masonf7922032007-03-25 20:17:36 -0400919 if (IS_ERR(inode)) {
920 err = PTR_ERR(inode);
921 goto out_fail;
922 }
923 drop_on_err = 1;
924 inode->i_op = &btrfs_dir_inode_operations;
925 inode->i_fop = &btrfs_dir_file_operations;
926
Chris Mason2619ba12007-04-10 16:58:11 -0400927 err = btrfs_make_empty_dir(trans, root, inode->i_ino, dir->i_ino);
928 if (err)
929 goto out_fail;
930
931 inode->i_size = 6;
932 err = btrfs_update_inode(trans, root, inode);
Chris Masonf7922032007-03-25 20:17:36 -0400933 if (err)
934 goto out_fail;
935 err = btrfs_add_link(trans, dentry, inode);
936 if (err)
937 goto out_fail;
938 d_instantiate(dentry, inode);
Chris Masonf7922032007-03-25 20:17:36 -0400939 drop_on_err = 0;
Chris Masoncd1bc462007-04-27 10:08:34 -0400940 dir->i_sb->s_dirt = 1;
Chris Masonf7922032007-03-25 20:17:36 -0400941
942out_fail:
943 btrfs_end_transaction(trans, root);
944out_unlock:
945 mutex_unlock(&root->fs_info->fs_mutex);
946 if (drop_on_err)
947 iput(inode);
948 return err;
949}
950
Chris Mason8fd17792007-04-19 21:01:03 -0400951static int btrfs_sync_file(struct file *file,
952 struct dentry *dentry, int datasync)
953{
954 struct inode *inode = dentry->d_inode;
955 struct btrfs_root *root = BTRFS_I(inode)->root;
956 int ret;
957 struct btrfs_trans_handle *trans;
958
959 mutex_lock(&root->fs_info->fs_mutex);
960 trans = btrfs_start_transaction(root, 1);
961 if (!trans) {
962 ret = -ENOMEM;
963 goto out;
964 }
965 ret = btrfs_commit_transaction(trans, root);
966 mutex_unlock(&root->fs_info->fs_mutex);
967out:
968 return ret > 0 ? EIO : ret;
969}
970
Chris Masond5719762007-03-23 10:01:08 -0400971static int btrfs_sync_fs(struct super_block *sb, int wait)
972{
973 struct btrfs_trans_handle *trans;
974 struct btrfs_root *root;
975 int ret;
Chris Masond98237b2007-03-28 13:57:48 -0400976 root = btrfs_sb(sb);
Chris Masondf2ce342007-03-23 11:00:45 -0400977
Chris Masond5719762007-03-23 10:01:08 -0400978 sb->s_dirt = 0;
Chris Masond561c022007-03-23 19:47:49 -0400979 if (!wait) {
Chris Mason7cfcc172007-04-02 14:53:59 -0400980 filemap_flush(root->fs_info->btree_inode->i_mapping);
Chris Masond561c022007-03-23 19:47:49 -0400981 return 0;
982 }
Chris Mason7cfcc172007-04-02 14:53:59 -0400983 filemap_write_and_wait(root->fs_info->btree_inode->i_mapping);
Chris Masond561c022007-03-23 19:47:49 -0400984 mutex_lock(&root->fs_info->fs_mutex);
Chris Masond5719762007-03-23 10:01:08 -0400985 trans = btrfs_start_transaction(root, 1);
986 ret = btrfs_commit_transaction(trans, root);
987 sb->s_dirt = 0;
988 BUG_ON(ret);
989printk("btrfs sync_fs\n");
Chris Masond561c022007-03-23 19:47:49 -0400990 mutex_unlock(&root->fs_info->fs_mutex);
Chris Masond5719762007-03-23 10:01:08 -0400991 return 0;
992}
993
Chris Mason75dfe392007-03-29 11:56:46 -0400994static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
Chris Masondee26a92007-03-26 16:00:06 -0400995 struct buffer_head *result, int create)
996{
997 int ret;
998 int err = 0;
999 u64 blocknr;
1000 u64 extent_start = 0;
1001 u64 extent_end = 0;
1002 u64 objectid = inode->i_ino;
Chris Mason236454d2007-04-19 13:37:44 -04001003 u32 found_type;
Chris Mason5caf2a02007-04-02 11:20:42 -04001004 struct btrfs_path *path;
Chris Masond6e4a422007-04-06 15:37:36 -04001005 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masondee26a92007-03-26 16:00:06 -04001006 struct btrfs_file_extent_item *item;
1007 struct btrfs_leaf *leaf;
1008 struct btrfs_disk_key *found_key;
1009
Chris Mason5caf2a02007-04-02 11:20:42 -04001010 path = btrfs_alloc_path();
1011 BUG_ON(!path);
1012 btrfs_init_path(path);
Chris Mason6567e832007-04-16 09:22:45 -04001013 if (create) {
Chris Mason6567e832007-04-16 09:22:45 -04001014 WARN_ON(1);
1015 }
Chris Masondee26a92007-03-26 16:00:06 -04001016
Chris Mason236454d2007-04-19 13:37:44 -04001017 ret = btrfs_lookup_file_extent(NULL, root, path,
Chris Mason9773a782007-03-27 11:26:26 -04001018 inode->i_ino,
Chris Mason236454d2007-04-19 13:37:44 -04001019 iblock << inode->i_blkbits, 0);
Chris Masondee26a92007-03-26 16:00:06 -04001020 if (ret < 0) {
Chris Masondee26a92007-03-26 16:00:06 -04001021 err = ret;
1022 goto out;
1023 }
1024
1025 if (ret != 0) {
Chris Mason5caf2a02007-04-02 11:20:42 -04001026 if (path->slots[0] == 0) {
1027 btrfs_release_path(root, path);
Chris Mason236454d2007-04-19 13:37:44 -04001028 goto out;
Chris Masondee26a92007-03-26 16:00:06 -04001029 }
Chris Mason5caf2a02007-04-02 11:20:42 -04001030 path->slots[0]--;
Chris Masondee26a92007-03-26 16:00:06 -04001031 }
1032
Chris Mason5caf2a02007-04-02 11:20:42 -04001033 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
Chris Masondee26a92007-03-26 16:00:06 -04001034 struct btrfs_file_extent_item);
Chris Mason5caf2a02007-04-02 11:20:42 -04001035 leaf = btrfs_buffer_leaf(path->nodes[0]);
Chris Masondee26a92007-03-26 16:00:06 -04001036 blocknr = btrfs_file_extent_disk_blocknr(item);
1037 blocknr += btrfs_file_extent_offset(item);
1038
Chris Masondee26a92007-03-26 16:00:06 -04001039 /* are we inside the extent that was found? */
Chris Mason5caf2a02007-04-02 11:20:42 -04001040 found_key = &leaf->items[path->slots[0]].key;
Chris Mason236454d2007-04-19 13:37:44 -04001041 found_type = btrfs_disk_key_type(found_key);
Chris Masondee26a92007-03-26 16:00:06 -04001042 if (btrfs_disk_key_objectid(found_key) != objectid ||
Chris Mason236454d2007-04-19 13:37:44 -04001043 found_type != BTRFS_EXTENT_DATA_KEY) {
Chris Masondee26a92007-03-26 16:00:06 -04001044 extent_end = 0;
1045 extent_start = 0;
Chris Mason5caf2a02007-04-02 11:20:42 -04001046 btrfs_release_path(root, path);
Chris Mason236454d2007-04-19 13:37:44 -04001047 goto out;
Chris Masondee26a92007-03-26 16:00:06 -04001048 }
Chris Mason236454d2007-04-19 13:37:44 -04001049 found_type = btrfs_file_extent_type(item);
Chris Mason5caf2a02007-04-02 11:20:42 -04001050 extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key);
Chris Mason236454d2007-04-19 13:37:44 -04001051 if (found_type == BTRFS_FILE_EXTENT_REG) {
1052 extent_start = extent_start >> inode->i_blkbits;
1053 extent_end = extent_start + btrfs_file_extent_num_blocks(item);
1054 if (iblock >= extent_start && iblock < extent_end) {
1055 err = 0;
1056 btrfs_map_bh_to_logical(root, result, blocknr +
1057 iblock - extent_start);
1058 goto out;
1059 }
1060 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
1061 char *ptr;
1062 char *map;
1063 u32 size;
1064 size = btrfs_file_extent_inline_len(leaf->items +
1065 path->slots[0]);
1066 extent_end = (extent_start + size) >> inode->i_blkbits;
1067 extent_start >>= inode->i_blkbits;
1068 if (iblock < extent_start || iblock > extent_end) {
1069 goto out;
1070 }
1071 ptr = btrfs_file_extent_inline_start(item);
1072 map = kmap(result->b_page);
1073 memcpy(map, ptr, size);
1074 memset(map + size, 0, PAGE_CACHE_SIZE - size);
1075 flush_dcache_page(result->b_page);
1076 kunmap(result->b_page);
1077 set_buffer_uptodate(result);
1078 SetPageChecked(result->b_page);
1079 btrfs_map_bh_to_logical(root, result, 0);
Chris Masondee26a92007-03-26 16:00:06 -04001080 }
Chris Masondee26a92007-03-26 16:00:06 -04001081out:
Chris Mason5caf2a02007-04-02 11:20:42 -04001082 btrfs_release_path(root, path);
1083 btrfs_free_path(path);
Chris Mason75dfe392007-03-29 11:56:46 -04001084 return err;
1085}
1086
1087static int btrfs_get_block(struct inode *inode, sector_t iblock,
1088 struct buffer_head *result, int create)
1089{
1090 int err;
Chris Masond6e4a422007-04-06 15:37:36 -04001091 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Mason75dfe392007-03-29 11:56:46 -04001092 mutex_lock(&root->fs_info->fs_mutex);
Chris Masone8f05c42007-04-04 14:30:09 -04001093 err = btrfs_get_block_lock(inode, iblock, result, create);
Chris Masondee26a92007-03-26 16:00:06 -04001094 mutex_unlock(&root->fs_info->fs_mutex);
1095 return err;
1096}
1097
1098static int btrfs_prepare_write(struct file *file, struct page *page,
1099 unsigned from, unsigned to)
1100{
Chris Mason6407bf62007-03-27 06:33:00 -04001101 return nobh_prepare_write(page, from, to, btrfs_get_block);
Chris Masondee26a92007-03-26 16:00:06 -04001102}
1103
Chris Masond561c022007-03-23 19:47:49 -04001104static void btrfs_write_super(struct super_block *sb)
1105{
1106 btrfs_sync_fs(sb, 1);
1107}
1108
Chris Masondee26a92007-03-26 16:00:06 -04001109static int btrfs_readpage(struct file *file, struct page *page)
1110{
1111 return mpage_readpage(page, btrfs_get_block);
1112}
1113
Chris Mason236454d2007-04-19 13:37:44 -04001114/*
1115 * While block_write_full_page is writing back the dirty buffers under
1116 * the page lock, whoever dirtied the buffers may decide to clean them
1117 * again at any time. We handle that by only looking at the buffer
1118 * state inside lock_buffer().
1119 *
1120 * If block_write_full_page() is called for regular writeback
1121 * (wbc->sync_mode == WB_SYNC_NONE) then it will redirty a page which has a
1122 * locked buffer. This only can happen if someone has written the buffer
1123 * directly, with submit_bh(). At the address_space level PageWriteback
1124 * prevents this contention from occurring.
1125 */
1126static int __btrfs_write_full_page(struct inode *inode, struct page *page,
1127 struct writeback_control *wbc)
1128{
1129 int err;
1130 sector_t block;
1131 sector_t last_block;
1132 struct buffer_head *bh, *head;
1133 const unsigned blocksize = 1 << inode->i_blkbits;
1134 int nr_underway = 0;
1135
1136 BUG_ON(!PageLocked(page));
1137
1138 last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
1139
1140 if (!page_has_buffers(page)) {
1141 create_empty_buffers(page, blocksize,
1142 (1 << BH_Dirty)|(1 << BH_Uptodate));
1143 }
1144
1145 /*
1146 * Be very careful. We have no exclusion from __set_page_dirty_buffers
1147 * here, and the (potentially unmapped) buffers may become dirty at
1148 * any time. If a buffer becomes dirty here after we've inspected it
1149 * then we just miss that fact, and the page stays dirty.
1150 *
1151 * Buffers outside i_size may be dirtied by __set_page_dirty_buffers;
1152 * handle that here by just cleaning them.
1153 */
1154
1155 block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
1156 head = page_buffers(page);
1157 bh = head;
1158
1159 /*
1160 * Get all the dirty buffers mapped to disk addresses and
1161 * handle any aliases from the underlying blockdev's mapping.
1162 */
1163 do {
1164 if (block > last_block) {
1165 /*
1166 * mapped buffers outside i_size will occur, because
1167 * this page can be outside i_size when there is a
1168 * truncate in progress.
1169 */
1170 /*
1171 * The buffer was zeroed by block_write_full_page()
1172 */
1173 clear_buffer_dirty(bh);
1174 set_buffer_uptodate(bh);
1175 } else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
1176 WARN_ON(bh->b_size != blocksize);
1177 err = btrfs_get_block(inode, block, bh, 0);
1178 if (err)
1179 goto recover;
1180 if (buffer_new(bh)) {
1181 /* blockdev mappings never come here */
1182 clear_buffer_new(bh);
1183 unmap_underlying_metadata(bh->b_bdev,
1184 bh->b_blocknr);
1185 }
1186 }
1187 bh = bh->b_this_page;
1188 block++;
1189 } while (bh != head);
1190
1191 do {
1192 if (!buffer_mapped(bh))
1193 continue;
1194 /*
1195 * If it's a fully non-blocking write attempt and we cannot
1196 * lock the buffer then redirty the page. Note that this can
1197 * potentially cause a busy-wait loop from pdflush and kswapd
1198 * activity, but those code paths have their own higher-level
1199 * throttling.
1200 */
1201 if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
1202 lock_buffer(bh);
1203 } else if (test_set_buffer_locked(bh)) {
1204 redirty_page_for_writepage(wbc, page);
1205 continue;
1206 }
1207 if (test_clear_buffer_dirty(bh) && bh->b_blocknr != 0) {
1208 mark_buffer_async_write(bh);
1209 } else {
1210 unlock_buffer(bh);
1211 }
1212 } while ((bh = bh->b_this_page) != head);
1213
1214 /*
1215 * The page and its buffers are protected by PageWriteback(), so we can
1216 * drop the bh refcounts early.
1217 */
1218 BUG_ON(PageWriteback(page));
1219 set_page_writeback(page);
1220
1221 do {
1222 struct buffer_head *next = bh->b_this_page;
1223 if (buffer_async_write(bh)) {
1224 submit_bh(WRITE, bh);
1225 nr_underway++;
1226 }
1227 bh = next;
1228 } while (bh != head);
1229 unlock_page(page);
1230
1231 err = 0;
1232done:
1233 if (nr_underway == 0) {
1234 /*
1235 * The page was marked dirty, but the buffers were
1236 * clean. Someone wrote them back by hand with
1237 * ll_rw_block/submit_bh. A rare case.
1238 */
1239 int uptodate = 1;
1240 do {
1241 if (!buffer_uptodate(bh)) {
1242 uptodate = 0;
1243 break;
1244 }
1245 bh = bh->b_this_page;
1246 } while (bh != head);
1247 if (uptodate)
1248 SetPageUptodate(page);
1249 end_page_writeback(page);
1250 /*
1251 * The page and buffer_heads can be released at any time from
1252 * here on.
1253 */
1254 wbc->pages_skipped++; /* We didn't write this page */
1255 }
1256 return err;
1257
1258recover:
1259 /*
1260 * ENOSPC, or some other error. We may already have added some
1261 * blocks to the file, so we need to write these out to avoid
1262 * exposing stale data.
1263 * The page is currently locked and not marked for writeback
1264 */
1265 bh = head;
1266 /* Recovery: lock and submit the mapped buffers */
1267 do {
1268 if (buffer_mapped(bh) && buffer_dirty(bh)) {
1269 lock_buffer(bh);
1270 mark_buffer_async_write(bh);
1271 } else {
1272 /*
1273 * The buffer may have been set dirty during
1274 * attachment to a dirty page.
1275 */
1276 clear_buffer_dirty(bh);
1277 }
1278 } while ((bh = bh->b_this_page) != head);
1279 SetPageError(page);
1280 BUG_ON(PageWriteback(page));
1281 set_page_writeback(page);
1282 do {
1283 struct buffer_head *next = bh->b_this_page;
1284 if (buffer_async_write(bh)) {
1285 clear_buffer_dirty(bh);
1286 submit_bh(WRITE, bh);
1287 nr_underway++;
1288 }
1289 bh = next;
1290 } while (bh != head);
1291 unlock_page(page);
1292 goto done;
1293}
1294
1295/*
1296 * The generic ->writepage function for buffer-backed address_spaces
1297 */
Chris Masondee26a92007-03-26 16:00:06 -04001298static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
1299{
Chris Mason236454d2007-04-19 13:37:44 -04001300 struct inode * const inode = page->mapping->host;
1301 loff_t i_size = i_size_read(inode);
1302 const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
1303 unsigned offset;
1304 void *kaddr;
1305
1306 /* Is the page fully inside i_size? */
1307 if (page->index < end_index)
1308 return __btrfs_write_full_page(inode, page, wbc);
1309
1310 /* Is the page fully outside i_size? (truncate in progress) */
1311 offset = i_size & (PAGE_CACHE_SIZE-1);
1312 if (page->index >= end_index+1 || !offset) {
1313 /*
1314 * The page may have dirty, unmapped buffers. For example,
1315 * they may have been added in ext3_writepage(). Make them
1316 * freeable here, so the page does not leak.
1317 */
1318 block_invalidatepage(page, 0);
1319 unlock_page(page);
1320 return 0; /* don't care */
1321 }
1322
1323 /*
1324 * The page straddles i_size. It must be zeroed out on each and every
1325 * writepage invokation because it may be mmapped. "A file is mapped
1326 * in multiples of the page size. For a file that is not a multiple of
1327 * the page size, the remaining memory is zeroed when mapped, and
1328 * writes to that region are not written out to the file."
1329 */
1330 kaddr = kmap_atomic(page, KM_USER0);
1331 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
1332 flush_dcache_page(page);
1333 kunmap_atomic(kaddr, KM_USER0);
1334 return __btrfs_write_full_page(inode, page, wbc);
Chris Masondee26a92007-03-26 16:00:06 -04001335}
Chris Masond561c022007-03-23 19:47:49 -04001336
Chris Masonf4b9aa82007-03-27 11:05:53 -04001337static void btrfs_truncate(struct inode *inode)
1338{
Chris Masond6e4a422007-04-06 15:37:36 -04001339 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masonf4b9aa82007-03-27 11:05:53 -04001340 int ret;
1341 struct btrfs_trans_handle *trans;
1342
1343 if (!S_ISREG(inode->i_mode))
1344 return;
1345 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
1346 return;
1347
Chris Masone8f05c42007-04-04 14:30:09 -04001348 nobh_truncate_page(inode->i_mapping, inode->i_size);
Chris Masonf4b9aa82007-03-27 11:05:53 -04001349
1350 /* FIXME, add redo link to tree so we don't leak on crash */
1351 mutex_lock(&root->fs_info->fs_mutex);
1352 trans = btrfs_start_transaction(root, 1);
1353 ret = btrfs_truncate_in_trans(trans, root, inode);
1354 BUG_ON(ret);
1355 ret = btrfs_end_transaction(trans, root);
1356 BUG_ON(ret);
1357 mutex_unlock(&root->fs_info->fs_mutex);
1358 mark_inode_dirty(inode);
1359}
1360
Chris Mason236454d2007-04-19 13:37:44 -04001361/*
1362 * Make sure any changes to nobh_commit_write() are reflected in
1363 * nobh_truncate_page(), since it doesn't call commit_write().
1364 */
1365static int btrfs_commit_write(struct file *file, struct page *page,
1366 unsigned from, unsigned to)
1367{
1368 struct inode *inode = page->mapping->host;
1369 struct buffer_head *bh;
1370 loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1371
1372 SetPageUptodate(page);
1373 bh = page_buffers(page);
1374 if (buffer_mapped(bh) && bh->b_blocknr != 0) {
1375 set_page_dirty(page);
1376 }
1377 if (pos > inode->i_size) {
1378 i_size_write(inode, pos);
1379 mark_inode_dirty(inode);
1380 }
1381 return 0;
1382}
1383
Chris Mason75dfe392007-03-29 11:56:46 -04001384static int btrfs_copy_from_user(loff_t pos, int num_pages, int write_bytes,
1385 struct page **prepared_pages,
1386 const char __user * buf)
1387{
1388 long page_fault = 0;
1389 int i;
1390 int offset = pos & (PAGE_CACHE_SIZE - 1);
1391
1392 for (i = 0; i < num_pages && write_bytes > 0; i++, offset = 0) {
1393 size_t count = min_t(size_t,
1394 PAGE_CACHE_SIZE - offset, write_bytes);
1395 struct page *page = prepared_pages[i];
1396 fault_in_pages_readable(buf, count);
1397
1398 /* Copy data from userspace to the current page */
1399 kmap(page);
1400 page_fault = __copy_from_user(page_address(page) + offset,
1401 buf, count);
1402 /* Flush processor's dcache for this page */
1403 flush_dcache_page(page);
1404 kunmap(page);
1405 buf += count;
1406 write_bytes -= count;
1407
1408 if (page_fault)
1409 break;
1410 }
1411 return page_fault ? -EFAULT : 0;
1412}
1413
1414static void btrfs_drop_pages(struct page **pages, size_t num_pages)
1415{
1416 size_t i;
1417 for (i = 0; i < num_pages; i++) {
1418 if (!pages[i])
1419 break;
1420 unlock_page(pages[i]);
1421 mark_page_accessed(pages[i]);
1422 page_cache_release(pages[i]);
1423 }
1424}
1425static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
1426 struct btrfs_root *root,
1427 struct file *file,
1428 struct page **pages,
1429 size_t num_pages,
1430 loff_t pos,
1431 size_t write_bytes)
1432{
1433 int i;
1434 int offset;
1435 int err = 0;
1436 int ret;
1437 int this_write;
Chris Masonf254e522007-03-29 15:15:27 -04001438 struct inode *inode = file->f_path.dentry->d_inode;
Chris Mason236454d2007-04-19 13:37:44 -04001439 struct buffer_head *bh;
1440 struct btrfs_file_extent_item *ei;
Chris Mason75dfe392007-03-29 11:56:46 -04001441
1442 for (i = 0; i < num_pages; i++) {
1443 offset = pos & (PAGE_CACHE_SIZE -1);
1444 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
Chris Masonf254e522007-03-29 15:15:27 -04001445 /* FIXME, one block at a time */
1446
1447 mutex_lock(&root->fs_info->fs_mutex);
1448 trans = btrfs_start_transaction(root, 1);
Chris Mason236454d2007-04-19 13:37:44 -04001449
1450 bh = page_buffers(pages[i]);
1451 if (buffer_mapped(bh) && bh->b_blocknr == 0) {
1452 struct btrfs_key key;
1453 struct btrfs_path *path;
1454 char *ptr;
1455 u32 datasize;
1456
1457 path = btrfs_alloc_path();
1458 BUG_ON(!path);
1459 key.objectid = inode->i_ino;
1460 key.offset = pages[i]->index << PAGE_CACHE_SHIFT;
1461 key.flags = 0;
1462 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
1463 BUG_ON(write_bytes >= PAGE_CACHE_SIZE);
1464 datasize = offset +
1465 btrfs_file_extent_calc_inline_size(write_bytes);
1466 ret = btrfs_insert_empty_item(trans, root, path, &key,
1467 datasize);
1468 BUG_ON(ret);
1469 ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
1470 path->slots[0], struct btrfs_file_extent_item);
1471 btrfs_set_file_extent_generation(ei, trans->transid);
1472 btrfs_set_file_extent_type(ei,
1473 BTRFS_FILE_EXTENT_INLINE);
1474 ptr = btrfs_file_extent_inline_start(ei);
1475 memcpy(ptr, bh->b_data, offset + write_bytes);
1476 mark_buffer_dirty(path->nodes[0]);
1477 btrfs_free_path(path);
1478 } else {
1479 btrfs_csum_file_block(trans, root, inode->i_ino,
Chris Masonf254e522007-03-29 15:15:27 -04001480 pages[i]->index << PAGE_CACHE_SHIFT,
1481 kmap(pages[i]), PAGE_CACHE_SIZE);
Chris Mason236454d2007-04-19 13:37:44 -04001482 kunmap(pages[i]);
1483 }
Chris Masonf254e522007-03-29 15:15:27 -04001484 SetPageChecked(pages[i]);
1485 ret = btrfs_end_transaction(trans, root);
1486 BUG_ON(ret);
1487 mutex_unlock(&root->fs_info->fs_mutex);
1488
Chris Mason236454d2007-04-19 13:37:44 -04001489 ret = btrfs_commit_write(file, pages[i], offset,
Chris Mason75dfe392007-03-29 11:56:46 -04001490 offset + this_write);
1491 pos += this_write;
1492 if (ret) {
1493 err = ret;
1494 goto failed;
1495 }
1496 WARN_ON(this_write > write_bytes);
1497 write_bytes -= this_write;
1498 }
1499failed:
1500 return err;
1501}
1502
Chris Masonb18c6682007-04-17 13:26:50 -04001503static int drop_extents(struct btrfs_trans_handle *trans,
1504 struct btrfs_root *root,
1505 struct inode *inode,
1506 u64 start, u64 end)
1507{
1508 int ret;
1509 struct btrfs_key key;
1510 struct btrfs_leaf *leaf;
1511 int slot;
1512 struct btrfs_file_extent_item *extent;
Chris Mason236454d2007-04-19 13:37:44 -04001513 u64 extent_end = 0;
Chris Masonb18c6682007-04-17 13:26:50 -04001514 int keep;
1515 struct btrfs_file_extent_item old;
1516 struct btrfs_path *path;
1517 u64 search_start = start;
1518 int bookend;
Chris Mason236454d2007-04-19 13:37:44 -04001519 int found_type;
1520 int found_extent;
1521 int found_inline;
1522
Chris Masonb18c6682007-04-17 13:26:50 -04001523 path = btrfs_alloc_path();
1524 if (!path)
1525 return -ENOMEM;
Chris Masonb18c6682007-04-17 13:26:50 -04001526 while(1) {
Chris Masona429e512007-04-18 16:15:28 -04001527 btrfs_release_path(root, path);
1528 ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
1529 search_start, -1);
1530 if (ret < 0)
1531 goto out;
1532 if (ret > 0) {
1533 if (path->slots[0] == 0) {
Chris Mason236454d2007-04-19 13:37:44 -04001534 ret = 0;
Chris Masona429e512007-04-18 16:15:28 -04001535 goto out;
1536 }
1537 path->slots[0]--;
1538 }
Chris Masonb18c6682007-04-17 13:26:50 -04001539 keep = 0;
1540 bookend = 0;
Chris Mason236454d2007-04-19 13:37:44 -04001541 found_extent = 0;
1542 found_inline = 0;
1543 extent = NULL;
Chris Masonb18c6682007-04-17 13:26:50 -04001544 leaf = btrfs_buffer_leaf(path->nodes[0]);
1545 slot = path->slots[0];
1546 btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
Chris Masonb18c6682007-04-17 13:26:50 -04001547 if (key.offset >= end || key.objectid != inode->i_ino) {
1548 ret = 0;
1549 goto out;
1550 }
Chris Mason236454d2007-04-19 13:37:44 -04001551 if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY) {
1552 ret = 0;
Chris Masona429e512007-04-18 16:15:28 -04001553 goto out;
Chris Mason236454d2007-04-19 13:37:44 -04001554 }
1555 extent = btrfs_item_ptr(leaf, slot,
1556 struct btrfs_file_extent_item);
1557 found_type = btrfs_file_extent_type(extent);
1558 if (found_type == BTRFS_FILE_EXTENT_REG) {
1559 extent_end = key.offset +
1560 (btrfs_file_extent_num_blocks(extent) <<
1561 inode->i_blkbits);
1562 found_extent = 1;
1563 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
1564 found_inline = 1;
1565 extent_end = key.offset +
1566 btrfs_file_extent_inline_len(leaf->items + slot);
1567 }
1568
1569 if (!found_extent && !found_inline) {
1570 ret = 0;
Chris Masona429e512007-04-18 16:15:28 -04001571 goto out;
Chris Mason236454d2007-04-19 13:37:44 -04001572 }
1573
1574 if (search_start >= extent_end) {
1575 ret = 0;
1576 goto out;
1577 }
1578
Chris Masona429e512007-04-18 16:15:28 -04001579 search_start = extent_end;
Chris Masonb18c6682007-04-17 13:26:50 -04001580
1581 if (end < extent_end && end >= key.offset) {
Chris Mason236454d2007-04-19 13:37:44 -04001582 if (found_extent) {
1583 memcpy(&old, extent, sizeof(old));
1584 ret = btrfs_inc_extent_ref(trans, root,
1585 btrfs_file_extent_disk_blocknr(&old),
1586 btrfs_file_extent_disk_num_blocks(&old));
1587 BUG_ON(ret);
1588 }
1589 WARN_ON(found_inline);
Chris Masonb18c6682007-04-17 13:26:50 -04001590 bookend = 1;
1591 }
1592
1593 if (start > key.offset) {
1594 u64 new_num;
Chris Masona429e512007-04-18 16:15:28 -04001595 u64 old_num;
Chris Masonb18c6682007-04-17 13:26:50 -04001596 /* truncate existing extent */
1597 keep = 1;
1598 WARN_ON(start & (root->blocksize - 1));
Chris Mason236454d2007-04-19 13:37:44 -04001599 if (found_extent) {
1600 new_num = (start - key.offset) >>
1601 inode->i_blkbits;
1602 old_num = btrfs_file_extent_num_blocks(extent);
1603 inode->i_blocks -= (old_num - new_num) << 3;
1604 btrfs_set_file_extent_num_blocks(extent,
1605 new_num);
1606 mark_buffer_dirty(path->nodes[0]);
1607 } else {
1608 WARN_ON(1);
1609 /*
1610 ret = btrfs_truncate_item(trans, root, path,
1611 start - key.offset);
1612 BUG_ON(ret);
1613 */
1614 }
Chris Masonb18c6682007-04-17 13:26:50 -04001615 }
1616 if (!keep) {
Chris Mason236454d2007-04-19 13:37:44 -04001617 u64 disk_blocknr = 0;
1618 u64 disk_num_blocks = 0;
1619 u64 extent_num_blocks = 0;
1620 if (found_extent) {
1621 disk_blocknr =
1622 btrfs_file_extent_disk_blocknr(extent);
1623 disk_num_blocks =
1624 btrfs_file_extent_disk_num_blocks(extent);
1625 extent_num_blocks =
1626 btrfs_file_extent_num_blocks(extent);
1627 }
Chris Masonb18c6682007-04-17 13:26:50 -04001628 ret = btrfs_del_item(trans, root, path);
1629 BUG_ON(ret);
1630 btrfs_release_path(root, path);
Chris Mason236454d2007-04-19 13:37:44 -04001631 if (found_extent) {
1632 inode->i_blocks -=
1633 btrfs_file_extent_num_blocks(extent) << 3;
1634 ret = btrfs_free_extent(trans, root,
1635 disk_blocknr,
1636 disk_num_blocks, 0);
1637 }
Chris Masonb18c6682007-04-17 13:26:50 -04001638
1639 BUG_ON(ret);
1640 if (!bookend && search_start >= end) {
1641 ret = 0;
1642 goto out;
1643 }
1644 if (!bookend)
Chris Masona429e512007-04-18 16:15:28 -04001645 continue;
Chris Masonb18c6682007-04-17 13:26:50 -04001646 }
Chris Mason236454d2007-04-19 13:37:44 -04001647 if (bookend && found_extent) {
Chris Masonb18c6682007-04-17 13:26:50 -04001648 /* create bookend */
1649 struct btrfs_key ins;
Chris Masonb18c6682007-04-17 13:26:50 -04001650 ins.objectid = inode->i_ino;
1651 ins.offset = end;
1652 ins.flags = 0;
1653 btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
1654
1655 btrfs_release_path(root, path);
Chris Masonb18c6682007-04-17 13:26:50 -04001656 ret = btrfs_insert_empty_item(trans, root, path, &ins,
1657 sizeof(*extent));
1658 BUG_ON(ret);
1659 extent = btrfs_item_ptr(
1660 btrfs_buffer_leaf(path->nodes[0]),
1661 path->slots[0],
1662 struct btrfs_file_extent_item);
1663 btrfs_set_file_extent_disk_blocknr(extent,
1664 btrfs_file_extent_disk_blocknr(&old));
1665 btrfs_set_file_extent_disk_num_blocks(extent,
1666 btrfs_file_extent_disk_num_blocks(&old));
1667
1668 btrfs_set_file_extent_offset(extent,
1669 btrfs_file_extent_offset(&old) +
1670 ((end - key.offset) >> inode->i_blkbits));
1671 WARN_ON(btrfs_file_extent_num_blocks(&old) <
1672 (end - key.offset) >> inode->i_blkbits);
1673 btrfs_set_file_extent_num_blocks(extent,
1674 btrfs_file_extent_num_blocks(&old) -
1675 ((end - key.offset) >> inode->i_blkbits));
1676
Chris Mason236454d2007-04-19 13:37:44 -04001677 btrfs_set_file_extent_type(extent,
1678 BTRFS_FILE_EXTENT_REG);
Chris Masonb18c6682007-04-17 13:26:50 -04001679 btrfs_set_file_extent_generation(extent,
1680 btrfs_file_extent_generation(&old));
Chris Masonb18c6682007-04-17 13:26:50 -04001681 btrfs_mark_buffer_dirty(path->nodes[0]);
Chris Masona429e512007-04-18 16:15:28 -04001682 inode->i_blocks +=
1683 btrfs_file_extent_num_blocks(extent) << 3;
Chris Masonb18c6682007-04-17 13:26:50 -04001684 ret = 0;
Chris Mason70b2bef2007-04-17 15:39:32 -04001685 goto out;
Chris Masonb18c6682007-04-17 13:26:50 -04001686 }
Chris Masonb18c6682007-04-17 13:26:50 -04001687 }
Chris Masonb18c6682007-04-17 13:26:50 -04001688out:
Chris Masonb18c6682007-04-17 13:26:50 -04001689 btrfs_free_path(path);
1690 return ret;
1691}
1692
1693static int prepare_pages(struct btrfs_root *root,
Chris Mason75dfe392007-03-29 11:56:46 -04001694 struct file *file,
1695 struct page **pages,
1696 size_t num_pages,
1697 loff_t pos,
Chris Mason2932f3e2007-04-10 14:22:02 -04001698 unsigned long first_index,
1699 unsigned long last_index,
Chris Mason6567e832007-04-16 09:22:45 -04001700 size_t write_bytes,
1701 u64 alloc_extent_start)
Chris Mason75dfe392007-03-29 11:56:46 -04001702{
1703 int i;
1704 unsigned long index = pos >> PAGE_CACHE_SHIFT;
1705 struct inode *inode = file->f_path.dentry->d_inode;
1706 int offset;
1707 int err = 0;
Chris Mason75dfe392007-03-29 11:56:46 -04001708 int this_write;
Chris Mason6567e832007-04-16 09:22:45 -04001709 struct buffer_head *bh;
1710 struct buffer_head *head;
Chris Mason75dfe392007-03-29 11:56:46 -04001711 loff_t isize = i_size_read(inode);
1712
1713 memset(pages, 0, num_pages * sizeof(struct page *));
1714
1715 for (i = 0; i < num_pages; i++) {
1716 pages[i] = grab_cache_page(inode->i_mapping, index + i);
1717 if (!pages[i]) {
1718 err = -ENOMEM;
1719 goto failed_release;
1720 }
1721 offset = pos & (PAGE_CACHE_SIZE -1);
1722 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
Chris Mason6567e832007-04-16 09:22:45 -04001723 create_empty_buffers(pages[i], root->fs_info->sb->s_blocksize,
1724 (1 << BH_Uptodate));
1725 head = page_buffers(pages[i]);
1726 bh = head;
1727 do {
1728 err = btrfs_map_bh_to_logical(root, bh,
1729 alloc_extent_start);
1730 BUG_ON(err);
1731 if (err)
1732 goto failed_truncate;
1733 bh = bh->b_this_page;
Chris Mason236454d2007-04-19 13:37:44 -04001734 if (alloc_extent_start)
1735 alloc_extent_start++;
Chris Mason6567e832007-04-16 09:22:45 -04001736 } while (bh != head);
Chris Mason75dfe392007-03-29 11:56:46 -04001737 pos += this_write;
Chris Mason75dfe392007-03-29 11:56:46 -04001738 WARN_ON(this_write > write_bytes);
1739 write_bytes -= this_write;
1740 }
1741 return 0;
1742
1743failed_release:
1744 btrfs_drop_pages(pages, num_pages);
1745 return err;
1746
1747failed_truncate:
1748 btrfs_drop_pages(pages, num_pages);
1749 if (pos > isize)
1750 vmtruncate(inode, isize);
1751 return err;
1752}
1753
1754static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
1755 size_t count, loff_t *ppos)
1756{
1757 loff_t pos;
1758 size_t num_written = 0;
1759 int err = 0;
1760 int ret = 0;
Chris Mason75dfe392007-03-29 11:56:46 -04001761 struct inode *inode = file->f_path.dentry->d_inode;
Chris Masond6e4a422007-04-06 15:37:36 -04001762 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masonb18c6682007-04-17 13:26:50 -04001763 struct page *pages[8];
Chris Masona429e512007-04-18 16:15:28 -04001764 struct page *pinned[2] = { NULL, NULL };
Chris Mason2932f3e2007-04-10 14:22:02 -04001765 unsigned long first_index;
1766 unsigned long last_index;
Chris Mason6567e832007-04-16 09:22:45 -04001767 u64 start_pos;
1768 u64 num_blocks;
1769 u64 alloc_extent_start;
Chris Mason6567e832007-04-16 09:22:45 -04001770 struct btrfs_trans_handle *trans;
Chris Masonb18c6682007-04-17 13:26:50 -04001771 struct btrfs_key ins;
Chris Mason75dfe392007-03-29 11:56:46 -04001772
1773 if (file->f_flags & O_DIRECT)
1774 return -EINVAL;
1775 pos = *ppos;
Chris Mason75dfe392007-03-29 11:56:46 -04001776 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
1777 current->backing_dev_info = inode->i_mapping->backing_dev_info;
1778 err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
1779 if (err)
1780 goto out;
1781 if (count == 0)
1782 goto out;
1783 err = remove_suid(file->f_path.dentry);
1784 if (err)
1785 goto out;
1786 file_update_time(file);
Chris Masona429e512007-04-18 16:15:28 -04001787
1788 start_pos = pos & ~((u64)PAGE_CACHE_SIZE - 1);
1789 num_blocks = (count + pos - start_pos + root->blocksize - 1) >>
1790 inode->i_blkbits;
1791
Chris Mason75dfe392007-03-29 11:56:46 -04001792 mutex_lock(&inode->i_mutex);
Chris Mason2932f3e2007-04-10 14:22:02 -04001793 first_index = pos >> PAGE_CACHE_SHIFT;
1794 last_index = (pos + count) >> PAGE_CACHE_SHIFT;
Chris Mason6567e832007-04-16 09:22:45 -04001795
Chris Masona429e512007-04-18 16:15:28 -04001796 if ((first_index << PAGE_CACHE_SHIFT) < inode->i_size &&
1797 (pos & (PAGE_CACHE_SIZE - 1))) {
1798 pinned[0] = grab_cache_page(inode->i_mapping, first_index);
1799 if (!PageUptodate(pinned[0])) {
1800 ret = mpage_readpage(pinned[0], btrfs_get_block);
1801 BUG_ON(ret);
1802 } else {
1803 unlock_page(pinned[0]);
1804 }
1805 }
1806 if (first_index != last_index &&
1807 (last_index << PAGE_CACHE_SHIFT) < inode->i_size &&
1808 (count & (PAGE_CACHE_SIZE - 1))) {
1809 pinned[1] = grab_cache_page(inode->i_mapping, last_index);
1810 if (!PageUptodate(pinned[1])) {
1811 ret = mpage_readpage(pinned[1], btrfs_get_block);
1812 BUG_ON(ret);
1813 } else {
1814 unlock_page(pinned[1]);
1815 }
1816 }
1817
Chris Mason6567e832007-04-16 09:22:45 -04001818 mutex_lock(&root->fs_info->fs_mutex);
1819 trans = btrfs_start_transaction(root, 1);
1820 if (!trans) {
1821 err = -ENOMEM;
Chris Masonb18c6682007-04-17 13:26:50 -04001822 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason6567e832007-04-16 09:22:45 -04001823 goto out_unlock;
1824 }
Chris Masona429e512007-04-18 16:15:28 -04001825 /* FIXME blocksize != 4096 */
1826 inode->i_blocks += num_blocks << 3;
Chris Masonb18c6682007-04-17 13:26:50 -04001827 if (start_pos < inode->i_size) {
Chris Masona429e512007-04-18 16:15:28 -04001828 /* FIXME blocksize != pagesize */
Chris Masonb18c6682007-04-17 13:26:50 -04001829 ret = drop_extents(trans, root, inode,
1830 start_pos,
1831 (pos + count + root->blocksize -1) &
Chris Masona429e512007-04-18 16:15:28 -04001832 ~((u64)root->blocksize - 1));
Chris Mason236454d2007-04-19 13:37:44 -04001833 BUG_ON(ret);
Chris Masonb18c6682007-04-17 13:26:50 -04001834 }
Chris Mason236454d2007-04-19 13:37:44 -04001835 if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size ||
1836 pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) {
Chris Mason4d775672007-04-20 20:23:12 -04001837 ret = btrfs_alloc_extent(trans, root, inode->i_ino,
Chris Masonc62a1922007-04-24 12:07:39 -04001838 num_blocks, 1, (u64)-1, &ins);
Chris Mason236454d2007-04-19 13:37:44 -04001839 BUG_ON(ret);
1840 ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
Chris Masonb18c6682007-04-17 13:26:50 -04001841 start_pos, ins.objectid, ins.offset);
Chris Mason236454d2007-04-19 13:37:44 -04001842 BUG_ON(ret);
1843 } else {
1844 ins.offset = 0;
1845 ins.objectid = 0;
1846 }
Chris Masonb18c6682007-04-17 13:26:50 -04001847 BUG_ON(ret);
1848 alloc_extent_start = ins.objectid;
1849 ret = btrfs_end_transaction(trans, root);
Chris Mason6567e832007-04-16 09:22:45 -04001850 mutex_unlock(&root->fs_info->fs_mutex);
1851
Chris Mason75dfe392007-03-29 11:56:46 -04001852 while(count > 0) {
1853 size_t offset = pos & (PAGE_CACHE_SIZE - 1);
1854 size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset);
1855 size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
1856 PAGE_CACHE_SHIFT;
Chris Masonb18c6682007-04-17 13:26:50 -04001857
1858 memset(pages, 0, sizeof(pages));
1859 ret = prepare_pages(root, file, pages, num_pages,
Chris Mason6567e832007-04-16 09:22:45 -04001860 pos, first_index, last_index,
1861 write_bytes, alloc_extent_start);
Chris Mason75dfe392007-03-29 11:56:46 -04001862 BUG_ON(ret);
Chris Masonb18c6682007-04-17 13:26:50 -04001863
Chris Mason6567e832007-04-16 09:22:45 -04001864 /* FIXME blocks != pagesize */
Chris Mason236454d2007-04-19 13:37:44 -04001865 if (alloc_extent_start)
1866 alloc_extent_start += num_pages;
Chris Mason75dfe392007-03-29 11:56:46 -04001867 ret = btrfs_copy_from_user(pos, num_pages,
1868 write_bytes, pages, buf);
1869 BUG_ON(ret);
1870
Chris Masonf254e522007-03-29 15:15:27 -04001871 ret = dirty_and_release_pages(NULL, root, file, pages,
Chris Mason70b2bef2007-04-17 15:39:32 -04001872 num_pages, pos, write_bytes);
Chris Mason75dfe392007-03-29 11:56:46 -04001873 BUG_ON(ret);
1874 btrfs_drop_pages(pages, num_pages);
1875
Chris Mason75dfe392007-03-29 11:56:46 -04001876 buf += write_bytes;
1877 count -= write_bytes;
1878 pos += write_bytes;
1879 num_written += write_bytes;
1880
1881 balance_dirty_pages_ratelimited(inode->i_mapping);
1882 cond_resched();
1883 }
Chris Mason6567e832007-04-16 09:22:45 -04001884out_unlock:
Chris Mason75dfe392007-03-29 11:56:46 -04001885 mutex_unlock(&inode->i_mutex);
1886out:
Chris Masona429e512007-04-18 16:15:28 -04001887 if (pinned[0])
1888 page_cache_release(pinned[0]);
1889 if (pinned[1])
1890 page_cache_release(pinned[1]);
Chris Mason75dfe392007-03-29 11:56:46 -04001891 *ppos = pos;
1892 current->backing_dev_info = NULL;
Chris Masona429e512007-04-18 16:15:28 -04001893 mark_inode_dirty(inode);
Chris Mason75dfe392007-03-29 11:56:46 -04001894 return num_written ? num_written : err;
1895}
1896
Chris Masonf254e522007-03-29 15:15:27 -04001897static int btrfs_read_actor(read_descriptor_t *desc, struct page *page,
1898 unsigned long offset, unsigned long size)
1899{
1900 char *kaddr;
1901 unsigned long left, count = desc->count;
Chris Masond6e4a422007-04-06 15:37:36 -04001902 struct inode *inode = page->mapping->host;
Chris Masonf254e522007-03-29 15:15:27 -04001903
1904 if (size > count)
1905 size = count;
1906
1907 if (!PageChecked(page)) {
1908 /* FIXME, do it per block */
Chris Masond6e4a422007-04-06 15:37:36 -04001909 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Mason236454d2007-04-19 13:37:44 -04001910
Chris Masonf254e522007-03-29 15:15:27 -04001911 int ret = btrfs_csum_verify_file_block(root,
Chris Mason236454d2007-04-19 13:37:44 -04001912 page->mapping->host->i_ino,
1913 page->index << PAGE_CACHE_SHIFT,
1914 kmap(page), PAGE_CACHE_SIZE);
Chris Masonf254e522007-03-29 15:15:27 -04001915 if (ret) {
1916 printk("failed to verify ino %lu page %lu\n",
1917 page->mapping->host->i_ino,
1918 page->index);
1919 memset(page_address(page), 0, PAGE_CACHE_SIZE);
1920 }
1921 SetPageChecked(page);
1922 kunmap(page);
1923 }
1924 /*
1925 * Faults on the destination of a read are common, so do it before
1926 * taking the kmap.
1927 */
1928 if (!fault_in_pages_writeable(desc->arg.buf, size)) {
1929 kaddr = kmap_atomic(page, KM_USER0);
1930 left = __copy_to_user_inatomic(desc->arg.buf,
1931 kaddr + offset, size);
1932 kunmap_atomic(kaddr, KM_USER0);
1933 if (left == 0)
1934 goto success;
1935 }
1936
1937 /* Do it the slow way */
1938 kaddr = kmap(page);
1939 left = __copy_to_user(desc->arg.buf, kaddr + offset, size);
1940 kunmap(page);
1941
1942 if (left) {
1943 size -= left;
1944 desc->error = -EFAULT;
1945 }
1946success:
1947 desc->count = count - size;
1948 desc->written += size;
1949 desc->arg.buf += size;
1950 return size;
1951}
1952
1953/**
1954 * btrfs_file_aio_read - filesystem read routine
1955 * @iocb: kernel I/O control block
1956 * @iov: io vector request
1957 * @nr_segs: number of segments in the iovec
1958 * @pos: current file position
1959 */
1960static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
1961 unsigned long nr_segs, loff_t pos)
1962{
1963 struct file *filp = iocb->ki_filp;
1964 ssize_t retval;
1965 unsigned long seg;
1966 size_t count;
1967 loff_t *ppos = &iocb->ki_pos;
1968
1969 count = 0;
1970 for (seg = 0; seg < nr_segs; seg++) {
1971 const struct iovec *iv = &iov[seg];
1972
1973 /*
1974 * If any segment has a negative length, or the cumulative
1975 * length ever wraps negative then return -EINVAL.
1976 */
1977 count += iv->iov_len;
1978 if (unlikely((ssize_t)(count|iv->iov_len) < 0))
1979 return -EINVAL;
1980 if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
1981 continue;
1982 if (seg == 0)
1983 return -EFAULT;
1984 nr_segs = seg;
1985 count -= iv->iov_len; /* This segment is no good */
1986 break;
1987 }
1988 retval = 0;
1989 if (count) {
1990 for (seg = 0; seg < nr_segs; seg++) {
1991 read_descriptor_t desc;
1992
1993 desc.written = 0;
1994 desc.arg.buf = iov[seg].iov_base;
1995 desc.count = iov[seg].iov_len;
1996 if (desc.count == 0)
1997 continue;
1998 desc.error = 0;
1999 do_generic_file_read(filp, ppos, &desc,
2000 btrfs_read_actor);
2001 retval += desc.written;
2002 if (desc.error) {
2003 retval = retval ?: desc.error;
2004 break;
2005 }
2006 }
2007 }
2008 return retval;
2009}
2010
Chris Mason2619ba12007-04-10 16:58:11 -04002011static int create_subvol(struct btrfs_root *root, char *name, int namelen)
2012{
2013 struct btrfs_trans_handle *trans;
2014 struct btrfs_key key;
2015 struct btrfs_root_item root_item;
2016 struct btrfs_inode_item *inode_item;
2017 struct buffer_head *subvol;
2018 struct btrfs_leaf *leaf;
2019 struct btrfs_root *new_root;
2020 struct inode *inode;
2021 int ret;
2022 u64 objectid;
2023 u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
2024
2025 mutex_lock(&root->fs_info->fs_mutex);
2026 trans = btrfs_start_transaction(root, 1);
2027 BUG_ON(!trans);
2028
2029 subvol = btrfs_alloc_free_block(trans, root);
Chris Mason5e828492007-04-23 19:10:49 -04002030 if (subvol == NULL)
2031 return -ENOSPC;
Chris Mason2619ba12007-04-10 16:58:11 -04002032 leaf = btrfs_buffer_leaf(subvol);
2033 btrfs_set_header_nritems(&leaf->header, 0);
2034 btrfs_set_header_level(&leaf->header, 0);
Chris Mason7eccb902007-04-11 15:53:25 -04002035 btrfs_set_header_blocknr(&leaf->header, bh_blocknr(subvol));
Chris Mason2619ba12007-04-10 16:58:11 -04002036 btrfs_set_header_generation(&leaf->header, trans->transid);
Chris Mason4d775672007-04-20 20:23:12 -04002037 btrfs_set_header_owner(&leaf->header, root->root_key.objectid);
Chris Mason2619ba12007-04-10 16:58:11 -04002038 memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid,
2039 sizeof(leaf->header.fsid));
Chris Mason4d775672007-04-20 20:23:12 -04002040 mark_buffer_dirty(subvol);
Chris Mason2619ba12007-04-10 16:58:11 -04002041
2042 inode_item = &root_item.inode;
2043 memset(inode_item, 0, sizeof(*inode_item));
2044 btrfs_set_inode_generation(inode_item, 1);
2045 btrfs_set_inode_size(inode_item, 3);
2046 btrfs_set_inode_nlink(inode_item, 1);
2047 btrfs_set_inode_nblocks(inode_item, 1);
2048 btrfs_set_inode_mode(inode_item, S_IFDIR | 0755);
2049
Chris Mason7eccb902007-04-11 15:53:25 -04002050 btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol));
Chris Mason2619ba12007-04-10 16:58:11 -04002051 btrfs_set_root_refs(&root_item, 1);
Chris Mason5e828492007-04-23 19:10:49 -04002052 brelse(subvol);
2053 subvol = NULL;
Chris Mason2619ba12007-04-10 16:58:11 -04002054
Chris Mason2619ba12007-04-10 16:58:11 -04002055 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
2056 0, &objectid);
2057 BUG_ON(ret);
2058
2059 btrfs_set_root_dirid(&root_item, new_dirid);
2060
2061 key.objectid = objectid;
2062 key.offset = 1;
2063 key.flags = 0;
2064 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
2065 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2066 &root_item);
2067 BUG_ON(ret);
2068
2069 /*
2070 * insert the directory item
2071 */
2072 key.offset = (u64)-1;
2073 ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
2074 name, namelen,
2075 root->fs_info->sb->s_root->d_inode->i_ino,
2076 &key, 0);
2077 BUG_ON(ret);
2078
2079 ret = btrfs_commit_transaction(trans, root);
2080 BUG_ON(ret);
2081
2082 new_root = btrfs_read_fs_root(root->fs_info, &key);
2083 BUG_ON(!new_root);
2084
2085 trans = btrfs_start_transaction(new_root, 1);
2086 BUG_ON(!trans);
2087
2088 inode = btrfs_new_inode(trans, new_root, new_dirid, S_IFDIR | 0700);
2089 inode->i_op = &btrfs_dir_inode_operations;
2090 inode->i_fop = &btrfs_dir_file_operations;
2091
2092 ret = btrfs_make_empty_dir(trans, new_root, new_dirid, new_dirid);
2093 BUG_ON(ret);
2094
2095 inode->i_nlink = 1;
2096 inode->i_size = 6;
2097 ret = btrfs_update_inode(trans, new_root, inode);
2098 BUG_ON(ret);
2099
2100 ret = btrfs_commit_transaction(trans, new_root);
2101 BUG_ON(ret);
2102
2103 iput(inode);
2104
2105 mutex_unlock(&root->fs_info->fs_mutex);
2106 return 0;
2107}
2108
Chris Masonc5739bb2007-04-10 09:27:04 -04002109static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2110{
2111 struct btrfs_trans_handle *trans;
2112 struct btrfs_key key;
2113 struct btrfs_root_item new_root_item;
2114 int ret;
2115 u64 objectid;
2116
Chris Mason2619ba12007-04-10 16:58:11 -04002117 if (!root->ref_cows)
2118 return -EINVAL;
2119
Chris Masonc5739bb2007-04-10 09:27:04 -04002120 mutex_lock(&root->fs_info->fs_mutex);
2121 trans = btrfs_start_transaction(root, 1);
2122 BUG_ON(!trans);
2123
2124 ret = btrfs_update_inode(trans, root, root->inode);
2125 BUG_ON(ret);
2126
Chris Mason1b05da22007-04-10 12:13:09 -04002127 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
2128 0, &objectid);
Chris Masonc5739bb2007-04-10 09:27:04 -04002129 BUG_ON(ret);
2130
Chris Masonc5739bb2007-04-10 09:27:04 -04002131 memcpy(&new_root_item, &root->root_item,
2132 sizeof(new_root_item));
2133
2134 key.objectid = objectid;
Chris Masonc5739bb2007-04-10 09:27:04 -04002135 key.offset = 1;
2136 key.flags = 0;
2137 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
Chris Mason7eccb902007-04-11 15:53:25 -04002138 btrfs_set_root_blocknr(&new_root_item, bh_blocknr(root->node));
Chris Masonc5739bb2007-04-10 09:27:04 -04002139
2140 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2141 &new_root_item);
2142 BUG_ON(ret);
2143
Chris Masonc5739bb2007-04-10 09:27:04 -04002144 /*
2145 * insert the directory item
2146 */
2147 key.offset = (u64)-1;
2148 ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
2149 name, namelen,
2150 root->fs_info->sb->s_root->d_inode->i_ino,
2151 &key, 0);
2152
2153 BUG_ON(ret);
2154
2155 ret = btrfs_inc_root_ref(trans, root);
2156 BUG_ON(ret);
2157
2158 ret = btrfs_commit_transaction(trans, root);
2159 BUG_ON(ret);
2160 mutex_unlock(&root->fs_info->fs_mutex);
2161 return 0;
2162}
2163
Chris Mason8352d8a2007-04-12 10:43:05 -04002164static int add_disk(struct btrfs_root *root, char *name, int namelen)
2165{
2166 struct block_device *bdev;
2167 struct btrfs_path *path;
2168 struct super_block *sb = root->fs_info->sb;
2169 struct btrfs_root *dev_root = root->fs_info->dev_root;
2170 struct btrfs_trans_handle *trans;
2171 struct btrfs_device_item *dev_item;
2172 struct btrfs_key key;
2173 u16 item_size;
2174 u64 num_blocks;
2175 u64 new_blocks;
Chris Masonb4100d62007-04-12 12:14:00 -04002176 u64 device_id;
Chris Mason8352d8a2007-04-12 10:43:05 -04002177 int ret;
Chris Masonb4100d62007-04-12 12:14:00 -04002178
Chris Mason8352d8a2007-04-12 10:43:05 -04002179printk("adding disk %s\n", name);
2180 path = btrfs_alloc_path();
2181 if (!path)
2182 return -ENOMEM;
2183 num_blocks = btrfs_super_total_blocks(root->fs_info->disk_super);
2184 bdev = open_bdev_excl(name, O_RDWR, sb);
2185 if (IS_ERR(bdev)) {
2186 ret = PTR_ERR(bdev);
2187printk("open bdev excl failed ret %d\n", ret);
2188 goto out_nolock;
2189 }
2190 set_blocksize(bdev, sb->s_blocksize);
2191 new_blocks = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
2192 key.objectid = num_blocks;
2193 key.offset = new_blocks;
2194 key.flags = 0;
2195 btrfs_set_key_type(&key, BTRFS_DEV_ITEM_KEY);
2196
2197 mutex_lock(&dev_root->fs_info->fs_mutex);
2198 trans = btrfs_start_transaction(dev_root, 1);
2199 item_size = sizeof(*dev_item) + namelen;
2200printk("insert empty on %Lu %Lu %u size %d\n", num_blocks, new_blocks, key.flags, item_size);
2201 ret = btrfs_insert_empty_item(trans, dev_root, path, &key, item_size);
2202 if (ret) {
2203printk("insert failed %d\n", ret);
2204 close_bdev_excl(bdev);
2205 if (ret > 0)
2206 ret = -EEXIST;
2207 goto out;
2208 }
2209 dev_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
2210 path->slots[0], struct btrfs_device_item);
2211 btrfs_set_device_pathlen(dev_item, namelen);
2212 memcpy(dev_item + 1, name, namelen);
Chris Masonb4100d62007-04-12 12:14:00 -04002213
2214 device_id = btrfs_super_last_device_id(root->fs_info->disk_super) + 1;
2215 btrfs_set_super_last_device_id(root->fs_info->disk_super, device_id);
2216 btrfs_set_device_id(dev_item, device_id);
Chris Mason8352d8a2007-04-12 10:43:05 -04002217 mark_buffer_dirty(path->nodes[0]);
2218
Chris Masonb4100d62007-04-12 12:14:00 -04002219 ret = btrfs_insert_dev_radix(root, bdev, device_id, num_blocks,
2220 new_blocks);
Chris Mason8352d8a2007-04-12 10:43:05 -04002221
2222 if (!ret) {
2223 btrfs_set_super_total_blocks(root->fs_info->disk_super,
2224 num_blocks + new_blocks);
2225 i_size_write(root->fs_info->btree_inode,
2226 (num_blocks + new_blocks) <<
2227 root->fs_info->btree_inode->i_blkbits);
2228 }
2229
2230out:
2231 ret = btrfs_commit_transaction(trans, dev_root);
2232 BUG_ON(ret);
2233 mutex_unlock(&root->fs_info->fs_mutex);
2234out_nolock:
2235 btrfs_free_path(path);
2236
2237 return ret;
2238}
2239
Chris Masonc5739bb2007-04-10 09:27:04 -04002240static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int
2241 cmd, unsigned long arg)
2242{
2243 struct btrfs_root *root = BTRFS_I(inode)->root;
2244 struct btrfs_ioctl_vol_args vol_args;
Chris Mason8352d8a2007-04-12 10:43:05 -04002245 int ret = 0;
Chris Mason7e381802007-04-19 15:36:27 -04002246 struct btrfs_dir_item *di;
Chris Masonc5739bb2007-04-10 09:27:04 -04002247 int namelen;
Chris Mason2619ba12007-04-10 16:58:11 -04002248 struct btrfs_path *path;
2249 u64 root_dirid;
Chris Masonc5739bb2007-04-10 09:27:04 -04002250
Chris Masonc5739bb2007-04-10 09:27:04 -04002251 switch (cmd) {
2252 case BTRFS_IOC_SNAP_CREATE:
2253 if (copy_from_user(&vol_args,
2254 (struct btrfs_ioctl_vol_args __user *)arg,
2255 sizeof(vol_args)))
2256 return -EFAULT;
2257 namelen = strlen(vol_args.name);
2258 if (namelen > BTRFS_VOL_NAME_MAX)
2259 return -EINVAL;
Chris Mason2619ba12007-04-10 16:58:11 -04002260 path = btrfs_alloc_path();
2261 if (!path)
2262 return -ENOMEM;
Chris Mason2d13d8d2007-04-10 20:07:20 -04002263 root_dirid = root->fs_info->sb->s_root->d_inode->i_ino,
Chris Mason2619ba12007-04-10 16:58:11 -04002264 mutex_lock(&root->fs_info->fs_mutex);
Chris Mason7e381802007-04-19 15:36:27 -04002265 di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root,
Chris Mason2619ba12007-04-10 16:58:11 -04002266 path, root_dirid,
2267 vol_args.name, namelen, 0);
2268 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason2d13d8d2007-04-10 20:07:20 -04002269 btrfs_free_path(path);
Chris Mason7e381802007-04-19 15:36:27 -04002270 if (di && !IS_ERR(di))
Chris Mason2619ba12007-04-10 16:58:11 -04002271 return -EEXIST;
2272
2273 if (root == root->fs_info->tree_root)
2274 ret = create_subvol(root, vol_args.name, namelen);
2275 else
2276 ret = create_snapshot(root, vol_args.name, namelen);
Chris Masonc5739bb2007-04-10 09:27:04 -04002277 WARN_ON(ret);
2278 break;
Chris Mason8352d8a2007-04-12 10:43:05 -04002279 case BTRFS_IOC_ADD_DISK:
2280 if (copy_from_user(&vol_args,
2281 (struct btrfs_ioctl_vol_args __user *)arg,
2282 sizeof(vol_args)))
2283 return -EFAULT;
2284 namelen = strlen(vol_args.name);
2285 if (namelen > BTRFS_VOL_NAME_MAX)
2286 return -EINVAL;
2287 vol_args.name[namelen] = '\0';
2288 ret = add_disk(root, vol_args.name, namelen);
2289 break;
Chris Masonc5739bb2007-04-10 09:27:04 -04002290 default:
2291 return -ENOTTY;
2292 }
Chris Mason8352d8a2007-04-12 10:43:05 -04002293 return ret;
Chris Masonc5739bb2007-04-10 09:27:04 -04002294}
2295
Chris Mason2c90e5d2007-04-02 10:50:19 -04002296static struct kmem_cache *btrfs_inode_cachep;
2297struct kmem_cache *btrfs_trans_handle_cachep;
2298struct kmem_cache *btrfs_transaction_cachep;
2299struct kmem_cache *btrfs_bit_radix_cachep;
2300struct kmem_cache *btrfs_path_cachep;
2301
2302/*
2303 * Called inside transaction, so use GFP_NOFS
2304 */
2305static struct inode *btrfs_alloc_inode(struct super_block *sb)
2306{
2307 struct btrfs_inode *ei;
2308
2309 ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS);
2310 if (!ei)
2311 return NULL;
Chris Mason2c90e5d2007-04-02 10:50:19 -04002312 return &ei->vfs_inode;
2313}
2314
2315static void btrfs_destroy_inode(struct inode *inode)
2316{
Chris Mason2c90e5d2007-04-02 10:50:19 -04002317 WARN_ON(!list_empty(&inode->i_dentry));
Chris Mason2c90e5d2007-04-02 10:50:19 -04002318 WARN_ON(inode->i_data.nrpages);
2319
Chris Mason2c90e5d2007-04-02 10:50:19 -04002320 kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
2321}
2322
2323static void init_once(void * foo, struct kmem_cache * cachep,
2324 unsigned long flags)
2325{
2326 struct btrfs_inode *ei = (struct btrfs_inode *) foo;
2327
2328 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
2329 SLAB_CTOR_CONSTRUCTOR) {
2330 inode_init_once(&ei->vfs_inode);
2331 }
2332}
2333
2334static int init_inodecache(void)
2335{
2336 btrfs_inode_cachep = kmem_cache_create("btrfs_inode_cache",
2337 sizeof(struct btrfs_inode),
2338 0, (SLAB_RECLAIM_ACCOUNT|
2339 SLAB_MEM_SPREAD),
2340 init_once, NULL);
2341 btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle_cache",
2342 sizeof(struct btrfs_trans_handle),
2343 0, (SLAB_RECLAIM_ACCOUNT|
2344 SLAB_MEM_SPREAD),
2345 NULL, NULL);
2346 btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction_cache",
2347 sizeof(struct btrfs_transaction),
2348 0, (SLAB_RECLAIM_ACCOUNT|
2349 SLAB_MEM_SPREAD),
2350 NULL, NULL);
2351 btrfs_path_cachep = kmem_cache_create("btrfs_path_cache",
2352 sizeof(struct btrfs_transaction),
2353 0, (SLAB_RECLAIM_ACCOUNT|
2354 SLAB_MEM_SPREAD),
2355 NULL, NULL);
2356 btrfs_bit_radix_cachep = kmem_cache_create("btrfs_radix",
2357 256,
2358 0, (SLAB_RECLAIM_ACCOUNT|
2359 SLAB_MEM_SPREAD |
2360 SLAB_DESTROY_BY_RCU),
2361 NULL, NULL);
2362 if (btrfs_inode_cachep == NULL || btrfs_trans_handle_cachep == NULL ||
2363 btrfs_transaction_cachep == NULL || btrfs_bit_radix_cachep == NULL)
2364 return -ENOMEM;
2365 return 0;
2366}
2367
2368static void destroy_inodecache(void)
2369{
2370 kmem_cache_destroy(btrfs_inode_cachep);
2371 kmem_cache_destroy(btrfs_trans_handle_cachep);
2372 kmem_cache_destroy(btrfs_transaction_cachep);
2373 kmem_cache_destroy(btrfs_bit_radix_cachep);
2374 kmem_cache_destroy(btrfs_path_cachep);
2375}
2376
Chris Mason2e635a22007-03-21 11:12:56 -04002377static int btrfs_get_sb(struct file_system_type *fs_type,
2378 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
2379{
2380 return get_sb_bdev(fs_type, flags, dev_name, data,
2381 btrfs_fill_super, mnt);
2382}
2383
Chris Mason236454d2007-04-19 13:37:44 -04002384
2385static int btrfs_getattr(struct vfsmount *mnt,
2386 struct dentry *dentry, struct kstat *stat)
2387{
2388 struct inode *inode = dentry->d_inode;
2389 generic_fillattr(inode, stat);
2390 stat->blksize = 256 * 1024;
2391 return 0;
2392}
2393
Chris Mason8fd17792007-04-19 21:01:03 -04002394static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
2395{
2396 struct btrfs_root *root = btrfs_sb(dentry->d_sb);
2397 struct btrfs_super_block *disk_super = root->fs_info->disk_super;
2398
2399 buf->f_namelen = BTRFS_NAME_LEN;
2400 buf->f_blocks = btrfs_super_total_blocks(disk_super);
2401 buf->f_bfree = buf->f_blocks - btrfs_super_blocks_used(disk_super);
2402 buf->f_bavail = buf->f_bfree;
2403 buf->f_bsize = dentry->d_sb->s_blocksize;
2404 buf->f_type = BTRFS_SUPER_MAGIC;
2405 return 0;
2406}
Chris Masonb5133862007-04-24 11:52:22 -04002407
Chris Mason2e635a22007-03-21 11:12:56 -04002408static struct file_system_type btrfs_fs_type = {
2409 .owner = THIS_MODULE,
2410 .name = "btrfs",
2411 .get_sb = btrfs_get_sb,
2412 .kill_sb = kill_block_super,
2413 .fs_flags = FS_REQUIRES_DEV,
2414};
2415
Chris Masone20d96d2007-03-22 12:13:20 -04002416static struct super_operations btrfs_super_ops = {
Chris Mason134e9732007-03-25 13:44:56 -04002417 .delete_inode = btrfs_delete_inode,
Chris Masone20d96d2007-03-22 12:13:20 -04002418 .put_super = btrfs_put_super,
2419 .read_inode = btrfs_read_locked_inode,
Chris Masond5719762007-03-23 10:01:08 -04002420 .write_super = btrfs_write_super,
2421 .sync_fs = btrfs_sync_fs,
Chris Mason4730a4b2007-03-26 12:00:39 -04002422 .write_inode = btrfs_write_inode,
Chris Masonb5133862007-04-24 11:52:22 -04002423 .dirty_inode = btrfs_dirty_inode,
Chris Mason2c90e5d2007-04-02 10:50:19 -04002424 .alloc_inode = btrfs_alloc_inode,
2425 .destroy_inode = btrfs_destroy_inode,
Chris Mason8fd17792007-04-19 21:01:03 -04002426 .statfs = btrfs_statfs,
Chris Masone20d96d2007-03-22 12:13:20 -04002427};
2428
2429static struct inode_operations btrfs_dir_inode_operations = {
2430 .lookup = btrfs_lookup,
Chris Masond5719762007-03-23 10:01:08 -04002431 .create = btrfs_create,
Chris Mason134e9732007-03-25 13:44:56 -04002432 .unlink = btrfs_unlink,
Chris Masonf7922032007-03-25 20:17:36 -04002433 .mkdir = btrfs_mkdir,
Chris Mason5f443fd2007-03-27 13:42:32 -04002434 .rmdir = btrfs_rmdir,
Chris Masone20d96d2007-03-22 12:13:20 -04002435};
2436
Chris Masond6e4a422007-04-06 15:37:36 -04002437static struct inode_operations btrfs_dir_ro_inode_operations = {
2438 .lookup = btrfs_lookup,
2439};
2440
Chris Masone20d96d2007-03-22 12:13:20 -04002441static struct file_operations btrfs_dir_file_operations = {
2442 .llseek = generic_file_llseek,
2443 .read = generic_read_dir,
2444 .readdir = btrfs_readdir,
Chris Masonc5739bb2007-04-10 09:27:04 -04002445 .ioctl = btrfs_ioctl,
Chris Masone20d96d2007-03-22 12:13:20 -04002446};
2447
Chris Masondee26a92007-03-26 16:00:06 -04002448static struct address_space_operations btrfs_aops = {
2449 .readpage = btrfs_readpage,
Chris Masondee26a92007-03-26 16:00:06 -04002450 .writepage = btrfs_writepage,
2451 .sync_page = block_sync_page,
2452 .prepare_write = btrfs_prepare_write,
Chris Mason75dfe392007-03-29 11:56:46 -04002453 .commit_write = btrfs_commit_write,
Chris Masondee26a92007-03-26 16:00:06 -04002454};
2455
2456static struct inode_operations btrfs_file_inode_operations = {
Chris Masonf4b9aa82007-03-27 11:05:53 -04002457 .truncate = btrfs_truncate,
Chris Mason236454d2007-04-19 13:37:44 -04002458 .getattr = btrfs_getattr,
Chris Masondee26a92007-03-26 16:00:06 -04002459};
2460
2461static struct file_operations btrfs_file_operations = {
2462 .llseek = generic_file_llseek,
2463 .read = do_sync_read,
Chris Masone8f05c42007-04-04 14:30:09 -04002464 .aio_read = btrfs_file_aio_read,
2465 .write = btrfs_file_write,
Chris Masondee26a92007-03-26 16:00:06 -04002466 .mmap = generic_file_mmap,
2467 .open = generic_file_open,
Chris Masonc5739bb2007-04-10 09:27:04 -04002468 .ioctl = btrfs_ioctl,
Chris Mason8fd17792007-04-19 21:01:03 -04002469 .fsync = btrfs_sync_file,
Chris Masondee26a92007-03-26 16:00:06 -04002470};
Chris Masone20d96d2007-03-22 12:13:20 -04002471
Chris Mason2e635a22007-03-21 11:12:56 -04002472static int __init init_btrfs_fs(void)
2473{
Chris Mason2c90e5d2007-04-02 10:50:19 -04002474 int err;
Chris Mason2e635a22007-03-21 11:12:56 -04002475 printk("btrfs loaded!\n");
Chris Mason2c90e5d2007-04-02 10:50:19 -04002476 err = init_inodecache();
2477 if (err)
2478 return err;
Chris Masond6e4a422007-04-06 15:37:36 -04002479 kset_set_kset_s(&btrfs_subsys, fs_subsys);
2480 err = subsystem_register(&btrfs_subsys);
2481 if (err)
2482 goto out;
Chris Mason2e635a22007-03-21 11:12:56 -04002483 return register_filesystem(&btrfs_fs_type);
Chris Masond6e4a422007-04-06 15:37:36 -04002484out:
2485 destroy_inodecache();
2486 return err;
Chris Mason2e635a22007-03-21 11:12:56 -04002487}
2488
2489static void __exit exit_btrfs_fs(void)
2490{
Chris Mason2c90e5d2007-04-02 10:50:19 -04002491 destroy_inodecache();
Chris Mason2e635a22007-03-21 11:12:56 -04002492 unregister_filesystem(&btrfs_fs_type);
Chris Masond6e4a422007-04-06 15:37:36 -04002493 subsystem_unregister(&btrfs_subsys);
Chris Mason2e635a22007-03-21 11:12:56 -04002494 printk("btrfs unloaded\n");
2495}
2496
2497module_init(init_btrfs_fs)
2498module_exit(exit_btrfs_fs)
2499
2500MODULE_LICENSE("GPL");