blob: b58b4cf667667d1b8aba4b9583141509769ed28d [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 Mason3a686372007-05-24 13:35:57 -040020#include "print-tree.h"
Chris Mason2e635a22007-03-21 11:12:56 -040021
Chris Masonc5739bb2007-04-10 09:27:04 -040022struct btrfs_iget_args {
23 u64 ino;
24 struct btrfs_root *root;
25};
26
Chris Mason2e635a22007-03-21 11:12:56 -040027#define BTRFS_SUPER_MAGIC 0x9123682E
Chris Masone20d96d2007-03-22 12:13:20 -040028
29static struct inode_operations btrfs_dir_inode_operations;
Chris Mason2b8d99a2007-05-24 08:34:10 -040030static struct inode_operations btrfs_symlink_inode_operations;
Chris Masond6e4a422007-04-06 15:37:36 -040031static struct inode_operations btrfs_dir_ro_inode_operations;
Chris Masone20d96d2007-03-22 12:13:20 -040032static struct super_operations btrfs_super_ops;
33static struct file_operations btrfs_dir_file_operations;
Chris Masondee26a92007-03-26 16:00:06 -040034static struct inode_operations btrfs_file_inode_operations;
35static struct address_space_operations btrfs_aops;
Chris Mason2b8d99a2007-05-24 08:34:10 -040036static struct address_space_operations btrfs_symlink_aops;
Chris Masondee26a92007-03-26 16:00:06 -040037static struct file_operations btrfs_file_operations;
Chris Masone20d96d2007-03-22 12:13:20 -040038
Chris Mason1de037a2007-05-29 15:17:08 -040039static int drop_extents(struct btrfs_trans_handle *trans,
40 struct btrfs_root *root,
41 struct inode *inode,
42 u64 start, u64 end, u64 *hint_block);
43static int btrfs_get_block(struct inode *inode, sector_t iblock,
44 struct buffer_head *result, int create);
45
Chris Masonfabb5682007-06-07 22:13:21 -040046
47#define S_SHIFT 12
48static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
49 [S_IFREG >> S_SHIFT] = BTRFS_FT_REG_FILE,
50 [S_IFDIR >> S_SHIFT] = BTRFS_FT_DIR,
51 [S_IFCHR >> S_SHIFT] = BTRFS_FT_CHRDEV,
52 [S_IFBLK >> S_SHIFT] = BTRFS_FT_BLKDEV,
53 [S_IFIFO >> S_SHIFT] = BTRFS_FT_FIFO,
54 [S_IFSOCK >> S_SHIFT] = BTRFS_FT_SOCK,
55 [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK,
56};
57
Chris Masone20d96d2007-03-22 12:13:20 -040058static void btrfs_read_locked_inode(struct inode *inode)
Chris Mason2e635a22007-03-21 11:12:56 -040059{
Chris Mason5caf2a02007-04-02 11:20:42 -040060 struct btrfs_path *path;
Chris Masone20d96d2007-03-22 12:13:20 -040061 struct btrfs_inode_item *inode_item;
Chris Masond6e4a422007-04-06 15:37:36 -040062 struct btrfs_root *root = BTRFS_I(inode)->root;
63 struct btrfs_key location;
Chris Mason31f3c992007-04-30 15:25:45 -040064 struct btrfs_block_group_cache *alloc_group;
65 u64 alloc_group_block;
Chris Masone20d96d2007-03-22 12:13:20 -040066 int ret;
Chris Masonf4b9aa82007-03-27 11:05:53 -040067
Chris Mason5caf2a02007-04-02 11:20:42 -040068 path = btrfs_alloc_path();
69 BUG_ON(!path);
70 btrfs_init_path(path);
Chris Masonf4b9aa82007-03-27 11:05:53 -040071 mutex_lock(&root->fs_info->fs_mutex);
72
Chris Masond6e4a422007-04-06 15:37:36 -040073 memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
74 ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
Chris Masone20d96d2007-03-22 12:13:20 -040075 if (ret) {
Chris Mason7cfcc172007-04-02 14:53:59 -040076 btrfs_free_path(path);
Chris Masond6e4a422007-04-06 15:37:36 -040077 goto make_bad;
Chris Mason2e635a22007-03-21 11:12:56 -040078 }
Chris Mason5caf2a02007-04-02 11:20:42 -040079 inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
80 path->slots[0],
Chris Masone20d96d2007-03-22 12:13:20 -040081 struct btrfs_inode_item);
82
Chris Masone20d96d2007-03-22 12:13:20 -040083 inode->i_mode = btrfs_inode_mode(inode_item);
84 inode->i_nlink = btrfs_inode_nlink(inode_item);
85 inode->i_uid = btrfs_inode_uid(inode_item);
86 inode->i_gid = btrfs_inode_gid(inode_item);
87 inode->i_size = btrfs_inode_size(inode_item);
88 inode->i_atime.tv_sec = btrfs_timespec_sec(&inode_item->atime);
89 inode->i_atime.tv_nsec = btrfs_timespec_nsec(&inode_item->atime);
90 inode->i_mtime.tv_sec = btrfs_timespec_sec(&inode_item->mtime);
91 inode->i_mtime.tv_nsec = btrfs_timespec_nsec(&inode_item->mtime);
92 inode->i_ctime.tv_sec = btrfs_timespec_sec(&inode_item->ctime);
93 inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime);
94 inode->i_blocks = btrfs_inode_nblocks(inode_item);
95 inode->i_generation = btrfs_inode_generation(inode_item);
Chris Mason31f3c992007-04-30 15:25:45 -040096 alloc_group_block = btrfs_inode_block_group(inode_item);
97 ret = radix_tree_gang_lookup(&root->fs_info->block_group_radix,
98 (void **)&alloc_group,
99 alloc_group_block, 1);
100 BUG_ON(!ret);
101 BTRFS_I(inode)->block_group = alloc_group;
Chris Mason5caf2a02007-04-02 11:20:42 -0400102
Chris Mason5caf2a02007-04-02 11:20:42 -0400103 btrfs_free_path(path);
104 inode_item = NULL;
105
Chris Masonf4b9aa82007-03-27 11:05:53 -0400106 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason1b05da22007-04-10 12:13:09 -0400107
Chris Masone20d96d2007-03-22 12:13:20 -0400108 switch (inode->i_mode & S_IFMT) {
109#if 0
110 default:
111 init_special_inode(inode, inode->i_mode,
112 btrfs_inode_rdev(inode_item));
113 break;
114#endif
115 case S_IFREG:
Chris Masondee26a92007-03-26 16:00:06 -0400116 inode->i_mapping->a_ops = &btrfs_aops;
117 inode->i_fop = &btrfs_file_operations;
118 inode->i_op = &btrfs_file_inode_operations;
Chris Masone20d96d2007-03-22 12:13:20 -0400119 break;
120 case S_IFDIR:
Chris Masone20d96d2007-03-22 12:13:20 -0400121 inode->i_fop = &btrfs_dir_file_operations;
Chris Masond6e4a422007-04-06 15:37:36 -0400122 if (root == root->fs_info->tree_root)
123 inode->i_op = &btrfs_dir_ro_inode_operations;
124 else
125 inode->i_op = &btrfs_dir_inode_operations;
Chris Masone20d96d2007-03-22 12:13:20 -0400126 break;
127 case S_IFLNK:
Chris Mason2b8d99a2007-05-24 08:34:10 -0400128 inode->i_op = &btrfs_symlink_inode_operations;
129 inode->i_mapping->a_ops = &btrfs_symlink_aops;
Chris Masone20d96d2007-03-22 12:13:20 -0400130 break;
131 }
Chris Masone20d96d2007-03-22 12:13:20 -0400132 return;
Chris Masond6e4a422007-04-06 15:37:36 -0400133
134make_bad:
135 btrfs_release_path(root, path);
136 btrfs_free_path(path);
137 mutex_unlock(&root->fs_info->fs_mutex);
138 make_bad_inode(inode);
Chris Mason2e635a22007-03-21 11:12:56 -0400139}
140
Chris Masonf68cad02007-04-24 12:44:26 -0400141static void fill_inode_item(struct btrfs_inode_item *item,
142 struct inode *inode)
143{
144 btrfs_set_inode_uid(item, inode->i_uid);
145 btrfs_set_inode_gid(item, inode->i_gid);
146 btrfs_set_inode_size(item, inode->i_size);
147 btrfs_set_inode_mode(item, inode->i_mode);
148 btrfs_set_inode_nlink(item, inode->i_nlink);
149 btrfs_set_timespec_sec(&item->atime, inode->i_atime.tv_sec);
150 btrfs_set_timespec_nsec(&item->atime, inode->i_atime.tv_nsec);
151 btrfs_set_timespec_sec(&item->mtime, inode->i_mtime.tv_sec);
152 btrfs_set_timespec_nsec(&item->mtime, inode->i_mtime.tv_nsec);
153 btrfs_set_timespec_sec(&item->ctime, inode->i_ctime.tv_sec);
154 btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
155 btrfs_set_inode_nblocks(item, inode->i_blocks);
156 btrfs_set_inode_generation(item, inode->i_generation);
Chris Mason31f3c992007-04-30 15:25:45 -0400157 btrfs_set_inode_block_group(item,
158 BTRFS_I(inode)->block_group->key.objectid);
Chris Masonf68cad02007-04-24 12:44:26 -0400159}
160
Chris Masonf68cad02007-04-24 12:44:26 -0400161static int btrfs_update_inode(struct btrfs_trans_handle *trans,
162 struct btrfs_root *root,
163 struct inode *inode)
164{
165 struct btrfs_inode_item *inode_item;
166 struct btrfs_path *path;
167 int ret;
168
169 path = btrfs_alloc_path();
170 BUG_ON(!path);
171 btrfs_init_path(path);
172 ret = btrfs_lookup_inode(trans, root, path,
173 &BTRFS_I(inode)->location, 1);
174 if (ret) {
175 if (ret > 0)
176 ret = -ENOENT;
177 goto failed;
178 }
179
180 inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
181 path->slots[0],
182 struct btrfs_inode_item);
183
184 fill_inode_item(inode_item, inode);
185 btrfs_mark_buffer_dirty(path->nodes[0]);
186 ret = 0;
187failed:
188 btrfs_release_path(root, path);
189 btrfs_free_path(path);
190 return ret;
191}
192
193
Chris Mason5f443fd2007-03-27 13:42:32 -0400194static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
195 struct btrfs_root *root,
196 struct inode *dir,
197 struct dentry *dentry)
Chris Mason134e9732007-03-25 13:44:56 -0400198{
Chris Mason5caf2a02007-04-02 11:20:42 -0400199 struct btrfs_path *path;
Chris Mason134e9732007-03-25 13:44:56 -0400200 const char *name = dentry->d_name.name;
201 int name_len = dentry->d_name.len;
Chris Mason7e381802007-04-19 15:36:27 -0400202 int ret = 0;
Chris Mason134e9732007-03-25 13:44:56 -0400203 u64 objectid;
204 struct btrfs_dir_item *di;
205
Chris Mason5caf2a02007-04-02 11:20:42 -0400206 path = btrfs_alloc_path();
207 BUG_ON(!path);
208 btrfs_init_path(path);
Chris Mason7e381802007-04-19 15:36:27 -0400209 di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
Chris Mason134e9732007-03-25 13:44:56 -0400210 name, name_len, -1);
Chris Mason7e381802007-04-19 15:36:27 -0400211 if (IS_ERR(di)) {
212 ret = PTR_ERR(di);
Chris Mason134e9732007-03-25 13:44:56 -0400213 goto err;
Chris Mason7e381802007-04-19 15:36:27 -0400214 }
215 if (!di) {
Chris Mason134e9732007-03-25 13:44:56 -0400216 ret = -ENOENT;
217 goto err;
218 }
Chris Masond6e4a422007-04-06 15:37:36 -0400219 objectid = btrfs_disk_key_objectid(&di->location);
Chris Mason7e381802007-04-19 15:36:27 -0400220 ret = btrfs_delete_one_dir_name(trans, root, path, di);
221 BUG_ON(ret);
222 btrfs_release_path(root, path);
Chris Mason134e9732007-03-25 13:44:56 -0400223
Chris Mason7e381802007-04-19 15:36:27 -0400224 di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino,
225 objectid, name, name_len, -1);
226 if (IS_ERR(di)) {
227 ret = PTR_ERR(di);
228 goto err;
229 }
230 if (!di) {
231 ret = -ENOENT;
232 goto err;
233 }
234 ret = btrfs_delete_one_dir_name(trans, root, path, di);
Chris Mason134e9732007-03-25 13:44:56 -0400235 BUG_ON(ret);
Chris Mason5f26f772007-04-05 10:38:44 -0400236
Chris Mason134e9732007-03-25 13:44:56 -0400237 dentry->d_inode->i_ctime = dir->i_ctime;
238err:
Chris Mason5caf2a02007-04-02 11:20:42 -0400239 btrfs_free_path(path);
Chris Masonf68cad02007-04-24 12:44:26 -0400240 if (!ret) {
Chris Mason5f26f772007-04-05 10:38:44 -0400241 dir->i_size -= name_len * 2;
Chris Masonf68cad02007-04-24 12:44:26 -0400242 btrfs_update_inode(trans, root, dir);
243 drop_nlink(dentry->d_inode);
244 btrfs_update_inode(trans, root, dentry->d_inode);
Chris Masoncd1bc462007-04-27 10:08:34 -0400245 dir->i_sb->s_dirt = 1;
Chris Masond4dbff92007-04-04 14:08:15 -0400246 }
Chris Mason134e9732007-03-25 13:44:56 -0400247 return ret;
248}
249
Chris Mason5f443fd2007-03-27 13:42:32 -0400250static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
251{
252 struct btrfs_root *root;
253 struct btrfs_trans_handle *trans;
254 int ret;
255
Chris Masond6e4a422007-04-06 15:37:36 -0400256 root = BTRFS_I(dir)->root;
Chris Mason5f443fd2007-03-27 13:42:32 -0400257 mutex_lock(&root->fs_info->fs_mutex);
258 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -0400259 btrfs_set_trans_block_group(trans, dir);
Chris Mason5f443fd2007-03-27 13:42:32 -0400260 ret = btrfs_unlink_trans(trans, root, dir, dentry);
261 btrfs_end_transaction(trans, root);
262 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason35b7e472007-05-02 15:53:43 -0400263 btrfs_btree_balance_dirty(root);
Chris Mason5f443fd2007-03-27 13:42:32 -0400264 return ret;
265}
266
267static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
268{
269 struct inode *inode = dentry->d_inode;
270 int err;
271 int ret;
Chris Masond6e4a422007-04-06 15:37:36 -0400272 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Mason5caf2a02007-04-02 11:20:42 -0400273 struct btrfs_path *path;
Chris Mason5f443fd2007-03-27 13:42:32 -0400274 struct btrfs_key key;
275 struct btrfs_trans_handle *trans;
Chris Mason5f26f772007-04-05 10:38:44 -0400276 struct btrfs_key found_key;
277 int found_type;
Chris Mason5f443fd2007-03-27 13:42:32 -0400278 struct btrfs_leaf *leaf;
Chris Mason5f26f772007-04-05 10:38:44 -0400279 char *goodnames = "..";
Chris Mason5f443fd2007-03-27 13:42:32 -0400280
Chris Mason5caf2a02007-04-02 11:20:42 -0400281 path = btrfs_alloc_path();
282 BUG_ON(!path);
283 btrfs_init_path(path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400284 mutex_lock(&root->fs_info->fs_mutex);
285 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -0400286 btrfs_set_trans_block_group(trans, dir);
Chris Mason5f443fd2007-03-27 13:42:32 -0400287 key.objectid = inode->i_ino;
288 key.offset = (u64)-1;
Chris Mason5f26f772007-04-05 10:38:44 -0400289 key.flags = (u32)-1;
290 while(1) {
291 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
292 if (ret < 0) {
293 err = ret;
294 goto out;
295 }
296 BUG_ON(ret == 0);
297 if (path->slots[0] == 0) {
298 err = -ENOENT;
299 goto out;
300 }
301 path->slots[0]--;
302 leaf = btrfs_buffer_leaf(path->nodes[0]);
303 btrfs_disk_key_to_cpu(&found_key,
304 &leaf->items[path->slots[0]].key);
305 found_type = btrfs_key_type(&found_key);
306 if (found_key.objectid != inode->i_ino) {
307 err = -ENOENT;
308 goto out;
309 }
310 if ((found_type != BTRFS_DIR_ITEM_KEY &&
311 found_type != BTRFS_DIR_INDEX_KEY) ||
312 (!btrfs_match_dir_item_name(root, path, goodnames, 2) &&
313 !btrfs_match_dir_item_name(root, path, goodnames, 1))) {
314 err = -ENOTEMPTY;
315 goto out;
316 }
317 ret = btrfs_del_item(trans, root, path);
318 BUG_ON(ret);
Chris Mason5f443fd2007-03-27 13:42:32 -0400319
Chris Mason5f26f772007-04-05 10:38:44 -0400320 if (found_type == BTRFS_DIR_ITEM_KEY && found_key.offset == 1)
321 break;
322 btrfs_release_path(root, path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400323 }
Chris Mason5f26f772007-04-05 10:38:44 -0400324 ret = 0;
Chris Mason5caf2a02007-04-02 11:20:42 -0400325 btrfs_release_path(root, path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400326
327 /* now the directory is empty */
328 err = btrfs_unlink_trans(trans, root, dir, dentry);
329 if (!err) {
330 inode->i_size = 0;
331 }
332out:
Chris Mason7cfcc172007-04-02 14:53:59 -0400333 btrfs_release_path(root, path);
334 btrfs_free_path(path);
Chris Mason5f443fd2007-03-27 13:42:32 -0400335 mutex_unlock(&root->fs_info->fs_mutex);
336 ret = btrfs_end_transaction(trans, root);
Chris Mason35b7e472007-05-02 15:53:43 -0400337 btrfs_btree_balance_dirty(root);
Chris Mason5f443fd2007-03-27 13:42:32 -0400338 if (ret && !err)
339 err = ret;
340 return err;
341}
342
Chris Mason134e9732007-03-25 13:44:56 -0400343static int btrfs_free_inode(struct btrfs_trans_handle *trans,
344 struct btrfs_root *root,
345 struct inode *inode)
346{
Chris Mason5caf2a02007-04-02 11:20:42 -0400347 struct btrfs_path *path;
Chris Mason134e9732007-03-25 13:44:56 -0400348 int ret;
Chris Mason5caf2a02007-04-02 11:20:42 -0400349
Chris Mason134e9732007-03-25 13:44:56 -0400350 clear_inode(inode);
Chris Mason5caf2a02007-04-02 11:20:42 -0400351
352 path = btrfs_alloc_path();
353 BUG_ON(!path);
354 btrfs_init_path(path);
Chris Masond6e4a422007-04-06 15:37:36 -0400355 ret = btrfs_lookup_inode(trans, root, path,
356 &BTRFS_I(inode)->location, -1);
Chris Mason134e9732007-03-25 13:44:56 -0400357 BUG_ON(ret);
Chris Mason5caf2a02007-04-02 11:20:42 -0400358 ret = btrfs_del_item(trans, root, path);
Chris Mason134e9732007-03-25 13:44:56 -0400359 BUG_ON(ret);
Chris Mason5caf2a02007-04-02 11:20:42 -0400360 btrfs_free_path(path);
Chris Mason134e9732007-03-25 13:44:56 -0400361 return ret;
362}
363
Chris Masonde428b62007-05-18 13:28:27 -0400364static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path,
365 u64 objectid)
366{
367 struct btrfs_node *node;
368 int i;
369 int nritems;
370 u64 item_objectid;
371 u64 blocknr;
372 int slot;
373 int ret;
374
375 if (!path->nodes[1])
376 return;
377 node = btrfs_buffer_node(path->nodes[1]);
378 slot = path->slots[1];
379 if (slot == 0)
380 return;
381 nritems = btrfs_header_nritems(&node->header);
382 for (i = slot - 1; i >= 0; i--) {
383 item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
384 if (item_objectid != objectid)
385 break;
386 blocknr = btrfs_node_blockptr(node, i);
387 ret = readahead_tree_block(root, blocknr);
388 if (ret)
389 break;
390 }
391}
392
Chris Masonf4b9aa82007-03-27 11:05:53 -0400393static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
394 struct btrfs_root *root,
395 struct inode *inode)
396{
397 int ret;
Chris Mason5caf2a02007-04-02 11:20:42 -0400398 struct btrfs_path *path;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400399 struct btrfs_key key;
400 struct btrfs_disk_key *found_key;
Chris Masone06afa82007-05-23 15:44:28 -0400401 u32 found_type;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400402 struct btrfs_leaf *leaf;
Chris Mason1de037a2007-05-29 15:17:08 -0400403 struct btrfs_file_extent_item *fi;
Chris Masonf254e522007-03-29 15:15:27 -0400404 u64 extent_start = 0;
405 u64 extent_num_blocks = 0;
Chris Mason1de037a2007-05-29 15:17:08 -0400406 u64 item_end = 0;
Chris Masonf254e522007-03-29 15:15:27 -0400407 int found_extent;
Chris Mason1de037a2007-05-29 15:17:08 -0400408 int del_item;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400409
Chris Mason5caf2a02007-04-02 11:20:42 -0400410 path = btrfs_alloc_path();
411 BUG_ON(!path);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400412 /* FIXME, add redo link to tree so we don't leak on crash */
413 key.objectid = inode->i_ino;
414 key.offset = (u64)-1;
Chris Masone06afa82007-05-23 15:44:28 -0400415 key.flags = (u32)-1;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400416 while(1) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400417 btrfs_init_path(path);
Chris Mason1de037a2007-05-29 15:17:08 -0400418 fi = NULL;
Chris Mason5caf2a02007-04-02 11:20:42 -0400419 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400420 if (ret < 0) {
Chris Masonf4b9aa82007-03-27 11:05:53 -0400421 goto error;
422 }
423 if (ret > 0) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400424 BUG_ON(path->slots[0] == 0);
425 path->slots[0]--;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400426 }
Chris Masonde428b62007-05-18 13:28:27 -0400427 reada_truncate(root, path, inode->i_ino);
Chris Mason5caf2a02007-04-02 11:20:42 -0400428 leaf = btrfs_buffer_leaf(path->nodes[0]);
429 found_key = &leaf->items[path->slots[0]].key;
Chris Masone06afa82007-05-23 15:44:28 -0400430 found_type = btrfs_disk_key_type(found_key);
Chris Masonf4b9aa82007-03-27 11:05:53 -0400431 if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
432 break;
Chris Masone06afa82007-05-23 15:44:28 -0400433 if (found_type != BTRFS_CSUM_ITEM_KEY &&
434 found_type != BTRFS_DIR_ITEM_KEY &&
435 found_type != BTRFS_DIR_INDEX_KEY &&
436 found_type != BTRFS_EXTENT_DATA_KEY)
Chris Masonf4b9aa82007-03-27 11:05:53 -0400437 break;
Chris Mason1de037a2007-05-29 15:17:08 -0400438 item_end = btrfs_disk_key_offset(found_key);
439 if (found_type == BTRFS_EXTENT_DATA_KEY) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400440 fi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
441 path->slots[0],
Chris Masonf254e522007-03-29 15:15:27 -0400442 struct btrfs_file_extent_item);
Chris Mason236454d2007-04-19 13:37:44 -0400443 if (btrfs_file_extent_type(fi) !=
444 BTRFS_FILE_EXTENT_INLINE) {
Chris Mason1de037a2007-05-29 15:17:08 -0400445 item_end += btrfs_file_extent_num_blocks(fi) <<
446 inode->i_blkbits;
447 }
448 }
449 if (found_type == BTRFS_CSUM_ITEM_KEY) {
450 ret = btrfs_csum_truncate(trans, root, path,
451 inode->i_size);
452 BUG_ON(ret);
453 }
454 if (item_end < inode->i_size) {
455 if (found_type) {
456 btrfs_set_key_type(&key, found_type - 1);
457 continue;
458 }
459 break;
460 }
461 if (btrfs_disk_key_offset(found_key) >= inode->i_size)
462 del_item = 1;
463 else
464 del_item = 0;
465 found_extent = 0;
466
467 if (found_type == BTRFS_EXTENT_DATA_KEY &&
468 btrfs_file_extent_type(fi) !=
469 BTRFS_FILE_EXTENT_INLINE) {
470 u64 num_dec;
471 if (!del_item) {
472 u64 orig_num_blocks =
473 btrfs_file_extent_num_blocks(fi);
474 extent_num_blocks = inode->i_size -
475 btrfs_disk_key_offset(found_key) +
476 root->blocksize - 1;
477 extent_num_blocks >>= inode->i_blkbits;
478 btrfs_set_file_extent_num_blocks(fi,
479 extent_num_blocks);
480 inode->i_blocks -= (orig_num_blocks -
481 extent_num_blocks) << 3;
482 mark_buffer_dirty(path->nodes[0]);
483 } else {
Chris Mason236454d2007-04-19 13:37:44 -0400484 extent_start =
485 btrfs_file_extent_disk_blocknr(fi);
486 extent_num_blocks =
487 btrfs_file_extent_disk_num_blocks(fi);
488 /* FIXME blocksize != 4096 */
Chris Mason3a686372007-05-24 13:35:57 -0400489 num_dec = btrfs_file_extent_num_blocks(fi) << 3;
490 if (extent_start != 0) {
491 found_extent = 1;
492 inode->i_blocks -= num_dec;
493 }
Chris Mason236454d2007-04-19 13:37:44 -0400494 }
Chris Masonf254e522007-03-29 15:15:27 -0400495 }
Chris Mason1de037a2007-05-29 15:17:08 -0400496 if (del_item) {
497 ret = btrfs_del_item(trans, root, path);
498 BUG_ON(ret);
499 } else {
500 break;
501 }
Chris Mason5caf2a02007-04-02 11:20:42 -0400502 btrfs_release_path(root, path);
Chris Masonf254e522007-03-29 15:15:27 -0400503 if (found_extent) {
504 ret = btrfs_free_extent(trans, root, extent_start,
505 extent_num_blocks, 0);
506 BUG_ON(ret);
507 }
Chris Masonf4b9aa82007-03-27 11:05:53 -0400508 }
Chris Masonf4b9aa82007-03-27 11:05:53 -0400509 ret = 0;
510error:
Chris Mason5caf2a02007-04-02 11:20:42 -0400511 btrfs_release_path(root, path);
512 btrfs_free_path(path);
Chris Masoncd1bc462007-04-27 10:08:34 -0400513 inode->i_sb->s_dirt = 1;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400514 return ret;
515}
516
Chris Mason1de037a2007-05-29 15:17:08 -0400517static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
518{
519 struct inode *inode = mapping->host;
520 unsigned blocksize = 1 << inode->i_blkbits;
521 pgoff_t index = from >> PAGE_CACHE_SHIFT;
522 unsigned offset = from & (PAGE_CACHE_SIZE-1);
523 struct page *page;
524 char *kaddr;
525 int ret = 0;
526 struct btrfs_root *root = BTRFS_I(inode)->root;
527 u64 alloc_hint;
528 struct btrfs_key ins;
529 struct btrfs_trans_handle *trans;
530
531 if ((offset & (blocksize - 1)) == 0)
532 goto out;
533
534 ret = -ENOMEM;
535 page = grab_cache_page(mapping, index);
536 if (!page)
537 goto out;
538
539 if (!PageUptodate(page)) {
540 ret = mpage_readpage(page, btrfs_get_block);
541 lock_page(page);
542 if (!PageUptodate(page)) {
543 ret = -EIO;
544 goto out;
545 }
546 }
547 mutex_lock(&root->fs_info->fs_mutex);
548 trans = btrfs_start_transaction(root, 1);
549 btrfs_set_trans_block_group(trans, inode);
550
551 ret = drop_extents(trans, root, inode, page->index << PAGE_CACHE_SHIFT,
552 (page->index + 1) << PAGE_CACHE_SHIFT, &alloc_hint);
553 BUG_ON(ret);
554 ret = btrfs_alloc_extent(trans, root, inode->i_ino, 1,
555 alloc_hint, (u64)-1, &ins, 1);
556 BUG_ON(ret);
557 ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
558 page->index << PAGE_CACHE_SHIFT,
559 ins.objectid, 1, 1);
560 BUG_ON(ret);
561 SetPageChecked(page);
562 kaddr = kmap(page);
563 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
564 flush_dcache_page(page);
565 btrfs_csum_file_block(trans, root, inode->i_ino,
566 page->index << PAGE_CACHE_SHIFT,
567 kaddr, PAGE_CACHE_SIZE);
568 kunmap(page);
569 btrfs_end_transaction(trans, root);
570 mutex_unlock(&root->fs_info->fs_mutex);
571
572 set_page_dirty(page);
573 unlock_page(page);
574 page_cache_release(page);
575out:
576 return ret;
577}
578
Chris Mason3a686372007-05-24 13:35:57 -0400579static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
580{
581 struct inode *inode = dentry->d_inode;
582 int err;
583
584 err = inode_change_ok(inode, attr);
585 if (err)
586 return err;
587
588 if (S_ISREG(inode->i_mode) &&
589 attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
590 struct btrfs_trans_handle *trans;
591 struct btrfs_root *root = BTRFS_I(inode)->root;
592 u64 mask = root->blocksize - 1;
593 u64 pos = (inode->i_size + mask) & ~mask;
594 u64 hole_size;
595
Chris Mason1de037a2007-05-29 15:17:08 -0400596 if (attr->ia_size <= pos)
Chris Mason3a686372007-05-24 13:35:57 -0400597 goto out;
Chris Mason1de037a2007-05-29 15:17:08 -0400598
599 btrfs_truncate_page(inode->i_mapping, inode->i_size);
600
Chris Mason3a686372007-05-24 13:35:57 -0400601 hole_size = (attr->ia_size - pos + mask) & ~mask;
602 hole_size >>= inode->i_blkbits;
603
604 mutex_lock(&root->fs_info->fs_mutex);
605 trans = btrfs_start_transaction(root, 1);
606 btrfs_set_trans_block_group(trans, inode);
607 err = btrfs_insert_file_extent(trans, root, inode->i_ino,
608 pos, 0, 0, hole_size);
609 BUG_ON(err);
610 btrfs_end_transaction(trans, root);
611 mutex_unlock(&root->fs_info->fs_mutex);
612 }
Chris Mason1de037a2007-05-29 15:17:08 -0400613out:
Chris Mason3a686372007-05-24 13:35:57 -0400614 err = inode_setattr(inode, attr);
615
Chris Mason3a686372007-05-24 13:35:57 -0400616 return err;
617}
Chris Mason134e9732007-03-25 13:44:56 -0400618static void btrfs_delete_inode(struct inode *inode)
619{
620 struct btrfs_trans_handle *trans;
Chris Masond6e4a422007-04-06 15:37:36 -0400621 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masonf4b9aa82007-03-27 11:05:53 -0400622 int ret;
623
Chris Mason134e9732007-03-25 13:44:56 -0400624 truncate_inode_pages(&inode->i_data, 0);
625 if (is_bad_inode(inode)) {
626 goto no_delete;
627 }
628 inode->i_size = 0;
Chris Mason134e9732007-03-25 13:44:56 -0400629 mutex_lock(&root->fs_info->fs_mutex);
630 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -0400631 btrfs_set_trans_block_group(trans, inode);
Chris Masone06afa82007-05-23 15:44:28 -0400632 ret = btrfs_truncate_in_trans(trans, root, inode);
633 BUG_ON(ret);
Chris Mason134e9732007-03-25 13:44:56 -0400634 btrfs_free_inode(trans, root, inode);
635 btrfs_end_transaction(trans, root);
636 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason35b7e472007-05-02 15:53:43 -0400637 btrfs_btree_balance_dirty(root);
Chris Mason134e9732007-03-25 13:44:56 -0400638 return;
639no_delete:
640 clear_inode(inode);
641}
642
Chris Masone20d96d2007-03-22 12:13:20 -0400643static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
Chris Masond6e4a422007-04-06 15:37:36 -0400644 struct btrfs_key *location)
Chris Masone20d96d2007-03-22 12:13:20 -0400645{
646 const char *name = dentry->d_name.name;
647 int namelen = dentry->d_name.len;
648 struct btrfs_dir_item *di;
Chris Mason5caf2a02007-04-02 11:20:42 -0400649 struct btrfs_path *path;
Chris Masond6e4a422007-04-06 15:37:36 -0400650 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Masone20d96d2007-03-22 12:13:20 -0400651 int ret;
652
Chris Mason5caf2a02007-04-02 11:20:42 -0400653 path = btrfs_alloc_path();
654 BUG_ON(!path);
655 btrfs_init_path(path);
Chris Mason7e381802007-04-19 15:36:27 -0400656 di = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name,
Chris Masone20d96d2007-03-22 12:13:20 -0400657 namelen, 0);
Chris Mason7e381802007-04-19 15:36:27 -0400658 if (!di || IS_ERR(di)) {
Chris Masond6e4a422007-04-06 15:37:36 -0400659 location->objectid = 0;
Chris Mason2c90e5d2007-04-02 10:50:19 -0400660 ret = 0;
Chris Masone20d96d2007-03-22 12:13:20 -0400661 goto out;
662 }
Chris Masond6e4a422007-04-06 15:37:36 -0400663 btrfs_disk_key_to_cpu(location, &di->location);
Chris Masone20d96d2007-03-22 12:13:20 -0400664out:
Chris Mason5caf2a02007-04-02 11:20:42 -0400665 btrfs_release_path(root, path);
666 btrfs_free_path(path);
Chris Masone20d96d2007-03-22 12:13:20 -0400667 return ret;
668}
669
Chris Mason35b7e472007-05-02 15:53:43 -0400670static int fixup_tree_root_location(struct btrfs_root *root,
Chris Masond6e4a422007-04-06 15:37:36 -0400671 struct btrfs_key *location,
672 struct btrfs_root **sub_root)
673{
674 struct btrfs_path *path;
675 struct btrfs_root_item *ri;
Chris Masond6e4a422007-04-06 15:37:36 -0400676
677 if (btrfs_key_type(location) != BTRFS_ROOT_ITEM_KEY)
678 return 0;
679 if (location->objectid == BTRFS_ROOT_TREE_OBJECTID)
680 return 0;
681
682 path = btrfs_alloc_path();
683 BUG_ON(!path);
684 mutex_lock(&root->fs_info->fs_mutex);
685
Chris Mason0f7d52f2007-04-09 10:42:37 -0400686 *sub_root = btrfs_read_fs_root(root->fs_info, location);
687 if (IS_ERR(*sub_root))
688 return PTR_ERR(*sub_root);
689
690 ri = &(*sub_root)->root_item;
Chris Masond6e4a422007-04-06 15:37:36 -0400691 location->objectid = btrfs_root_dirid(ri);
692 location->flags = 0;
693 btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
694 location->offset = 0;
Chris Mason0f7d52f2007-04-09 10:42:37 -0400695
Chris Masond6e4a422007-04-06 15:37:36 -0400696 btrfs_free_path(path);
697 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason0f7d52f2007-04-09 10:42:37 -0400698 return 0;
Chris Masond6e4a422007-04-06 15:37:36 -0400699}
700
Chris Mason35b7e472007-05-02 15:53:43 -0400701static int btrfs_init_locked_inode(struct inode *inode, void *p)
Chris Masonc5739bb2007-04-10 09:27:04 -0400702{
703 struct btrfs_iget_args *args = p;
704 inode->i_ino = args->ino;
705 BTRFS_I(inode)->root = args->root;
706 return 0;
707}
708
Chris Mason35b7e472007-05-02 15:53:43 -0400709static int btrfs_find_actor(struct inode *inode, void *opaque)
Chris Masonc5739bb2007-04-10 09:27:04 -0400710{
711 struct btrfs_iget_args *args = opaque;
712 return (args->ino == inode->i_ino &&
713 args->root == BTRFS_I(inode)->root);
714}
715
Chris Mason35b7e472007-05-02 15:53:43 -0400716static struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
717 struct btrfs_root *root)
Chris Masonc5739bb2007-04-10 09:27:04 -0400718{
719 struct inode *inode;
720 struct btrfs_iget_args args;
721 args.ino = objectid;
722 args.root = root;
723
724 inode = iget5_locked(s, objectid, btrfs_find_actor,
725 btrfs_init_locked_inode,
726 (void *)&args);
727 return inode;
728}
Chris Masond6e4a422007-04-06 15:37:36 -0400729
Chris Masone20d96d2007-03-22 12:13:20 -0400730static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
731 struct nameidata *nd)
732{
733 struct inode * inode;
Chris Masond6e4a422007-04-06 15:37:36 -0400734 struct btrfs_inode *bi = BTRFS_I(dir);
735 struct btrfs_root *root = bi->root;
736 struct btrfs_root *sub_root = root;
737 struct btrfs_key location;
Chris Masone20d96d2007-03-22 12:13:20 -0400738 int ret;
739
740 if (dentry->d_name.len > BTRFS_NAME_LEN)
741 return ERR_PTR(-ENAMETOOLONG);
Chris Mason22b0ebd2007-03-30 08:47:31 -0400742 mutex_lock(&root->fs_info->fs_mutex);
Chris Masond6e4a422007-04-06 15:37:36 -0400743 ret = btrfs_inode_by_name(dir, dentry, &location);
Chris Mason22b0ebd2007-03-30 08:47:31 -0400744 mutex_unlock(&root->fs_info->fs_mutex);
Chris Masone20d96d2007-03-22 12:13:20 -0400745 if (ret < 0)
746 return ERR_PTR(ret);
747 inode = NULL;
Chris Masond6e4a422007-04-06 15:37:36 -0400748 if (location.objectid) {
749 ret = fixup_tree_root_location(root, &location, &sub_root);
750 if (ret < 0)
751 return ERR_PTR(ret);
752 if (ret > 0)
753 return ERR_PTR(-ENOENT);
Chris Masonc5739bb2007-04-10 09:27:04 -0400754 inode = btrfs_iget_locked(dir->i_sb, location.objectid,
755 sub_root);
Chris Masone20d96d2007-03-22 12:13:20 -0400756 if (!inode)
757 return ERR_PTR(-EACCES);
Chris Masond6e4a422007-04-06 15:37:36 -0400758 if (inode->i_state & I_NEW) {
Chris Mason0f7d52f2007-04-09 10:42:37 -0400759 if (sub_root != root) {
Chris Masonc5739bb2007-04-10 09:27:04 -0400760printk("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 -0400761 igrab(inode);
762 sub_root->inode = inode;
763 }
Chris Masond6e4a422007-04-06 15:37:36 -0400764 BTRFS_I(inode)->root = sub_root;
765 memcpy(&BTRFS_I(inode)->location, &location,
766 sizeof(location));
767 btrfs_read_locked_inode(inode);
768 unlock_new_inode(inode);
769 }
Chris Masone20d96d2007-03-22 12:13:20 -0400770 }
771 return d_splice_alias(inode, dentry);
772}
773
Chris Masonde428b62007-05-18 13:28:27 -0400774static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path,
775 u64 objectid)
Chris Mason090d1872007-05-01 08:53:32 -0400776{
777 struct btrfs_node *node;
778 int i;
Chris Masonde428b62007-05-18 13:28:27 -0400779 u32 nritems;
Chris Mason090d1872007-05-01 08:53:32 -0400780 u64 item_objectid;
781 u64 blocknr;
782 int slot;
Chris Masonde428b62007-05-18 13:28:27 -0400783 int ret;
Chris Mason090d1872007-05-01 08:53:32 -0400784
785 if (!path->nodes[1])
786 return;
787 node = btrfs_buffer_node(path->nodes[1]);
788 slot = path->slots[1];
Chris Mason090d1872007-05-01 08:53:32 -0400789 nritems = btrfs_header_nritems(&node->header);
Chris Masonde428b62007-05-18 13:28:27 -0400790 for (i = slot + 1; i < nritems; i++) {
Chris Mason090d1872007-05-01 08:53:32 -0400791 item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
792 if (item_objectid != objectid)
793 break;
794 blocknr = btrfs_node_blockptr(node, i);
Chris Masonde428b62007-05-18 13:28:27 -0400795 ret = readahead_tree_block(root, blocknr);
796 if (ret)
797 break;
Chris Mason090d1872007-05-01 08:53:32 -0400798 }
799}
Chris Masonfabb5682007-06-07 22:13:21 -0400800static unsigned char btrfs_filetype_table[] = {
801 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
802};
Chris Mason090d1872007-05-01 08:53:32 -0400803
Chris Masone20d96d2007-03-22 12:13:20 -0400804static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
805{
806 struct inode *inode = filp->f_path.dentry->d_inode;
Chris Masond6e4a422007-04-06 15:37:36 -0400807 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masone20d96d2007-03-22 12:13:20 -0400808 struct btrfs_item *item;
809 struct btrfs_dir_item *di;
810 struct btrfs_key key;
Chris Mason5caf2a02007-04-02 11:20:42 -0400811 struct btrfs_path *path;
Chris Masone20d96d2007-03-22 12:13:20 -0400812 int ret;
813 u32 nritems;
814 struct btrfs_leaf *leaf;
815 int slot;
816 int advance;
Chris Masonfabb5682007-06-07 22:13:21 -0400817 unsigned char d_type;
Chris Mason7f5c1512007-03-23 15:56:19 -0400818 int over = 0;
Chris Mason7e381802007-04-19 15:36:27 -0400819 u32 di_cur;
820 u32 di_total;
821 u32 di_len;
822 int key_type = BTRFS_DIR_INDEX_KEY;
Chris Masond6e4a422007-04-06 15:37:36 -0400823
824 /* FIXME, use a real flag for deciding about the key type */
825 if (root->fs_info->tree_root == root)
826 key_type = BTRFS_DIR_ITEM_KEY;
Chris Mason22b0ebd2007-03-30 08:47:31 -0400827 mutex_lock(&root->fs_info->fs_mutex);
Chris Masone20d96d2007-03-22 12:13:20 -0400828 key.objectid = inode->i_ino;
Chris Masone20d96d2007-03-22 12:13:20 -0400829 key.flags = 0;
Chris Masond6e4a422007-04-06 15:37:36 -0400830 btrfs_set_key_type(&key, key_type);
Chris Masone20d96d2007-03-22 12:13:20 -0400831 key.offset = filp->f_pos;
Chris Mason5caf2a02007-04-02 11:20:42 -0400832 path = btrfs_alloc_path();
833 btrfs_init_path(path);
834 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
Chris Mason1b05da22007-04-10 12:13:09 -0400835 if (ret < 0)
Chris Masone20d96d2007-03-22 12:13:20 -0400836 goto err;
Chris Mason7f5c1512007-03-23 15:56:19 -0400837 advance = 0;
Chris Masonde428b62007-05-18 13:28:27 -0400838 reada_leaves(root, path, inode->i_ino);
Chris Masone20d96d2007-03-22 12:13:20 -0400839 while(1) {
Chris Mason5caf2a02007-04-02 11:20:42 -0400840 leaf = btrfs_buffer_leaf(path->nodes[0]);
Chris Masone20d96d2007-03-22 12:13:20 -0400841 nritems = btrfs_header_nritems(&leaf->header);
Chris Mason5caf2a02007-04-02 11:20:42 -0400842 slot = path->slots[0];
Chris Masondee26a92007-03-26 16:00:06 -0400843 if (advance || slot >= nritems) {
844 if (slot >= nritems -1) {
Chris Masonde428b62007-05-18 13:28:27 -0400845 reada_leaves(root, path, inode->i_ino);
Chris Mason5caf2a02007-04-02 11:20:42 -0400846 ret = btrfs_next_leaf(root, path);
Chris Masone20d96d2007-03-22 12:13:20 -0400847 if (ret)
848 break;
Chris Mason5caf2a02007-04-02 11:20:42 -0400849 leaf = btrfs_buffer_leaf(path->nodes[0]);
Chris Masone20d96d2007-03-22 12:13:20 -0400850 nritems = btrfs_header_nritems(&leaf->header);
Chris Mason5caf2a02007-04-02 11:20:42 -0400851 slot = path->slots[0];
Chris Masone20d96d2007-03-22 12:13:20 -0400852 } else {
853 slot++;
Chris Mason5caf2a02007-04-02 11:20:42 -0400854 path->slots[0]++;
Chris Masone20d96d2007-03-22 12:13:20 -0400855 }
856 }
857 advance = 1;
858 item = leaf->items + slot;
Chris Masone20d96d2007-03-22 12:13:20 -0400859 if (btrfs_disk_key_objectid(&item->key) != key.objectid)
860 break;
Chris Masond6e4a422007-04-06 15:37:36 -0400861 if (btrfs_disk_key_type(&item->key) != key_type)
Chris Masona429e512007-04-18 16:15:28 -0400862 break;
Chris Mason7f5c1512007-03-23 15:56:19 -0400863 if (btrfs_disk_key_offset(&item->key) < filp->f_pos)
864 continue;
Chris Mason7fcde0e2007-04-05 12:13:21 -0400865 filp->f_pos = btrfs_disk_key_offset(&item->key);
Chris Masondee26a92007-03-26 16:00:06 -0400866 advance = 1;
Chris Masone20d96d2007-03-22 12:13:20 -0400867 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
Chris Mason7e381802007-04-19 15:36:27 -0400868 di_cur = 0;
869 di_total = btrfs_item_size(leaf->items + slot);
870 while(di_cur < di_total) {
Chris Masonfabb5682007-06-07 22:13:21 -0400871 d_type = btrfs_filetype_table[btrfs_dir_type(di)];
Chris Mason7e381802007-04-19 15:36:27 -0400872 over = filldir(dirent, (const char *)(di + 1),
873 btrfs_dir_name_len(di),
874 btrfs_disk_key_offset(&item->key),
875 btrfs_disk_key_objectid(&di->location),
876 d_type);
877 if (over)
878 goto nopos;
879 di_len = btrfs_dir_name_len(di) + sizeof(*di);
880 di_cur += di_len;
881 di = (struct btrfs_dir_item *)((char *)di + di_len);
882 }
Chris Masone20d96d2007-03-22 12:13:20 -0400883 }
Chris Mason7fcde0e2007-04-05 12:13:21 -0400884 filp->f_pos++;
885nopos:
Chris Masone20d96d2007-03-22 12:13:20 -0400886 ret = 0;
887err:
Chris Mason5caf2a02007-04-02 11:20:42 -0400888 btrfs_release_path(root, path);
889 btrfs_free_path(path);
Chris Mason22b0ebd2007-03-30 08:47:31 -0400890 mutex_unlock(&root->fs_info->fs_mutex);
Chris Masone20d96d2007-03-22 12:13:20 -0400891 return ret;
892}
893
894static void btrfs_put_super (struct super_block * sb)
895{
896 struct btrfs_root *root = btrfs_sb(sb);
897 int ret;
898
899 ret = close_ctree(root);
900 if (ret) {
901 printk("close ctree returns %d\n", ret);
902 }
903 sb->s_fs_info = NULL;
904}
Chris Mason2e635a22007-03-21 11:12:56 -0400905
906static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
907{
908 struct inode * inode;
Chris Masone20d96d2007-03-22 12:13:20 -0400909 struct dentry * root_dentry;
910 struct btrfs_super_block *disk_super;
Chris Mason0f7d52f2007-04-09 10:42:37 -0400911 struct btrfs_root *tree_root;
Chris Masond6e4a422007-04-06 15:37:36 -0400912 struct btrfs_inode *bi;
Chris Mason2e635a22007-03-21 11:12:56 -0400913
914 sb->s_maxbytes = MAX_LFS_FILESIZE;
Chris Mason2e635a22007-03-21 11:12:56 -0400915 sb->s_magic = BTRFS_SUPER_MAGIC;
Chris Masone20d96d2007-03-22 12:13:20 -0400916 sb->s_op = &btrfs_super_ops;
Chris Mason2e635a22007-03-21 11:12:56 -0400917 sb->s_time_gran = 1;
Chris Masone20d96d2007-03-22 12:13:20 -0400918
Chris Mason0f7d52f2007-04-09 10:42:37 -0400919 tree_root = open_ctree(sb);
Chris Masond98237b2007-03-28 13:57:48 -0400920
Chris Mason0f7d52f2007-04-09 10:42:37 -0400921 if (!tree_root) {
Chris Masone20d96d2007-03-22 12:13:20 -0400922 printk("btrfs: open_ctree failed\n");
923 return -EIO;
924 }
Chris Mason0f7d52f2007-04-09 10:42:37 -0400925 sb->s_fs_info = tree_root;
926 disk_super = tree_root->fs_info->disk_super;
Chris Masone20d96d2007-03-22 12:13:20 -0400927 printk("read in super total blocks %Lu root %Lu\n",
928 btrfs_super_total_blocks(disk_super),
929 btrfs_super_root_dir(disk_super));
930
Chris Masonc5739bb2007-04-10 09:27:04 -0400931 inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super),
932 tree_root);
Chris Masond6e4a422007-04-06 15:37:36 -0400933 bi = BTRFS_I(inode);
934 bi->location.objectid = inode->i_ino;
935 bi->location.offset = 0;
936 bi->location.flags = 0;
Chris Mason0f7d52f2007-04-09 10:42:37 -0400937 bi->root = tree_root;
Chris Masond6e4a422007-04-06 15:37:36 -0400938 btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY);
939
Chris Mason2e635a22007-03-21 11:12:56 -0400940 if (!inode)
941 return -ENOMEM;
Chris Masone20d96d2007-03-22 12:13:20 -0400942 if (inode->i_state & I_NEW) {
943 btrfs_read_locked_inode(inode);
944 unlock_new_inode(inode);
945 }
Chris Mason2e635a22007-03-21 11:12:56 -0400946
Chris Masone20d96d2007-03-22 12:13:20 -0400947 root_dentry = d_alloc_root(inode);
948 if (!root_dentry) {
Chris Mason2e635a22007-03-21 11:12:56 -0400949 iput(inode);
950 return -ENOMEM;
951 }
Chris Masone20d96d2007-03-22 12:13:20 -0400952 sb->s_root = root_dentry;
953
Chris Mason2e635a22007-03-21 11:12:56 -0400954 return 0;
955}
956
Chris Mason4730a4b2007-03-26 12:00:39 -0400957static int btrfs_write_inode(struct inode *inode, int wait)
958{
Chris Masond6e4a422007-04-06 15:37:36 -0400959 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Mason4730a4b2007-03-26 12:00:39 -0400960 struct btrfs_trans_handle *trans;
Chris Masonb5133862007-04-24 11:52:22 -0400961 int ret = 0;
962
963 if (wait) {
964 mutex_lock(&root->fs_info->fs_mutex);
965 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -0400966 btrfs_set_trans_block_group(trans, inode);
Chris Masonb5133862007-04-24 11:52:22 -0400967 ret = btrfs_commit_transaction(trans, root);
968 mutex_unlock(&root->fs_info->fs_mutex);
969 }
970 return ret;
971}
972
973static void btrfs_dirty_inode(struct inode *inode)
974{
975 struct btrfs_root *root = BTRFS_I(inode)->root;
976 struct btrfs_trans_handle *trans;
Chris Mason4730a4b2007-03-26 12:00:39 -0400977
978 mutex_lock(&root->fs_info->fs_mutex);
979 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -0400980 btrfs_set_trans_block_group(trans, inode);
Chris Masonb5133862007-04-24 11:52:22 -0400981 btrfs_update_inode(trans, root, inode);
982 btrfs_end_transaction(trans, root);
Chris Mason4730a4b2007-03-26 12:00:39 -0400983 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason35b7e472007-05-02 15:53:43 -0400984 btrfs_btree_balance_dirty(root);
Chris Mason4730a4b2007-03-26 12:00:39 -0400985}
986
Chris Masond5719762007-03-23 10:01:08 -0400987static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
Chris Mason2619ba12007-04-10 16:58:11 -0400988 struct btrfs_root *root,
Chris Mason31f3c992007-04-30 15:25:45 -0400989 u64 objectid,
990 struct btrfs_block_group_cache *group,
991 int mode)
Chris Masond5719762007-03-23 10:01:08 -0400992{
993 struct inode *inode;
994 struct btrfs_inode_item inode_item;
Chris Mason1b05da22007-04-10 12:13:09 -0400995 struct btrfs_key *location;
Chris Masond5719762007-03-23 10:01:08 -0400996 int ret;
Chris Masonde428b62007-05-18 13:28:27 -0400997 int owner;
Chris Masond5719762007-03-23 10:01:08 -0400998
Chris Mason2619ba12007-04-10 16:58:11 -0400999 inode = new_inode(root->fs_info->sb);
Chris Masond5719762007-03-23 10:01:08 -04001000 if (!inode)
1001 return ERR_PTR(-ENOMEM);
1002
Chris Mason2619ba12007-04-10 16:58:11 -04001003 BTRFS_I(inode)->root = root;
Chris Masonde428b62007-05-18 13:28:27 -04001004 if (mode & S_IFDIR)
1005 owner = 0;
1006 else
1007 owner = 1;
1008 group = btrfs_find_block_group(root, group, 0, 0, owner);
Chris Mason31f3c992007-04-30 15:25:45 -04001009 BTRFS_I(inode)->block_group = group;
Chris Masond5719762007-03-23 10:01:08 -04001010
1011 inode->i_uid = current->fsuid;
1012 inode->i_gid = current->fsgid;
1013 inode->i_mode = mode;
1014 inode->i_ino = objectid;
1015 inode->i_blocks = 0;
Chris Masonc5739bb2007-04-10 09:27:04 -04001016 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
Chris Masond5719762007-03-23 10:01:08 -04001017 fill_inode_item(&inode_item, inode);
Chris Mason1b05da22007-04-10 12:13:09 -04001018 location = &BTRFS_I(inode)->location;
1019 location->objectid = objectid;
1020 location->flags = 0;
1021 location->offset = 0;
1022 btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
Chris Masond5719762007-03-23 10:01:08 -04001023
1024 ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
1025 BUG_ON(ret);
1026
1027 insert_inode_hash(inode);
Chris Masond5719762007-03-23 10:01:08 -04001028 return inode;
1029}
1030
Chris Masonfabb5682007-06-07 22:13:21 -04001031static inline u8 btrfs_inode_type(struct inode *inode)
1032{
1033 return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT];
1034}
1035
Chris Masond5719762007-03-23 10:01:08 -04001036static int btrfs_add_link(struct btrfs_trans_handle *trans,
1037 struct dentry *dentry, struct inode *inode)
1038{
1039 int ret;
Chris Masond6e4a422007-04-06 15:37:36 -04001040 struct btrfs_key key;
1041 struct btrfs_root *root = BTRFS_I(dentry->d_parent->d_inode)->root;
1042 key.objectid = inode->i_ino;
1043 key.flags = 0;
1044 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
1045 key.offset = 0;
1046
1047 ret = btrfs_insert_dir_item(trans, root,
Chris Masond5719762007-03-23 10:01:08 -04001048 dentry->d_name.name, dentry->d_name.len,
1049 dentry->d_parent->d_inode->i_ino,
Chris Masonfabb5682007-06-07 22:13:21 -04001050 &key, btrfs_inode_type(inode));
Chris Mason4730a4b2007-03-26 12:00:39 -04001051 if (ret == 0) {
Chris Mason5f26f772007-04-05 10:38:44 -04001052 dentry->d_parent->d_inode->i_size += dentry->d_name.len * 2;
Chris Masond6e4a422007-04-06 15:37:36 -04001053 ret = btrfs_update_inode(trans, root,
Chris Mason4730a4b2007-03-26 12:00:39 -04001054 dentry->d_parent->d_inode);
1055 }
Chris Masond5719762007-03-23 10:01:08 -04001056 return ret;
1057}
1058
1059static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
1060 struct dentry *dentry, struct inode *inode)
1061{
1062 int err = btrfs_add_link(trans, dentry, inode);
1063 if (!err) {
1064 d_instantiate(dentry, inode);
1065 return 0;
1066 }
Chris Mason2c90e5d2007-04-02 10:50:19 -04001067 if (err > 0)
1068 err = -EEXIST;
Chris Masond5719762007-03-23 10:01:08 -04001069 return err;
1070}
1071
1072static int btrfs_create(struct inode *dir, struct dentry *dentry,
1073 int mode, struct nameidata *nd)
1074{
1075 struct btrfs_trans_handle *trans;
Chris Masond6e4a422007-04-06 15:37:36 -04001076 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Masond5719762007-03-23 10:01:08 -04001077 struct inode *inode;
1078 int err;
Chris Mason134e9732007-03-25 13:44:56 -04001079 int drop_inode = 0;
Chris Mason2619ba12007-04-10 16:58:11 -04001080 u64 objectid;
Chris Masond5719762007-03-23 10:01:08 -04001081
Chris Masond561c022007-03-23 19:47:49 -04001082 mutex_lock(&root->fs_info->fs_mutex);
Chris Masond5719762007-03-23 10:01:08 -04001083 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -04001084 btrfs_set_trans_block_group(trans, dir);
Chris Mason2619ba12007-04-10 16:58:11 -04001085
1086 err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
1087 if (err) {
1088 err = -ENOSPC;
1089 goto out_unlock;
1090 }
1091
Chris Mason31f3c992007-04-30 15:25:45 -04001092 inode = btrfs_new_inode(trans, root, objectid,
1093 BTRFS_I(dir)->block_group, mode);
Chris Masond5719762007-03-23 10:01:08 -04001094 err = PTR_ERR(inode);
1095 if (IS_ERR(inode))
Chris Masond561c022007-03-23 19:47:49 -04001096 goto out_unlock;
Chris Mason31f3c992007-04-30 15:25:45 -04001097
1098 btrfs_set_trans_block_group(trans, inode);
Chris Masond5719762007-03-23 10:01:08 -04001099 err = btrfs_add_nondir(trans, dentry, inode);
Chris Mason134e9732007-03-25 13:44:56 -04001100 if (err)
1101 drop_inode = 1;
Chris Masondee26a92007-03-26 16:00:06 -04001102 else {
1103 inode->i_mapping->a_ops = &btrfs_aops;
1104 inode->i_fop = &btrfs_file_operations;
1105 inode->i_op = &btrfs_file_inode_operations;
1106 }
Chris Masond5719762007-03-23 10:01:08 -04001107 dir->i_sb->s_dirt = 1;
Chris Mason31f3c992007-04-30 15:25:45 -04001108 btrfs_update_inode_block_group(trans, inode);
1109 btrfs_update_inode_block_group(trans, dir);
Chris Masond561c022007-03-23 19:47:49 -04001110out_unlock:
Chris Mason22b0ebd2007-03-30 08:47:31 -04001111 btrfs_end_transaction(trans, root);
Chris Masond561c022007-03-23 19:47:49 -04001112 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason2c90e5d2007-04-02 10:50:19 -04001113
Chris Mason134e9732007-03-25 13:44:56 -04001114 if (drop_inode) {
1115 inode_dec_link_count(inode);
1116 iput(inode);
1117 }
Chris Mason35b7e472007-05-02 15:53:43 -04001118 btrfs_btree_balance_dirty(root);
Chris Masond5719762007-03-23 10:01:08 -04001119 return err;
1120}
1121
Chris Mason2b8d99a2007-05-24 08:34:10 -04001122static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
1123 struct dentry *dentry)
1124{
1125 struct btrfs_trans_handle *trans;
1126 struct btrfs_root *root = BTRFS_I(dir)->root;
1127 struct inode *inode = old_dentry->d_inode;
1128 int err;
1129 int drop_inode = 0;
1130
1131 if (inode->i_nlink == 0)
1132 return -ENOENT;
1133
1134 inc_nlink(inode);
1135 mutex_lock(&root->fs_info->fs_mutex);
1136 trans = btrfs_start_transaction(root, 1);
1137 btrfs_set_trans_block_group(trans, dir);
1138 atomic_inc(&inode->i_count);
1139 err = btrfs_add_nondir(trans, dentry, inode);
1140 if (err)
1141 drop_inode = 1;
1142 dir->i_sb->s_dirt = 1;
1143 btrfs_update_inode_block_group(trans, dir);
1144 btrfs_update_inode(trans, root, inode);
1145
1146 btrfs_end_transaction(trans, root);
1147 mutex_unlock(&root->fs_info->fs_mutex);
1148
1149 if (drop_inode) {
1150 inode_dec_link_count(inode);
1151 iput(inode);
1152 }
1153 btrfs_btree_balance_dirty(root);
1154 return err;
1155}
1156
Chris Masonf7922032007-03-25 20:17:36 -04001157static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans,
Chris Mason2619ba12007-04-10 16:58:11 -04001158 struct btrfs_root *root,
1159 u64 objectid, u64 dirid)
Chris Masonf7922032007-03-25 20:17:36 -04001160{
Chris Masonf7922032007-03-25 20:17:36 -04001161 int ret;
1162 char buf[2];
Chris Masond6e4a422007-04-06 15:37:36 -04001163 struct btrfs_key key;
1164
Chris Masonf7922032007-03-25 20:17:36 -04001165 buf[0] = '.';
1166 buf[1] = '.';
1167
Chris Mason2619ba12007-04-10 16:58:11 -04001168 key.objectid = objectid;
Chris Masond6e4a422007-04-06 15:37:36 -04001169 key.offset = 0;
1170 key.flags = 0;
1171 btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
1172
Chris Mason2619ba12007-04-10 16:58:11 -04001173 ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid,
Chris Masonfabb5682007-06-07 22:13:21 -04001174 &key, BTRFS_FT_DIR);
Chris Masonf7922032007-03-25 20:17:36 -04001175 if (ret)
1176 goto error;
Chris Mason2619ba12007-04-10 16:58:11 -04001177 key.objectid = dirid;
1178 ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid,
Chris Masonfabb5682007-06-07 22:13:21 -04001179 &key, BTRFS_FT_DIR);
Chris Mason4730a4b2007-03-26 12:00:39 -04001180 if (ret)
1181 goto error;
Chris Masonf7922032007-03-25 20:17:36 -04001182error:
1183 return ret;
1184}
1185
1186static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1187{
1188 struct inode *inode;
1189 struct btrfs_trans_handle *trans;
Chris Masond6e4a422007-04-06 15:37:36 -04001190 struct btrfs_root *root = BTRFS_I(dir)->root;
Chris Masonf7922032007-03-25 20:17:36 -04001191 int err = 0;
1192 int drop_on_err = 0;
Chris Mason2619ba12007-04-10 16:58:11 -04001193 u64 objectid;
Chris Masonf7922032007-03-25 20:17:36 -04001194
1195 mutex_lock(&root->fs_info->fs_mutex);
1196 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -04001197 btrfs_set_trans_block_group(trans, dir);
Chris Masonf7922032007-03-25 20:17:36 -04001198 if (IS_ERR(trans)) {
1199 err = PTR_ERR(trans);
1200 goto out_unlock;
1201 }
Chris Mason2619ba12007-04-10 16:58:11 -04001202
1203 err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
1204 if (err) {
1205 err = -ENOSPC;
1206 goto out_unlock;
1207 }
1208
Chris Mason31f3c992007-04-30 15:25:45 -04001209 inode = btrfs_new_inode(trans, root, objectid,
1210 BTRFS_I(dir)->block_group, S_IFDIR | mode);
Chris Masonf7922032007-03-25 20:17:36 -04001211 if (IS_ERR(inode)) {
1212 err = PTR_ERR(inode);
1213 goto out_fail;
1214 }
1215 drop_on_err = 1;
1216 inode->i_op = &btrfs_dir_inode_operations;
1217 inode->i_fop = &btrfs_dir_file_operations;
Chris Mason31f3c992007-04-30 15:25:45 -04001218 btrfs_set_trans_block_group(trans, inode);
Chris Masonf7922032007-03-25 20:17:36 -04001219
Chris Mason2619ba12007-04-10 16:58:11 -04001220 err = btrfs_make_empty_dir(trans, root, inode->i_ino, dir->i_ino);
1221 if (err)
1222 goto out_fail;
1223
1224 inode->i_size = 6;
1225 err = btrfs_update_inode(trans, root, inode);
Chris Masonf7922032007-03-25 20:17:36 -04001226 if (err)
1227 goto out_fail;
1228 err = btrfs_add_link(trans, dentry, inode);
1229 if (err)
1230 goto out_fail;
1231 d_instantiate(dentry, inode);
Chris Masonf7922032007-03-25 20:17:36 -04001232 drop_on_err = 0;
Chris Masoncd1bc462007-04-27 10:08:34 -04001233 dir->i_sb->s_dirt = 1;
Chris Mason31f3c992007-04-30 15:25:45 -04001234 btrfs_update_inode_block_group(trans, inode);
1235 btrfs_update_inode_block_group(trans, dir);
Chris Masonf7922032007-03-25 20:17:36 -04001236
1237out_fail:
1238 btrfs_end_transaction(trans, root);
1239out_unlock:
1240 mutex_unlock(&root->fs_info->fs_mutex);
1241 if (drop_on_err)
1242 iput(inode);
Chris Mason35b7e472007-05-02 15:53:43 -04001243 btrfs_btree_balance_dirty(root);
Chris Masonf7922032007-03-25 20:17:36 -04001244 return err;
1245}
1246
Chris Mason8fd17792007-04-19 21:01:03 -04001247static int btrfs_sync_file(struct file *file,
1248 struct dentry *dentry, int datasync)
1249{
1250 struct inode *inode = dentry->d_inode;
1251 struct btrfs_root *root = BTRFS_I(inode)->root;
1252 int ret;
1253 struct btrfs_trans_handle *trans;
1254
1255 mutex_lock(&root->fs_info->fs_mutex);
1256 trans = btrfs_start_transaction(root, 1);
1257 if (!trans) {
1258 ret = -ENOMEM;
1259 goto out;
1260 }
1261 ret = btrfs_commit_transaction(trans, root);
1262 mutex_unlock(&root->fs_info->fs_mutex);
1263out:
1264 return ret > 0 ? EIO : ret;
1265}
1266
Chris Masond5719762007-03-23 10:01:08 -04001267static int btrfs_sync_fs(struct super_block *sb, int wait)
1268{
1269 struct btrfs_trans_handle *trans;
1270 struct btrfs_root *root;
1271 int ret;
Chris Masond98237b2007-03-28 13:57:48 -04001272 root = btrfs_sb(sb);
Chris Masondf2ce342007-03-23 11:00:45 -04001273
Chris Masond5719762007-03-23 10:01:08 -04001274 sb->s_dirt = 0;
Chris Masond561c022007-03-23 19:47:49 -04001275 if (!wait) {
Chris Mason7cfcc172007-04-02 14:53:59 -04001276 filemap_flush(root->fs_info->btree_inode->i_mapping);
Chris Masond561c022007-03-23 19:47:49 -04001277 return 0;
1278 }
Chris Masond561c022007-03-23 19:47:49 -04001279 mutex_lock(&root->fs_info->fs_mutex);
Chris Masond5719762007-03-23 10:01:08 -04001280 trans = btrfs_start_transaction(root, 1);
1281 ret = btrfs_commit_transaction(trans, root);
1282 sb->s_dirt = 0;
1283 BUG_ON(ret);
1284printk("btrfs sync_fs\n");
Chris Masond561c022007-03-23 19:47:49 -04001285 mutex_unlock(&root->fs_info->fs_mutex);
Chris Masond5719762007-03-23 10:01:08 -04001286 return 0;
1287}
1288
Chris Masonfabb5682007-06-07 22:13:21 -04001289#define BTRFS_GET_BLOCK_NO_CREATE 0
1290#define BTRFS_GET_BLOCK_CREATE 1
1291#define BTRFS_GET_BLOCK_NO_DIRECT 2
1292
Chris Mason75dfe392007-03-29 11:56:46 -04001293static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
Chris Masondee26a92007-03-26 16:00:06 -04001294 struct buffer_head *result, int create)
1295{
1296 int ret;
1297 int err = 0;
1298 u64 blocknr;
1299 u64 extent_start = 0;
1300 u64 extent_end = 0;
1301 u64 objectid = inode->i_ino;
Chris Mason236454d2007-04-19 13:37:44 -04001302 u32 found_type;
Chris Mason1de037a2007-05-29 15:17:08 -04001303 u64 alloc_hint = 0;
Chris Mason5caf2a02007-04-02 11:20:42 -04001304 struct btrfs_path *path;
Chris Masond6e4a422007-04-06 15:37:36 -04001305 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masondee26a92007-03-26 16:00:06 -04001306 struct btrfs_file_extent_item *item;
1307 struct btrfs_leaf *leaf;
1308 struct btrfs_disk_key *found_key;
Chris Mason1de037a2007-05-29 15:17:08 -04001309 struct btrfs_trans_handle *trans = NULL;
Chris Masondee26a92007-03-26 16:00:06 -04001310
Chris Mason5caf2a02007-04-02 11:20:42 -04001311 path = btrfs_alloc_path();
1312 BUG_ON(!path);
1313 btrfs_init_path(path);
Chris Masonfabb5682007-06-07 22:13:21 -04001314 if (create & BTRFS_GET_BLOCK_CREATE) {
Chris Mason6567e832007-04-16 09:22:45 -04001315 WARN_ON(1);
Chris Mason1de037a2007-05-29 15:17:08 -04001316 /* this almost but not quite works */
1317 trans = btrfs_start_transaction(root, 1);
1318 if (!trans) {
1319 err = -ENOMEM;
1320 goto out;
1321 }
1322 ret = drop_extents(trans, root, inode,
1323 iblock << inode->i_blkbits,
1324 (iblock + 1) << inode->i_blkbits,
1325 &alloc_hint);
1326 BUG_ON(ret);
Chris Mason6567e832007-04-16 09:22:45 -04001327 }
Chris Masondee26a92007-03-26 16:00:06 -04001328
Chris Mason236454d2007-04-19 13:37:44 -04001329 ret = btrfs_lookup_file_extent(NULL, root, path,
Chris Mason9773a782007-03-27 11:26:26 -04001330 inode->i_ino,
Chris Mason236454d2007-04-19 13:37:44 -04001331 iblock << inode->i_blkbits, 0);
Chris Masondee26a92007-03-26 16:00:06 -04001332 if (ret < 0) {
Chris Masondee26a92007-03-26 16:00:06 -04001333 err = ret;
1334 goto out;
1335 }
1336
1337 if (ret != 0) {
Chris Mason5caf2a02007-04-02 11:20:42 -04001338 if (path->slots[0] == 0) {
1339 btrfs_release_path(root, path);
Chris Mason1de037a2007-05-29 15:17:08 -04001340 goto not_found;
Chris Masondee26a92007-03-26 16:00:06 -04001341 }
Chris Mason5caf2a02007-04-02 11:20:42 -04001342 path->slots[0]--;
Chris Masondee26a92007-03-26 16:00:06 -04001343 }
1344
Chris Mason5caf2a02007-04-02 11:20:42 -04001345 item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
Chris Masondee26a92007-03-26 16:00:06 -04001346 struct btrfs_file_extent_item);
Chris Mason5caf2a02007-04-02 11:20:42 -04001347 leaf = btrfs_buffer_leaf(path->nodes[0]);
Chris Masondee26a92007-03-26 16:00:06 -04001348 blocknr = btrfs_file_extent_disk_blocknr(item);
1349 blocknr += btrfs_file_extent_offset(item);
1350
Chris Masondee26a92007-03-26 16:00:06 -04001351 /* are we inside the extent that was found? */
Chris Mason5caf2a02007-04-02 11:20:42 -04001352 found_key = &leaf->items[path->slots[0]].key;
Chris Mason236454d2007-04-19 13:37:44 -04001353 found_type = btrfs_disk_key_type(found_key);
Chris Masondee26a92007-03-26 16:00:06 -04001354 if (btrfs_disk_key_objectid(found_key) != objectid ||
Chris Mason236454d2007-04-19 13:37:44 -04001355 found_type != BTRFS_EXTENT_DATA_KEY) {
Chris Masondee26a92007-03-26 16:00:06 -04001356 extent_end = 0;
1357 extent_start = 0;
Chris Mason1de037a2007-05-29 15:17:08 -04001358 goto not_found;
Chris Masondee26a92007-03-26 16:00:06 -04001359 }
Chris Mason236454d2007-04-19 13:37:44 -04001360 found_type = btrfs_file_extent_type(item);
Chris Mason5caf2a02007-04-02 11:20:42 -04001361 extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key);
Chris Mason236454d2007-04-19 13:37:44 -04001362 if (found_type == BTRFS_FILE_EXTENT_REG) {
1363 extent_start = extent_start >> inode->i_blkbits;
1364 extent_end = extent_start + btrfs_file_extent_num_blocks(item);
Chris Mason3a686372007-05-24 13:35:57 -04001365 err = 0;
Chris Mason1de037a2007-05-29 15:17:08 -04001366 if (btrfs_file_extent_disk_blocknr(item) == 0)
Chris Mason3a686372007-05-24 13:35:57 -04001367 goto out;
Chris Mason236454d2007-04-19 13:37:44 -04001368 if (iblock >= extent_start && iblock < extent_end) {
Chris Mason236454d2007-04-19 13:37:44 -04001369 btrfs_map_bh_to_logical(root, result, blocknr +
1370 iblock - extent_start);
1371 goto out;
1372 }
1373 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
1374 char *ptr;
1375 char *map;
1376 u32 size;
Chris Masonfabb5682007-06-07 22:13:21 -04001377
1378 if (create & BTRFS_GET_BLOCK_NO_DIRECT) {
1379 err = -EINVAL;
1380 goto out;
1381 }
Chris Mason236454d2007-04-19 13:37:44 -04001382 size = btrfs_file_extent_inline_len(leaf->items +
1383 path->slots[0]);
1384 extent_end = (extent_start + size) >> inode->i_blkbits;
1385 extent_start >>= inode->i_blkbits;
1386 if (iblock < extent_start || iblock > extent_end) {
Chris Mason1de037a2007-05-29 15:17:08 -04001387 goto not_found;
Chris Mason236454d2007-04-19 13:37:44 -04001388 }
1389 ptr = btrfs_file_extent_inline_start(item);
1390 map = kmap(result->b_page);
1391 memcpy(map, ptr, size);
1392 memset(map + size, 0, PAGE_CACHE_SIZE - size);
1393 flush_dcache_page(result->b_page);
1394 kunmap(result->b_page);
1395 set_buffer_uptodate(result);
1396 SetPageChecked(result->b_page);
1397 btrfs_map_bh_to_logical(root, result, 0);
Chris Masondee26a92007-03-26 16:00:06 -04001398 }
Chris Mason1de037a2007-05-29 15:17:08 -04001399not_found:
Chris Masonfabb5682007-06-07 22:13:21 -04001400 if (create & BTRFS_GET_BLOCK_CREATE) {
Chris Mason1de037a2007-05-29 15:17:08 -04001401 struct btrfs_key ins;
1402 ret = btrfs_alloc_extent(trans, root, inode->i_ino,
1403 1, alloc_hint, (u64)-1,
1404 &ins, 1);
1405 BUG_ON(ret);
1406 ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
1407 iblock << inode->i_blkbits,
1408 ins.objectid, ins.offset,
1409 ins.offset);
1410 BUG_ON(ret);
1411 SetPageChecked(result->b_page);
1412 btrfs_map_bh_to_logical(root, result, ins.objectid);
1413 }
Chris Masondee26a92007-03-26 16:00:06 -04001414out:
Chris Mason1de037a2007-05-29 15:17:08 -04001415 if (trans)
1416 err = btrfs_end_transaction(trans, root);
Chris Mason5caf2a02007-04-02 11:20:42 -04001417 btrfs_free_path(path);
Chris Mason75dfe392007-03-29 11:56:46 -04001418 return err;
1419}
1420
1421static int btrfs_get_block(struct inode *inode, sector_t iblock,
1422 struct buffer_head *result, int create)
1423{
1424 int err;
Chris Masond6e4a422007-04-06 15:37:36 -04001425 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Mason75dfe392007-03-29 11:56:46 -04001426 mutex_lock(&root->fs_info->fs_mutex);
Chris Masone8f05c42007-04-04 14:30:09 -04001427 err = btrfs_get_block_lock(inode, iblock, result, create);
Chris Masondee26a92007-03-26 16:00:06 -04001428 mutex_unlock(&root->fs_info->fs_mutex);
1429 return err;
1430}
1431
Chris Masonfabb5682007-06-07 22:13:21 -04001432static int btrfs_get_block_bmap(struct inode *inode, sector_t iblock,
1433 struct buffer_head *result, int create)
1434{
1435 struct btrfs_root *root = BTRFS_I(inode)->root;
1436 mutex_lock(&root->fs_info->fs_mutex);
1437 btrfs_get_block_lock(inode, iblock, result, BTRFS_GET_BLOCK_NO_DIRECT);
1438 mutex_unlock(&root->fs_info->fs_mutex);
1439 return 0;
1440}
1441
1442static sector_t btrfs_bmap(struct address_space *as, sector_t block)
1443{
1444 return generic_block_bmap(as, block, btrfs_get_block_bmap);
1445}
1446
Chris Masondee26a92007-03-26 16:00:06 -04001447static int btrfs_prepare_write(struct file *file, struct page *page,
1448 unsigned from, unsigned to)
1449{
Chris Mason1de037a2007-05-29 15:17:08 -04001450 return block_prepare_write(page, from, to, btrfs_get_block);
Chris Masondee26a92007-03-26 16:00:06 -04001451}
1452
Chris Masond561c022007-03-23 19:47:49 -04001453static void btrfs_write_super(struct super_block *sb)
1454{
1455 btrfs_sync_fs(sb, 1);
1456}
1457
Chris Masondee26a92007-03-26 16:00:06 -04001458static int btrfs_readpage(struct file *file, struct page *page)
1459{
1460 return mpage_readpage(page, btrfs_get_block);
1461}
1462
Chris Mason236454d2007-04-19 13:37:44 -04001463/*
1464 * While block_write_full_page is writing back the dirty buffers under
1465 * the page lock, whoever dirtied the buffers may decide to clean them
1466 * again at any time. We handle that by only looking at the buffer
1467 * state inside lock_buffer().
1468 *
1469 * If block_write_full_page() is called for regular writeback
1470 * (wbc->sync_mode == WB_SYNC_NONE) then it will redirty a page which has a
1471 * locked buffer. This only can happen if someone has written the buffer
1472 * directly, with submit_bh(). At the address_space level PageWriteback
1473 * prevents this contention from occurring.
1474 */
1475static int __btrfs_write_full_page(struct inode *inode, struct page *page,
1476 struct writeback_control *wbc)
1477{
1478 int err;
1479 sector_t block;
1480 sector_t last_block;
1481 struct buffer_head *bh, *head;
1482 const unsigned blocksize = 1 << inode->i_blkbits;
1483 int nr_underway = 0;
1484
1485 BUG_ON(!PageLocked(page));
1486
1487 last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
1488
1489 if (!page_has_buffers(page)) {
1490 create_empty_buffers(page, blocksize,
1491 (1 << BH_Dirty)|(1 << BH_Uptodate));
1492 }
1493
1494 /*
1495 * Be very careful. We have no exclusion from __set_page_dirty_buffers
1496 * here, and the (potentially unmapped) buffers may become dirty at
1497 * any time. If a buffer becomes dirty here after we've inspected it
1498 * then we just miss that fact, and the page stays dirty.
1499 *
1500 * Buffers outside i_size may be dirtied by __set_page_dirty_buffers;
1501 * handle that here by just cleaning them.
1502 */
1503
1504 block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
1505 head = page_buffers(page);
1506 bh = head;
1507
1508 /*
1509 * Get all the dirty buffers mapped to disk addresses and
1510 * handle any aliases from the underlying blockdev's mapping.
1511 */
1512 do {
1513 if (block > last_block) {
1514 /*
1515 * mapped buffers outside i_size will occur, because
1516 * this page can be outside i_size when there is a
1517 * truncate in progress.
1518 */
1519 /*
1520 * The buffer was zeroed by block_write_full_page()
1521 */
1522 clear_buffer_dirty(bh);
1523 set_buffer_uptodate(bh);
1524 } else if (!buffer_mapped(bh) && buffer_dirty(bh)) {
1525 WARN_ON(bh->b_size != blocksize);
1526 err = btrfs_get_block(inode, block, bh, 0);
Chris Mason35b7e472007-05-02 15:53:43 -04001527 if (err) {
1528printk("writepage going to recovery err %d\n", err);
Chris Mason236454d2007-04-19 13:37:44 -04001529 goto recover;
Chris Mason35b7e472007-05-02 15:53:43 -04001530 }
Chris Mason236454d2007-04-19 13:37:44 -04001531 if (buffer_new(bh)) {
1532 /* blockdev mappings never come here */
1533 clear_buffer_new(bh);
Chris Mason236454d2007-04-19 13:37:44 -04001534 }
1535 }
1536 bh = bh->b_this_page;
1537 block++;
1538 } while (bh != head);
1539
1540 do {
1541 if (!buffer_mapped(bh))
1542 continue;
1543 /*
1544 * If it's a fully non-blocking write attempt and we cannot
1545 * lock the buffer then redirty the page. Note that this can
1546 * potentially cause a busy-wait loop from pdflush and kswapd
1547 * activity, but those code paths have their own higher-level
1548 * throttling.
1549 */
1550 if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
1551 lock_buffer(bh);
1552 } else if (test_set_buffer_locked(bh)) {
1553 redirty_page_for_writepage(wbc, page);
1554 continue;
1555 }
1556 if (test_clear_buffer_dirty(bh) && bh->b_blocknr != 0) {
1557 mark_buffer_async_write(bh);
1558 } else {
1559 unlock_buffer(bh);
1560 }
1561 } while ((bh = bh->b_this_page) != head);
1562
1563 /*
1564 * The page and its buffers are protected by PageWriteback(), so we can
1565 * drop the bh refcounts early.
1566 */
1567 BUG_ON(PageWriteback(page));
1568 set_page_writeback(page);
1569
1570 do {
1571 struct buffer_head *next = bh->b_this_page;
1572 if (buffer_async_write(bh)) {
1573 submit_bh(WRITE, bh);
1574 nr_underway++;
1575 }
1576 bh = next;
1577 } while (bh != head);
1578 unlock_page(page);
1579
1580 err = 0;
1581done:
1582 if (nr_underway == 0) {
1583 /*
1584 * The page was marked dirty, but the buffers were
1585 * clean. Someone wrote them back by hand with
1586 * ll_rw_block/submit_bh. A rare case.
1587 */
1588 int uptodate = 1;
1589 do {
1590 if (!buffer_uptodate(bh)) {
1591 uptodate = 0;
1592 break;
1593 }
1594 bh = bh->b_this_page;
1595 } while (bh != head);
1596 if (uptodate)
1597 SetPageUptodate(page);
1598 end_page_writeback(page);
Chris Mason236454d2007-04-19 13:37:44 -04001599 }
1600 return err;
1601
1602recover:
1603 /*
1604 * ENOSPC, or some other error. We may already have added some
1605 * blocks to the file, so we need to write these out to avoid
1606 * exposing stale data.
1607 * The page is currently locked and not marked for writeback
1608 */
1609 bh = head;
1610 /* Recovery: lock and submit the mapped buffers */
1611 do {
1612 if (buffer_mapped(bh) && buffer_dirty(bh)) {
1613 lock_buffer(bh);
1614 mark_buffer_async_write(bh);
1615 } else {
1616 /*
1617 * The buffer may have been set dirty during
1618 * attachment to a dirty page.
1619 */
1620 clear_buffer_dirty(bh);
1621 }
1622 } while ((bh = bh->b_this_page) != head);
1623 SetPageError(page);
1624 BUG_ON(PageWriteback(page));
1625 set_page_writeback(page);
1626 do {
1627 struct buffer_head *next = bh->b_this_page;
1628 if (buffer_async_write(bh)) {
1629 clear_buffer_dirty(bh);
1630 submit_bh(WRITE, bh);
1631 nr_underway++;
1632 }
1633 bh = next;
1634 } while (bh != head);
1635 unlock_page(page);
1636 goto done;
1637}
1638
1639/*
1640 * The generic ->writepage function for buffer-backed address_spaces
1641 */
Chris Masondee26a92007-03-26 16:00:06 -04001642static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
1643{
Chris Mason236454d2007-04-19 13:37:44 -04001644 struct inode * const inode = page->mapping->host;
1645 loff_t i_size = i_size_read(inode);
1646 const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
1647 unsigned offset;
1648 void *kaddr;
1649
1650 /* Is the page fully inside i_size? */
1651 if (page->index < end_index)
1652 return __btrfs_write_full_page(inode, page, wbc);
1653
1654 /* Is the page fully outside i_size? (truncate in progress) */
1655 offset = i_size & (PAGE_CACHE_SIZE-1);
1656 if (page->index >= end_index+1 || !offset) {
1657 /*
1658 * The page may have dirty, unmapped buffers. For example,
1659 * they may have been added in ext3_writepage(). Make them
1660 * freeable here, so the page does not leak.
1661 */
1662 block_invalidatepage(page, 0);
1663 unlock_page(page);
1664 return 0; /* don't care */
1665 }
1666
1667 /*
1668 * The page straddles i_size. It must be zeroed out on each and every
1669 * writepage invokation because it may be mmapped. "A file is mapped
1670 * in multiples of the page size. For a file that is not a multiple of
1671 * the page size, the remaining memory is zeroed when mapped, and
1672 * writes to that region are not written out to the file."
1673 */
1674 kaddr = kmap_atomic(page, KM_USER0);
1675 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
1676 flush_dcache_page(page);
1677 kunmap_atomic(kaddr, KM_USER0);
1678 return __btrfs_write_full_page(inode, page, wbc);
Chris Masondee26a92007-03-26 16:00:06 -04001679}
Chris Masond561c022007-03-23 19:47:49 -04001680
Chris Masonf4b9aa82007-03-27 11:05:53 -04001681static void btrfs_truncate(struct inode *inode)
1682{
Chris Masond6e4a422007-04-06 15:37:36 -04001683 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masonf4b9aa82007-03-27 11:05:53 -04001684 int ret;
1685 struct btrfs_trans_handle *trans;
1686
1687 if (!S_ISREG(inode->i_mode))
1688 return;
1689 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
1690 return;
1691
Chris Mason1de037a2007-05-29 15:17:08 -04001692 btrfs_truncate_page(inode->i_mapping, inode->i_size);
Chris Masonf4b9aa82007-03-27 11:05:53 -04001693
Chris Masonf4b9aa82007-03-27 11:05:53 -04001694 mutex_lock(&root->fs_info->fs_mutex);
1695 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -04001696 btrfs_set_trans_block_group(trans, inode);
Chris Mason1de037a2007-05-29 15:17:08 -04001697
1698 /* FIXME, add redo link to tree so we don't leak on crash */
Chris Masonf4b9aa82007-03-27 11:05:53 -04001699 ret = btrfs_truncate_in_trans(trans, root, inode);
1700 BUG_ON(ret);
Chris Mason35b7e472007-05-02 15:53:43 -04001701 btrfs_update_inode(trans, root, inode);
Chris Masonf4b9aa82007-03-27 11:05:53 -04001702 ret = btrfs_end_transaction(trans, root);
1703 BUG_ON(ret);
1704 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason35b7e472007-05-02 15:53:43 -04001705 btrfs_btree_balance_dirty(root);
Chris Masonf4b9aa82007-03-27 11:05:53 -04001706}
1707
Chris Mason236454d2007-04-19 13:37:44 -04001708static int btrfs_commit_write(struct file *file, struct page *page,
1709 unsigned from, unsigned to)
1710{
1711 struct inode *inode = page->mapping->host;
1712 struct buffer_head *bh;
1713 loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
1714
1715 SetPageUptodate(page);
1716 bh = page_buffers(page);
Chris Mason1de037a2007-05-29 15:17:08 -04001717 set_buffer_uptodate(bh);
Chris Mason236454d2007-04-19 13:37:44 -04001718 if (buffer_mapped(bh) && bh->b_blocknr != 0) {
1719 set_page_dirty(page);
1720 }
1721 if (pos > inode->i_size) {
1722 i_size_write(inode, pos);
1723 mark_inode_dirty(inode);
1724 }
1725 return 0;
1726}
1727
Chris Mason75dfe392007-03-29 11:56:46 -04001728static int btrfs_copy_from_user(loff_t pos, int num_pages, int write_bytes,
1729 struct page **prepared_pages,
1730 const char __user * buf)
1731{
1732 long page_fault = 0;
1733 int i;
1734 int offset = pos & (PAGE_CACHE_SIZE - 1);
1735
1736 for (i = 0; i < num_pages && write_bytes > 0; i++, offset = 0) {
1737 size_t count = min_t(size_t,
1738 PAGE_CACHE_SIZE - offset, write_bytes);
1739 struct page *page = prepared_pages[i];
1740 fault_in_pages_readable(buf, count);
1741
1742 /* Copy data from userspace to the current page */
1743 kmap(page);
1744 page_fault = __copy_from_user(page_address(page) + offset,
1745 buf, count);
1746 /* Flush processor's dcache for this page */
1747 flush_dcache_page(page);
1748 kunmap(page);
1749 buf += count;
1750 write_bytes -= count;
1751
1752 if (page_fault)
1753 break;
1754 }
1755 return page_fault ? -EFAULT : 0;
1756}
1757
1758static void btrfs_drop_pages(struct page **pages, size_t num_pages)
1759{
1760 size_t i;
1761 for (i = 0; i < num_pages; i++) {
1762 if (!pages[i])
1763 break;
1764 unlock_page(pages[i]);
1765 mark_page_accessed(pages[i]);
1766 page_cache_release(pages[i]);
1767 }
1768}
1769static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
1770 struct btrfs_root *root,
1771 struct file *file,
1772 struct page **pages,
1773 size_t num_pages,
1774 loff_t pos,
1775 size_t write_bytes)
1776{
1777 int i;
1778 int offset;
1779 int err = 0;
1780 int ret;
1781 int this_write;
Chris Masonf254e522007-03-29 15:15:27 -04001782 struct inode *inode = file->f_path.dentry->d_inode;
Chris Mason236454d2007-04-19 13:37:44 -04001783 struct buffer_head *bh;
1784 struct btrfs_file_extent_item *ei;
Chris Mason75dfe392007-03-29 11:56:46 -04001785
1786 for (i = 0; i < num_pages; i++) {
1787 offset = pos & (PAGE_CACHE_SIZE -1);
1788 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
Chris Masonf254e522007-03-29 15:15:27 -04001789 /* FIXME, one block at a time */
1790
1791 mutex_lock(&root->fs_info->fs_mutex);
1792 trans = btrfs_start_transaction(root, 1);
Chris Mason31f3c992007-04-30 15:25:45 -04001793 btrfs_set_trans_block_group(trans, inode);
Chris Mason236454d2007-04-19 13:37:44 -04001794
1795 bh = page_buffers(pages[i]);
1796 if (buffer_mapped(bh) && bh->b_blocknr == 0) {
1797 struct btrfs_key key;
1798 struct btrfs_path *path;
1799 char *ptr;
1800 u32 datasize;
1801
1802 path = btrfs_alloc_path();
1803 BUG_ON(!path);
1804 key.objectid = inode->i_ino;
1805 key.offset = pages[i]->index << PAGE_CACHE_SHIFT;
1806 key.flags = 0;
1807 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
1808 BUG_ON(write_bytes >= PAGE_CACHE_SIZE);
1809 datasize = offset +
1810 btrfs_file_extent_calc_inline_size(write_bytes);
1811 ret = btrfs_insert_empty_item(trans, root, path, &key,
1812 datasize);
1813 BUG_ON(ret);
1814 ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
1815 path->slots[0], struct btrfs_file_extent_item);
1816 btrfs_set_file_extent_generation(ei, trans->transid);
1817 btrfs_set_file_extent_type(ei,
1818 BTRFS_FILE_EXTENT_INLINE);
1819 ptr = btrfs_file_extent_inline_start(ei);
Chris Mason098f59c2007-05-11 11:33:21 -04001820 btrfs_memcpy(root, path->nodes[0]->b_data,
1821 ptr, bh->b_data, offset + write_bytes);
Chris Mason236454d2007-04-19 13:37:44 -04001822 mark_buffer_dirty(path->nodes[0]);
1823 btrfs_free_path(path);
Chris Mason3a686372007-05-24 13:35:57 -04001824 } else if (buffer_mapped(bh)) {
Chris Mason236454d2007-04-19 13:37:44 -04001825 btrfs_csum_file_block(trans, root, inode->i_ino,
Chris Masonf254e522007-03-29 15:15:27 -04001826 pages[i]->index << PAGE_CACHE_SHIFT,
1827 kmap(pages[i]), PAGE_CACHE_SIZE);
Chris Mason236454d2007-04-19 13:37:44 -04001828 kunmap(pages[i]);
1829 }
Chris Masonf254e522007-03-29 15:15:27 -04001830 SetPageChecked(pages[i]);
Chris Masone37c9e62007-05-09 20:13:14 -04001831 // btrfs_update_inode_block_group(trans, inode);
Chris Masonf254e522007-03-29 15:15:27 -04001832 ret = btrfs_end_transaction(trans, root);
1833 BUG_ON(ret);
1834 mutex_unlock(&root->fs_info->fs_mutex);
1835
Chris Mason236454d2007-04-19 13:37:44 -04001836 ret = btrfs_commit_write(file, pages[i], offset,
Chris Mason75dfe392007-03-29 11:56:46 -04001837 offset + this_write);
1838 pos += this_write;
1839 if (ret) {
1840 err = ret;
1841 goto failed;
1842 }
1843 WARN_ON(this_write > write_bytes);
1844 write_bytes -= this_write;
1845 }
1846failed:
1847 return err;
1848}
1849
Chris Masonb18c6682007-04-17 13:26:50 -04001850static int drop_extents(struct btrfs_trans_handle *trans,
1851 struct btrfs_root *root,
1852 struct inode *inode,
Chris Masonde428b62007-05-18 13:28:27 -04001853 u64 start, u64 end, u64 *hint_block)
Chris Masonb18c6682007-04-17 13:26:50 -04001854{
1855 int ret;
1856 struct btrfs_key key;
1857 struct btrfs_leaf *leaf;
1858 int slot;
1859 struct btrfs_file_extent_item *extent;
Chris Mason236454d2007-04-19 13:37:44 -04001860 u64 extent_end = 0;
Chris Masonb18c6682007-04-17 13:26:50 -04001861 int keep;
1862 struct btrfs_file_extent_item old;
1863 struct btrfs_path *path;
1864 u64 search_start = start;
1865 int bookend;
Chris Mason236454d2007-04-19 13:37:44 -04001866 int found_type;
1867 int found_extent;
1868 int found_inline;
1869
Chris Masonb18c6682007-04-17 13:26:50 -04001870 path = btrfs_alloc_path();
1871 if (!path)
1872 return -ENOMEM;
Chris Masonb18c6682007-04-17 13:26:50 -04001873 while(1) {
Chris Masona429e512007-04-18 16:15:28 -04001874 btrfs_release_path(root, path);
1875 ret = btrfs_lookup_file_extent(trans, root, path, inode->i_ino,
1876 search_start, -1);
1877 if (ret < 0)
1878 goto out;
1879 if (ret > 0) {
1880 if (path->slots[0] == 0) {
Chris Mason236454d2007-04-19 13:37:44 -04001881 ret = 0;
Chris Masona429e512007-04-18 16:15:28 -04001882 goto out;
1883 }
1884 path->slots[0]--;
1885 }
Chris Masonb18c6682007-04-17 13:26:50 -04001886 keep = 0;
1887 bookend = 0;
Chris Mason236454d2007-04-19 13:37:44 -04001888 found_extent = 0;
1889 found_inline = 0;
1890 extent = NULL;
Chris Masonb18c6682007-04-17 13:26:50 -04001891 leaf = btrfs_buffer_leaf(path->nodes[0]);
1892 slot = path->slots[0];
1893 btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
Chris Masonb18c6682007-04-17 13:26:50 -04001894 if (key.offset >= end || key.objectid != inode->i_ino) {
1895 ret = 0;
1896 goto out;
1897 }
Chris Mason236454d2007-04-19 13:37:44 -04001898 if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY) {
1899 ret = 0;
Chris Masona429e512007-04-18 16:15:28 -04001900 goto out;
Chris Mason236454d2007-04-19 13:37:44 -04001901 }
1902 extent = btrfs_item_ptr(leaf, slot,
1903 struct btrfs_file_extent_item);
1904 found_type = btrfs_file_extent_type(extent);
1905 if (found_type == BTRFS_FILE_EXTENT_REG) {
1906 extent_end = key.offset +
1907 (btrfs_file_extent_num_blocks(extent) <<
1908 inode->i_blkbits);
1909 found_extent = 1;
1910 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
1911 found_inline = 1;
1912 extent_end = key.offset +
1913 btrfs_file_extent_inline_len(leaf->items + slot);
1914 }
1915
1916 if (!found_extent && !found_inline) {
1917 ret = 0;
Chris Masona429e512007-04-18 16:15:28 -04001918 goto out;
Chris Mason236454d2007-04-19 13:37:44 -04001919 }
1920
1921 if (search_start >= extent_end) {
1922 ret = 0;
1923 goto out;
1924 }
1925
Chris Mason3a686372007-05-24 13:35:57 -04001926 if (found_inline) {
1927 u64 mask = root->blocksize - 1;
1928 search_start = (extent_end + mask) & ~mask;
1929 } else
1930 search_start = extent_end;
Chris Masonb18c6682007-04-17 13:26:50 -04001931
1932 if (end < extent_end && end >= key.offset) {
Chris Mason236454d2007-04-19 13:37:44 -04001933 if (found_extent) {
Chris Mason3a686372007-05-24 13:35:57 -04001934 u64 disk_blocknr =
1935 btrfs_file_extent_disk_blocknr(extent);
1936 u64 disk_num_blocks =
1937 btrfs_file_extent_disk_num_blocks(extent);
Chris Mason236454d2007-04-19 13:37:44 -04001938 memcpy(&old, extent, sizeof(old));
Chris Mason3a686372007-05-24 13:35:57 -04001939 if (disk_blocknr != 0) {
1940 ret = btrfs_inc_extent_ref(trans, root,
1941 disk_blocknr, disk_num_blocks);
1942 BUG_ON(ret);
1943 }
Chris Mason236454d2007-04-19 13:37:44 -04001944 }
1945 WARN_ON(found_inline);
Chris Masonb18c6682007-04-17 13:26:50 -04001946 bookend = 1;
1947 }
1948
1949 if (start > key.offset) {
1950 u64 new_num;
Chris Masona429e512007-04-18 16:15:28 -04001951 u64 old_num;
Chris Masonb18c6682007-04-17 13:26:50 -04001952 /* truncate existing extent */
1953 keep = 1;
1954 WARN_ON(start & (root->blocksize - 1));
Chris Mason236454d2007-04-19 13:37:44 -04001955 if (found_extent) {
1956 new_num = (start - key.offset) >>
1957 inode->i_blkbits;
1958 old_num = btrfs_file_extent_num_blocks(extent);
Chris Masonde428b62007-05-18 13:28:27 -04001959 *hint_block =
1960 btrfs_file_extent_disk_blocknr(extent);
Chris Mason3a686372007-05-24 13:35:57 -04001961 if (btrfs_file_extent_disk_blocknr(extent)) {
1962 inode->i_blocks -=
1963 (old_num - new_num) << 3;
1964 }
Chris Mason236454d2007-04-19 13:37:44 -04001965 btrfs_set_file_extent_num_blocks(extent,
1966 new_num);
1967 mark_buffer_dirty(path->nodes[0]);
1968 } else {
1969 WARN_ON(1);
Chris Mason236454d2007-04-19 13:37:44 -04001970 }
Chris Masonb18c6682007-04-17 13:26:50 -04001971 }
1972 if (!keep) {
Chris Mason236454d2007-04-19 13:37:44 -04001973 u64 disk_blocknr = 0;
1974 u64 disk_num_blocks = 0;
1975 u64 extent_num_blocks = 0;
1976 if (found_extent) {
1977 disk_blocknr =
1978 btrfs_file_extent_disk_blocknr(extent);
1979 disk_num_blocks =
1980 btrfs_file_extent_disk_num_blocks(extent);
1981 extent_num_blocks =
1982 btrfs_file_extent_num_blocks(extent);
Chris Masonde428b62007-05-18 13:28:27 -04001983 *hint_block =
1984 btrfs_file_extent_disk_blocknr(extent);
Chris Mason236454d2007-04-19 13:37:44 -04001985 }
Chris Masonb18c6682007-04-17 13:26:50 -04001986 ret = btrfs_del_item(trans, root, path);
1987 BUG_ON(ret);
1988 btrfs_release_path(root, path);
Chris Mason098f59c2007-05-11 11:33:21 -04001989 extent = NULL;
Chris Mason3a686372007-05-24 13:35:57 -04001990 if (found_extent && disk_blocknr != 0) {
Chris Mason098f59c2007-05-11 11:33:21 -04001991 inode->i_blocks -= extent_num_blocks << 3;
Chris Mason236454d2007-04-19 13:37:44 -04001992 ret = btrfs_free_extent(trans, root,
1993 disk_blocknr,
1994 disk_num_blocks, 0);
1995 }
Chris Masonb18c6682007-04-17 13:26:50 -04001996
1997 BUG_ON(ret);
1998 if (!bookend && search_start >= end) {
1999 ret = 0;
2000 goto out;
2001 }
2002 if (!bookend)
Chris Masona429e512007-04-18 16:15:28 -04002003 continue;
Chris Masonb18c6682007-04-17 13:26:50 -04002004 }
Chris Mason236454d2007-04-19 13:37:44 -04002005 if (bookend && found_extent) {
Chris Masonb18c6682007-04-17 13:26:50 -04002006 /* create bookend */
2007 struct btrfs_key ins;
Chris Masonb18c6682007-04-17 13:26:50 -04002008 ins.objectid = inode->i_ino;
2009 ins.offset = end;
2010 ins.flags = 0;
2011 btrfs_set_key_type(&ins, BTRFS_EXTENT_DATA_KEY);
2012
2013 btrfs_release_path(root, path);
Chris Masonb18c6682007-04-17 13:26:50 -04002014 ret = btrfs_insert_empty_item(trans, root, path, &ins,
2015 sizeof(*extent));
2016 BUG_ON(ret);
2017 extent = btrfs_item_ptr(
2018 btrfs_buffer_leaf(path->nodes[0]),
2019 path->slots[0],
2020 struct btrfs_file_extent_item);
2021 btrfs_set_file_extent_disk_blocknr(extent,
2022 btrfs_file_extent_disk_blocknr(&old));
2023 btrfs_set_file_extent_disk_num_blocks(extent,
2024 btrfs_file_extent_disk_num_blocks(&old));
2025
2026 btrfs_set_file_extent_offset(extent,
2027 btrfs_file_extent_offset(&old) +
2028 ((end - key.offset) >> inode->i_blkbits));
2029 WARN_ON(btrfs_file_extent_num_blocks(&old) <
Chris Mason3a686372007-05-24 13:35:57 -04002030 (extent_end - end) >> inode->i_blkbits);
Chris Masonb18c6682007-04-17 13:26:50 -04002031 btrfs_set_file_extent_num_blocks(extent,
Chris Mason3a686372007-05-24 13:35:57 -04002032 (extent_end - end) >> inode->i_blkbits);
Chris Masonb18c6682007-04-17 13:26:50 -04002033
Chris Mason236454d2007-04-19 13:37:44 -04002034 btrfs_set_file_extent_type(extent,
2035 BTRFS_FILE_EXTENT_REG);
Chris Masonb18c6682007-04-17 13:26:50 -04002036 btrfs_set_file_extent_generation(extent,
2037 btrfs_file_extent_generation(&old));
Chris Masonb18c6682007-04-17 13:26:50 -04002038 btrfs_mark_buffer_dirty(path->nodes[0]);
Chris Mason3a686372007-05-24 13:35:57 -04002039 if (btrfs_file_extent_disk_blocknr(&old) != 0) {
2040 inode->i_blocks +=
2041 btrfs_file_extent_num_blocks(extent) << 3;
2042 }
Chris Masonb18c6682007-04-17 13:26:50 -04002043 ret = 0;
Chris Mason70b2bef2007-04-17 15:39:32 -04002044 goto out;
Chris Masonb18c6682007-04-17 13:26:50 -04002045 }
Chris Masonb18c6682007-04-17 13:26:50 -04002046 }
Chris Masonb18c6682007-04-17 13:26:50 -04002047out:
Chris Masonb18c6682007-04-17 13:26:50 -04002048 btrfs_free_path(path);
2049 return ret;
2050}
2051
2052static int prepare_pages(struct btrfs_root *root,
Chris Mason75dfe392007-03-29 11:56:46 -04002053 struct file *file,
2054 struct page **pages,
2055 size_t num_pages,
2056 loff_t pos,
Chris Mason2932f3e2007-04-10 14:22:02 -04002057 unsigned long first_index,
2058 unsigned long last_index,
Chris Mason6567e832007-04-16 09:22:45 -04002059 size_t write_bytes,
2060 u64 alloc_extent_start)
Chris Mason75dfe392007-03-29 11:56:46 -04002061{
2062 int i;
2063 unsigned long index = pos >> PAGE_CACHE_SHIFT;
2064 struct inode *inode = file->f_path.dentry->d_inode;
2065 int offset;
2066 int err = 0;
Chris Mason75dfe392007-03-29 11:56:46 -04002067 int this_write;
Chris Mason6567e832007-04-16 09:22:45 -04002068 struct buffer_head *bh;
2069 struct buffer_head *head;
Chris Mason75dfe392007-03-29 11:56:46 -04002070 loff_t isize = i_size_read(inode);
2071
2072 memset(pages, 0, num_pages * sizeof(struct page *));
2073
2074 for (i = 0; i < num_pages; i++) {
2075 pages[i] = grab_cache_page(inode->i_mapping, index + i);
2076 if (!pages[i]) {
2077 err = -ENOMEM;
2078 goto failed_release;
2079 }
Chris Mason35b7e472007-05-02 15:53:43 -04002080 cancel_dirty_page(pages[i], PAGE_CACHE_SIZE);
2081 wait_on_page_writeback(pages[i]);
Chris Mason75dfe392007-03-29 11:56:46 -04002082 offset = pos & (PAGE_CACHE_SIZE -1);
2083 this_write = min(PAGE_CACHE_SIZE - offset, write_bytes);
Chris Mason35b7e472007-05-02 15:53:43 -04002084 if (!page_has_buffers(pages[i])) {
2085 create_empty_buffers(pages[i],
2086 root->fs_info->sb->s_blocksize,
2087 (1 << BH_Uptodate));
2088 }
Chris Mason6567e832007-04-16 09:22:45 -04002089 head = page_buffers(pages[i]);
2090 bh = head;
2091 do {
2092 err = btrfs_map_bh_to_logical(root, bh,
2093 alloc_extent_start);
2094 BUG_ON(err);
2095 if (err)
2096 goto failed_truncate;
2097 bh = bh->b_this_page;
Chris Mason236454d2007-04-19 13:37:44 -04002098 if (alloc_extent_start)
2099 alloc_extent_start++;
Chris Mason6567e832007-04-16 09:22:45 -04002100 } while (bh != head);
Chris Mason75dfe392007-03-29 11:56:46 -04002101 pos += this_write;
Chris Mason75dfe392007-03-29 11:56:46 -04002102 WARN_ON(this_write > write_bytes);
2103 write_bytes -= this_write;
2104 }
2105 return 0;
2106
2107failed_release:
2108 btrfs_drop_pages(pages, num_pages);
2109 return err;
2110
2111failed_truncate:
2112 btrfs_drop_pages(pages, num_pages);
2113 if (pos > isize)
2114 vmtruncate(inode, isize);
2115 return err;
2116}
2117
2118static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
2119 size_t count, loff_t *ppos)
2120{
2121 loff_t pos;
2122 size_t num_written = 0;
2123 int err = 0;
2124 int ret = 0;
Chris Mason75dfe392007-03-29 11:56:46 -04002125 struct inode *inode = file->f_path.dentry->d_inode;
Chris Masond6e4a422007-04-06 15:37:36 -04002126 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Masonb18c6682007-04-17 13:26:50 -04002127 struct page *pages[8];
Chris Mason35b7e472007-05-02 15:53:43 -04002128 struct page *pinned[2];
Chris Mason2932f3e2007-04-10 14:22:02 -04002129 unsigned long first_index;
2130 unsigned long last_index;
Chris Mason6567e832007-04-16 09:22:45 -04002131 u64 start_pos;
2132 u64 num_blocks;
2133 u64 alloc_extent_start;
Chris Masonde428b62007-05-18 13:28:27 -04002134 u64 hint_block;
Chris Mason6567e832007-04-16 09:22:45 -04002135 struct btrfs_trans_handle *trans;
Chris Masonb18c6682007-04-17 13:26:50 -04002136 struct btrfs_key ins;
Chris Mason35b7e472007-05-02 15:53:43 -04002137 pinned[0] = NULL;
2138 pinned[1] = NULL;
Chris Mason75dfe392007-03-29 11:56:46 -04002139 if (file->f_flags & O_DIRECT)
2140 return -EINVAL;
2141 pos = *ppos;
Chris Mason75dfe392007-03-29 11:56:46 -04002142 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
2143 current->backing_dev_info = inode->i_mapping->backing_dev_info;
2144 err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
2145 if (err)
2146 goto out;
2147 if (count == 0)
2148 goto out;
2149 err = remove_suid(file->f_path.dentry);
2150 if (err)
2151 goto out;
2152 file_update_time(file);
Chris Masona429e512007-04-18 16:15:28 -04002153
2154 start_pos = pos & ~((u64)PAGE_CACHE_SIZE - 1);
2155 num_blocks = (count + pos - start_pos + root->blocksize - 1) >>
2156 inode->i_blkbits;
2157
Chris Mason75dfe392007-03-29 11:56:46 -04002158 mutex_lock(&inode->i_mutex);
Chris Mason2932f3e2007-04-10 14:22:02 -04002159 first_index = pos >> PAGE_CACHE_SHIFT;
2160 last_index = (pos + count) >> PAGE_CACHE_SHIFT;
Chris Mason6567e832007-04-16 09:22:45 -04002161
Chris Mason1de037a2007-05-29 15:17:08 -04002162 if ((pos & (PAGE_CACHE_SIZE - 1))) {
Chris Masona429e512007-04-18 16:15:28 -04002163 pinned[0] = grab_cache_page(inode->i_mapping, first_index);
2164 if (!PageUptodate(pinned[0])) {
2165 ret = mpage_readpage(pinned[0], btrfs_get_block);
2166 BUG_ON(ret);
Chris Mason35b7e472007-05-02 15:53:43 -04002167 wait_on_page_locked(pinned[0]);
Chris Masona429e512007-04-18 16:15:28 -04002168 } else {
2169 unlock_page(pinned[0]);
2170 }
2171 }
Chris Mason1de037a2007-05-29 15:17:08 -04002172 if ((pos + count) & (PAGE_CACHE_SIZE - 1)) {
Chris Masona429e512007-04-18 16:15:28 -04002173 pinned[1] = grab_cache_page(inode->i_mapping, last_index);
2174 if (!PageUptodate(pinned[1])) {
2175 ret = mpage_readpage(pinned[1], btrfs_get_block);
2176 BUG_ON(ret);
Chris Mason35b7e472007-05-02 15:53:43 -04002177 wait_on_page_locked(pinned[1]);
Chris Masona429e512007-04-18 16:15:28 -04002178 } else {
2179 unlock_page(pinned[1]);
2180 }
2181 }
2182
Chris Mason6567e832007-04-16 09:22:45 -04002183 mutex_lock(&root->fs_info->fs_mutex);
2184 trans = btrfs_start_transaction(root, 1);
2185 if (!trans) {
2186 err = -ENOMEM;
Chris Masonb18c6682007-04-17 13:26:50 -04002187 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason6567e832007-04-16 09:22:45 -04002188 goto out_unlock;
2189 }
Chris Mason31f3c992007-04-30 15:25:45 -04002190 btrfs_set_trans_block_group(trans, inode);
Chris Masona429e512007-04-18 16:15:28 -04002191 /* FIXME blocksize != 4096 */
2192 inode->i_blocks += num_blocks << 3;
Chris Masonde428b62007-05-18 13:28:27 -04002193 hint_block = 0;
Chris Masonb18c6682007-04-17 13:26:50 -04002194 if (start_pos < inode->i_size) {
Chris Masona429e512007-04-18 16:15:28 -04002195 /* FIXME blocksize != pagesize */
Chris Masonb18c6682007-04-17 13:26:50 -04002196 ret = drop_extents(trans, root, inode,
2197 start_pos,
2198 (pos + count + root->blocksize -1) &
Chris Masonde428b62007-05-18 13:28:27 -04002199 ~((u64)root->blocksize - 1), &hint_block);
Chris Mason236454d2007-04-19 13:37:44 -04002200 BUG_ON(ret);
Chris Masonb18c6682007-04-17 13:26:50 -04002201 }
Chris Mason3a686372007-05-24 13:35:57 -04002202 if (inode->i_size < start_pos) {
2203 u64 last_pos_in_file;
2204 u64 hole_size;
2205 u64 mask = root->blocksize - 1;
2206 last_pos_in_file = (inode->i_size + mask) & ~mask;
2207 hole_size = (start_pos - last_pos_in_file + mask) & ~mask;
2208 hole_size >>= inode->i_blkbits;
2209 if (last_pos_in_file < start_pos) {
2210 ret = btrfs_insert_file_extent(trans, root,
2211 inode->i_ino,
2212 last_pos_in_file,
2213 0, 0, hole_size);
2214 }
2215 BUG_ON(ret);
2216 }
Chris Mason236454d2007-04-19 13:37:44 -04002217 if (inode->i_size >= PAGE_CACHE_SIZE || pos + count < inode->i_size ||
2218 pos + count - start_pos > BTRFS_MAX_INLINE_DATA_SIZE(root)) {
Chris Mason4d775672007-04-20 20:23:12 -04002219 ret = btrfs_alloc_extent(trans, root, inode->i_ino,
Chris Masonde428b62007-05-18 13:28:27 -04002220 num_blocks, hint_block, (u64)-1,
2221 &ins, 1);
Chris Mason236454d2007-04-19 13:37:44 -04002222 BUG_ON(ret);
2223 ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
Chris Mason3a686372007-05-24 13:35:57 -04002224 start_pos, ins.objectid, ins.offset,
2225 ins.offset);
Chris Mason236454d2007-04-19 13:37:44 -04002226 BUG_ON(ret);
2227 } else {
2228 ins.offset = 0;
2229 ins.objectid = 0;
2230 }
Chris Masonb18c6682007-04-17 13:26:50 -04002231 BUG_ON(ret);
2232 alloc_extent_start = ins.objectid;
Chris Masone37c9e62007-05-09 20:13:14 -04002233 // btrfs_update_inode_block_group(trans, inode);
Chris Masonb18c6682007-04-17 13:26:50 -04002234 ret = btrfs_end_transaction(trans, root);
Chris Mason6567e832007-04-16 09:22:45 -04002235 mutex_unlock(&root->fs_info->fs_mutex);
2236
Chris Mason75dfe392007-03-29 11:56:46 -04002237 while(count > 0) {
2238 size_t offset = pos & (PAGE_CACHE_SIZE - 1);
2239 size_t write_bytes = min(count, PAGE_CACHE_SIZE - offset);
2240 size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
2241 PAGE_CACHE_SHIFT;
Chris Masonb18c6682007-04-17 13:26:50 -04002242
2243 memset(pages, 0, sizeof(pages));
2244 ret = prepare_pages(root, file, pages, num_pages,
Chris Mason6567e832007-04-16 09:22:45 -04002245 pos, first_index, last_index,
2246 write_bytes, alloc_extent_start);
Chris Mason75dfe392007-03-29 11:56:46 -04002247 BUG_ON(ret);
Chris Masonb18c6682007-04-17 13:26:50 -04002248
Chris Mason6567e832007-04-16 09:22:45 -04002249 /* FIXME blocks != pagesize */
Chris Mason236454d2007-04-19 13:37:44 -04002250 if (alloc_extent_start)
2251 alloc_extent_start += num_pages;
Chris Mason75dfe392007-03-29 11:56:46 -04002252 ret = btrfs_copy_from_user(pos, num_pages,
2253 write_bytes, pages, buf);
2254 BUG_ON(ret);
2255
Chris Masonf254e522007-03-29 15:15:27 -04002256 ret = dirty_and_release_pages(NULL, root, file, pages,
Chris Mason70b2bef2007-04-17 15:39:32 -04002257 num_pages, pos, write_bytes);
Chris Mason75dfe392007-03-29 11:56:46 -04002258 BUG_ON(ret);
2259 btrfs_drop_pages(pages, num_pages);
2260
Chris Mason75dfe392007-03-29 11:56:46 -04002261 buf += write_bytes;
2262 count -= write_bytes;
2263 pos += write_bytes;
2264 num_written += write_bytes;
2265
2266 balance_dirty_pages_ratelimited(inode->i_mapping);
Chris Mason35b7e472007-05-02 15:53:43 -04002267 btrfs_btree_balance_dirty(root);
Chris Mason75dfe392007-03-29 11:56:46 -04002268 cond_resched();
2269 }
Chris Mason6567e832007-04-16 09:22:45 -04002270out_unlock:
Chris Mason75dfe392007-03-29 11:56:46 -04002271 mutex_unlock(&inode->i_mutex);
2272out:
Chris Masona429e512007-04-18 16:15:28 -04002273 if (pinned[0])
2274 page_cache_release(pinned[0]);
2275 if (pinned[1])
2276 page_cache_release(pinned[1]);
Chris Mason75dfe392007-03-29 11:56:46 -04002277 *ppos = pos;
2278 current->backing_dev_info = NULL;
Chris Masona429e512007-04-18 16:15:28 -04002279 mark_inode_dirty(inode);
Chris Mason75dfe392007-03-29 11:56:46 -04002280 return num_written ? num_written : err;
2281}
2282
Chris Masonf254e522007-03-29 15:15:27 -04002283static int btrfs_read_actor(read_descriptor_t *desc, struct page *page,
2284 unsigned long offset, unsigned long size)
2285{
2286 char *kaddr;
2287 unsigned long left, count = desc->count;
Chris Masond6e4a422007-04-06 15:37:36 -04002288 struct inode *inode = page->mapping->host;
Chris Masonf254e522007-03-29 15:15:27 -04002289
2290 if (size > count)
2291 size = count;
2292
2293 if (!PageChecked(page)) {
2294 /* FIXME, do it per block */
Chris Masond6e4a422007-04-06 15:37:36 -04002295 struct btrfs_root *root = BTRFS_I(inode)->root;
Chris Mason1de037a2007-05-29 15:17:08 -04002296 int ret;
2297 struct buffer_head *bh;
Chris Mason236454d2007-04-19 13:37:44 -04002298
Chris Mason1de037a2007-05-29 15:17:08 -04002299 if (page_has_buffers(page)) {
2300 bh = page_buffers(page);
2301 if (!buffer_mapped(bh)) {
2302 SetPageChecked(page);
2303 goto checked;
2304 }
2305 }
2306
2307 ret = btrfs_csum_verify_file_block(root,
Chris Mason236454d2007-04-19 13:37:44 -04002308 page->mapping->host->i_ino,
2309 page->index << PAGE_CACHE_SHIFT,
2310 kmap(page), PAGE_CACHE_SIZE);
Chris Masonf254e522007-03-29 15:15:27 -04002311 if (ret) {
Chris Mason3a686372007-05-24 13:35:57 -04002312 if (ret != -ENOENT) {
Chris Mason1de037a2007-05-29 15:17:08 -04002313 printk("failed to verify ino %lu page %lu ret %d\n",
Chris Mason3a686372007-05-24 13:35:57 -04002314 page->mapping->host->i_ino,
Chris Mason1de037a2007-05-29 15:17:08 -04002315 page->index, ret);
2316 memset(page_address(page), 1, PAGE_CACHE_SIZE);
Chris Mason3a686372007-05-24 13:35:57 -04002317 flush_dcache_page(page);
2318 }
Chris Masonf254e522007-03-29 15:15:27 -04002319 }
2320 SetPageChecked(page);
2321 kunmap(page);
2322 }
Chris Mason1de037a2007-05-29 15:17:08 -04002323checked:
Chris Masonf254e522007-03-29 15:15:27 -04002324 /*
2325 * Faults on the destination of a read are common, so do it before
2326 * taking the kmap.
2327 */
2328 if (!fault_in_pages_writeable(desc->arg.buf, size)) {
2329 kaddr = kmap_atomic(page, KM_USER0);
2330 left = __copy_to_user_inatomic(desc->arg.buf,
2331 kaddr + offset, size);
2332 kunmap_atomic(kaddr, KM_USER0);
2333 if (left == 0)
2334 goto success;
2335 }
2336
2337 /* Do it the slow way */
2338 kaddr = kmap(page);
2339 left = __copy_to_user(desc->arg.buf, kaddr + offset, size);
2340 kunmap(page);
2341
2342 if (left) {
2343 size -= left;
2344 desc->error = -EFAULT;
2345 }
2346success:
2347 desc->count = count - size;
2348 desc->written += size;
2349 desc->arg.buf += size;
2350 return size;
2351}
2352
2353/**
2354 * btrfs_file_aio_read - filesystem read routine
2355 * @iocb: kernel I/O control block
2356 * @iov: io vector request
2357 * @nr_segs: number of segments in the iovec
2358 * @pos: current file position
2359 */
2360static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
2361 unsigned long nr_segs, loff_t pos)
2362{
2363 struct file *filp = iocb->ki_filp;
2364 ssize_t retval;
2365 unsigned long seg;
2366 size_t count;
2367 loff_t *ppos = &iocb->ki_pos;
2368
2369 count = 0;
2370 for (seg = 0; seg < nr_segs; seg++) {
2371 const struct iovec *iv = &iov[seg];
2372
2373 /*
2374 * If any segment has a negative length, or the cumulative
2375 * length ever wraps negative then return -EINVAL.
2376 */
2377 count += iv->iov_len;
2378 if (unlikely((ssize_t)(count|iv->iov_len) < 0))
2379 return -EINVAL;
2380 if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
2381 continue;
2382 if (seg == 0)
2383 return -EFAULT;
2384 nr_segs = seg;
2385 count -= iv->iov_len; /* This segment is no good */
2386 break;
2387 }
2388 retval = 0;
2389 if (count) {
2390 for (seg = 0; seg < nr_segs; seg++) {
2391 read_descriptor_t desc;
2392
2393 desc.written = 0;
2394 desc.arg.buf = iov[seg].iov_base;
2395 desc.count = iov[seg].iov_len;
2396 if (desc.count == 0)
2397 continue;
2398 desc.error = 0;
2399 do_generic_file_read(filp, ppos, &desc,
2400 btrfs_read_actor);
2401 retval += desc.written;
2402 if (desc.error) {
2403 retval = retval ?: desc.error;
2404 break;
2405 }
2406 }
2407 }
2408 return retval;
2409}
2410
Chris Mason2619ba12007-04-10 16:58:11 -04002411static int create_subvol(struct btrfs_root *root, char *name, int namelen)
2412{
2413 struct btrfs_trans_handle *trans;
2414 struct btrfs_key key;
2415 struct btrfs_root_item root_item;
2416 struct btrfs_inode_item *inode_item;
2417 struct buffer_head *subvol;
2418 struct btrfs_leaf *leaf;
2419 struct btrfs_root *new_root;
2420 struct inode *inode;
Chris Mason31f3c992007-04-30 15:25:45 -04002421 struct inode *dir;
Chris Mason2619ba12007-04-10 16:58:11 -04002422 int ret;
2423 u64 objectid;
2424 u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
2425
2426 mutex_lock(&root->fs_info->fs_mutex);
2427 trans = btrfs_start_transaction(root, 1);
2428 BUG_ON(!trans);
2429
Chris Mason31f3c992007-04-30 15:25:45 -04002430 subvol = btrfs_alloc_free_block(trans, root, 0);
Chris Mason5e828492007-04-23 19:10:49 -04002431 if (subvol == NULL)
2432 return -ENOSPC;
Chris Mason2619ba12007-04-10 16:58:11 -04002433 leaf = btrfs_buffer_leaf(subvol);
2434 btrfs_set_header_nritems(&leaf->header, 0);
2435 btrfs_set_header_level(&leaf->header, 0);
Chris Mason7eccb902007-04-11 15:53:25 -04002436 btrfs_set_header_blocknr(&leaf->header, bh_blocknr(subvol));
Chris Mason2619ba12007-04-10 16:58:11 -04002437 btrfs_set_header_generation(&leaf->header, trans->transid);
Chris Mason4d775672007-04-20 20:23:12 -04002438 btrfs_set_header_owner(&leaf->header, root->root_key.objectid);
Chris Mason2619ba12007-04-10 16:58:11 -04002439 memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid,
2440 sizeof(leaf->header.fsid));
Chris Mason4d775672007-04-20 20:23:12 -04002441 mark_buffer_dirty(subvol);
Chris Mason2619ba12007-04-10 16:58:11 -04002442
2443 inode_item = &root_item.inode;
2444 memset(inode_item, 0, sizeof(*inode_item));
2445 btrfs_set_inode_generation(inode_item, 1);
2446 btrfs_set_inode_size(inode_item, 3);
2447 btrfs_set_inode_nlink(inode_item, 1);
2448 btrfs_set_inode_nblocks(inode_item, 1);
2449 btrfs_set_inode_mode(inode_item, S_IFDIR | 0755);
2450
Chris Mason7eccb902007-04-11 15:53:25 -04002451 btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol));
Chris Mason2619ba12007-04-10 16:58:11 -04002452 btrfs_set_root_refs(&root_item, 1);
Chris Mason5e828492007-04-23 19:10:49 -04002453 brelse(subvol);
2454 subvol = NULL;
Chris Mason2619ba12007-04-10 16:58:11 -04002455
Chris Mason2619ba12007-04-10 16:58:11 -04002456 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
2457 0, &objectid);
2458 BUG_ON(ret);
2459
2460 btrfs_set_root_dirid(&root_item, new_dirid);
2461
2462 key.objectid = objectid;
2463 key.offset = 1;
2464 key.flags = 0;
2465 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
2466 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2467 &root_item);
2468 BUG_ON(ret);
2469
2470 /*
2471 * insert the directory item
2472 */
2473 key.offset = (u64)-1;
Chris Mason31f3c992007-04-30 15:25:45 -04002474 dir = root->fs_info->sb->s_root->d_inode;
Chris Mason2619ba12007-04-10 16:58:11 -04002475 ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
Chris Masonfabb5682007-06-07 22:13:21 -04002476 name, namelen, dir->i_ino, &key,
2477 BTRFS_FT_DIR);
Chris Mason2619ba12007-04-10 16:58:11 -04002478 BUG_ON(ret);
2479
2480 ret = btrfs_commit_transaction(trans, root);
2481 BUG_ON(ret);
2482
2483 new_root = btrfs_read_fs_root(root->fs_info, &key);
2484 BUG_ON(!new_root);
2485
2486 trans = btrfs_start_transaction(new_root, 1);
2487 BUG_ON(!trans);
2488
Chris Mason31f3c992007-04-30 15:25:45 -04002489 inode = btrfs_new_inode(trans, new_root, new_dirid,
2490 BTRFS_I(dir)->block_group, S_IFDIR | 0700);
Chris Mason2619ba12007-04-10 16:58:11 -04002491 inode->i_op = &btrfs_dir_inode_operations;
2492 inode->i_fop = &btrfs_dir_file_operations;
2493
2494 ret = btrfs_make_empty_dir(trans, new_root, new_dirid, new_dirid);
2495 BUG_ON(ret);
2496
2497 inode->i_nlink = 1;
2498 inode->i_size = 6;
2499 ret = btrfs_update_inode(trans, new_root, inode);
2500 BUG_ON(ret);
2501
2502 ret = btrfs_commit_transaction(trans, new_root);
2503 BUG_ON(ret);
2504
2505 iput(inode);
2506
2507 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason35b7e472007-05-02 15:53:43 -04002508 btrfs_btree_balance_dirty(root);
Chris Mason2619ba12007-04-10 16:58:11 -04002509 return 0;
2510}
2511
Chris Masonc5739bb2007-04-10 09:27:04 -04002512static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
2513{
2514 struct btrfs_trans_handle *trans;
2515 struct btrfs_key key;
2516 struct btrfs_root_item new_root_item;
2517 int ret;
2518 u64 objectid;
2519
Chris Mason2619ba12007-04-10 16:58:11 -04002520 if (!root->ref_cows)
2521 return -EINVAL;
2522
Chris Masonc5739bb2007-04-10 09:27:04 -04002523 mutex_lock(&root->fs_info->fs_mutex);
2524 trans = btrfs_start_transaction(root, 1);
2525 BUG_ON(!trans);
2526
2527 ret = btrfs_update_inode(trans, root, root->inode);
2528 BUG_ON(ret);
2529
Chris Mason1b05da22007-04-10 12:13:09 -04002530 ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
2531 0, &objectid);
Chris Masonc5739bb2007-04-10 09:27:04 -04002532 BUG_ON(ret);
2533
Chris Masonc5739bb2007-04-10 09:27:04 -04002534 memcpy(&new_root_item, &root->root_item,
2535 sizeof(new_root_item));
2536
2537 key.objectid = objectid;
Chris Masonc5739bb2007-04-10 09:27:04 -04002538 key.offset = 1;
2539 key.flags = 0;
2540 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
Chris Mason7eccb902007-04-11 15:53:25 -04002541 btrfs_set_root_blocknr(&new_root_item, bh_blocknr(root->node));
Chris Masonc5739bb2007-04-10 09:27:04 -04002542
2543 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
2544 &new_root_item);
2545 BUG_ON(ret);
2546
Chris Masonc5739bb2007-04-10 09:27:04 -04002547 /*
2548 * insert the directory item
2549 */
2550 key.offset = (u64)-1;
2551 ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
2552 name, namelen,
2553 root->fs_info->sb->s_root->d_inode->i_ino,
Chris Masonfabb5682007-06-07 22:13:21 -04002554 &key, BTRFS_FT_DIR);
Chris Masonc5739bb2007-04-10 09:27:04 -04002555
2556 BUG_ON(ret);
2557
2558 ret = btrfs_inc_root_ref(trans, root);
2559 BUG_ON(ret);
2560
2561 ret = btrfs_commit_transaction(trans, root);
2562 BUG_ON(ret);
2563 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason35b7e472007-05-02 15:53:43 -04002564 btrfs_btree_balance_dirty(root);
Chris Masonc5739bb2007-04-10 09:27:04 -04002565 return 0;
2566}
2567
Chris Mason8352d8a2007-04-12 10:43:05 -04002568static int add_disk(struct btrfs_root *root, char *name, int namelen)
2569{
2570 struct block_device *bdev;
2571 struct btrfs_path *path;
2572 struct super_block *sb = root->fs_info->sb;
2573 struct btrfs_root *dev_root = root->fs_info->dev_root;
2574 struct btrfs_trans_handle *trans;
2575 struct btrfs_device_item *dev_item;
2576 struct btrfs_key key;
2577 u16 item_size;
2578 u64 num_blocks;
2579 u64 new_blocks;
Chris Masonb4100d62007-04-12 12:14:00 -04002580 u64 device_id;
Chris Mason8352d8a2007-04-12 10:43:05 -04002581 int ret;
Chris Masonb4100d62007-04-12 12:14:00 -04002582
Chris Mason8352d8a2007-04-12 10:43:05 -04002583printk("adding disk %s\n", name);
2584 path = btrfs_alloc_path();
2585 if (!path)
2586 return -ENOMEM;
2587 num_blocks = btrfs_super_total_blocks(root->fs_info->disk_super);
2588 bdev = open_bdev_excl(name, O_RDWR, sb);
2589 if (IS_ERR(bdev)) {
2590 ret = PTR_ERR(bdev);
2591printk("open bdev excl failed ret %d\n", ret);
2592 goto out_nolock;
2593 }
2594 set_blocksize(bdev, sb->s_blocksize);
2595 new_blocks = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
2596 key.objectid = num_blocks;
2597 key.offset = new_blocks;
2598 key.flags = 0;
2599 btrfs_set_key_type(&key, BTRFS_DEV_ITEM_KEY);
2600
2601 mutex_lock(&dev_root->fs_info->fs_mutex);
2602 trans = btrfs_start_transaction(dev_root, 1);
2603 item_size = sizeof(*dev_item) + namelen;
2604printk("insert empty on %Lu %Lu %u size %d\n", num_blocks, new_blocks, key.flags, item_size);
2605 ret = btrfs_insert_empty_item(trans, dev_root, path, &key, item_size);
2606 if (ret) {
2607printk("insert failed %d\n", ret);
2608 close_bdev_excl(bdev);
2609 if (ret > 0)
2610 ret = -EEXIST;
2611 goto out;
2612 }
2613 dev_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
2614 path->slots[0], struct btrfs_device_item);
2615 btrfs_set_device_pathlen(dev_item, namelen);
2616 memcpy(dev_item + 1, name, namelen);
Chris Masonb4100d62007-04-12 12:14:00 -04002617
2618 device_id = btrfs_super_last_device_id(root->fs_info->disk_super) + 1;
2619 btrfs_set_super_last_device_id(root->fs_info->disk_super, device_id);
2620 btrfs_set_device_id(dev_item, device_id);
Chris Mason8352d8a2007-04-12 10:43:05 -04002621 mark_buffer_dirty(path->nodes[0]);
2622
Chris Masonb4100d62007-04-12 12:14:00 -04002623 ret = btrfs_insert_dev_radix(root, bdev, device_id, num_blocks,
2624 new_blocks);
Chris Mason8352d8a2007-04-12 10:43:05 -04002625
2626 if (!ret) {
2627 btrfs_set_super_total_blocks(root->fs_info->disk_super,
2628 num_blocks + new_blocks);
2629 i_size_write(root->fs_info->btree_inode,
2630 (num_blocks + new_blocks) <<
2631 root->fs_info->btree_inode->i_blkbits);
2632 }
2633
2634out:
2635 ret = btrfs_commit_transaction(trans, dev_root);
2636 BUG_ON(ret);
2637 mutex_unlock(&root->fs_info->fs_mutex);
2638out_nolock:
2639 btrfs_free_path(path);
Chris Mason35b7e472007-05-02 15:53:43 -04002640 btrfs_btree_balance_dirty(root);
Chris Mason8352d8a2007-04-12 10:43:05 -04002641
2642 return ret;
2643}
2644
Chris Masonc5739bb2007-04-10 09:27:04 -04002645static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int
2646 cmd, unsigned long arg)
2647{
2648 struct btrfs_root *root = BTRFS_I(inode)->root;
2649 struct btrfs_ioctl_vol_args vol_args;
Chris Mason8352d8a2007-04-12 10:43:05 -04002650 int ret = 0;
Chris Mason7e381802007-04-19 15:36:27 -04002651 struct btrfs_dir_item *di;
Chris Masonc5739bb2007-04-10 09:27:04 -04002652 int namelen;
Chris Mason2619ba12007-04-10 16:58:11 -04002653 struct btrfs_path *path;
2654 u64 root_dirid;
Chris Masonc5739bb2007-04-10 09:27:04 -04002655
Chris Masonc5739bb2007-04-10 09:27:04 -04002656 switch (cmd) {
2657 case BTRFS_IOC_SNAP_CREATE:
2658 if (copy_from_user(&vol_args,
2659 (struct btrfs_ioctl_vol_args __user *)arg,
2660 sizeof(vol_args)))
2661 return -EFAULT;
2662 namelen = strlen(vol_args.name);
2663 if (namelen > BTRFS_VOL_NAME_MAX)
2664 return -EINVAL;
Chris Mason2619ba12007-04-10 16:58:11 -04002665 path = btrfs_alloc_path();
2666 if (!path)
2667 return -ENOMEM;
Chris Mason2d13d8d2007-04-10 20:07:20 -04002668 root_dirid = root->fs_info->sb->s_root->d_inode->i_ino,
Chris Mason2619ba12007-04-10 16:58:11 -04002669 mutex_lock(&root->fs_info->fs_mutex);
Chris Mason7e381802007-04-19 15:36:27 -04002670 di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root,
Chris Mason2619ba12007-04-10 16:58:11 -04002671 path, root_dirid,
2672 vol_args.name, namelen, 0);
2673 mutex_unlock(&root->fs_info->fs_mutex);
Chris Mason2d13d8d2007-04-10 20:07:20 -04002674 btrfs_free_path(path);
Chris Mason7e381802007-04-19 15:36:27 -04002675 if (di && !IS_ERR(di))
Chris Mason2619ba12007-04-10 16:58:11 -04002676 return -EEXIST;
2677
2678 if (root == root->fs_info->tree_root)
2679 ret = create_subvol(root, vol_args.name, namelen);
2680 else
2681 ret = create_snapshot(root, vol_args.name, namelen);
Chris Masonc5739bb2007-04-10 09:27:04 -04002682 WARN_ON(ret);
2683 break;
Chris Mason8352d8a2007-04-12 10:43:05 -04002684 case BTRFS_IOC_ADD_DISK:
2685 if (copy_from_user(&vol_args,
2686 (struct btrfs_ioctl_vol_args __user *)arg,
2687 sizeof(vol_args)))
2688 return -EFAULT;
2689 namelen = strlen(vol_args.name);
2690 if (namelen > BTRFS_VOL_NAME_MAX)
2691 return -EINVAL;
2692 vol_args.name[namelen] = '\0';
2693 ret = add_disk(root, vol_args.name, namelen);
2694 break;
Chris Masonc5739bb2007-04-10 09:27:04 -04002695 default:
2696 return -ENOTTY;
2697 }
Chris Mason8352d8a2007-04-12 10:43:05 -04002698 return ret;
Chris Masonc5739bb2007-04-10 09:27:04 -04002699}
2700
Chris Mason2c90e5d2007-04-02 10:50:19 -04002701static struct kmem_cache *btrfs_inode_cachep;
2702struct kmem_cache *btrfs_trans_handle_cachep;
2703struct kmem_cache *btrfs_transaction_cachep;
2704struct kmem_cache *btrfs_bit_radix_cachep;
2705struct kmem_cache *btrfs_path_cachep;
2706
2707/*
2708 * Called inside transaction, so use GFP_NOFS
2709 */
2710static struct inode *btrfs_alloc_inode(struct super_block *sb)
2711{
2712 struct btrfs_inode *ei;
2713
2714 ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS);
2715 if (!ei)
2716 return NULL;
Chris Mason2c90e5d2007-04-02 10:50:19 -04002717 return &ei->vfs_inode;
2718}
2719
2720static void btrfs_destroy_inode(struct inode *inode)
2721{
Chris Mason2c90e5d2007-04-02 10:50:19 -04002722 WARN_ON(!list_empty(&inode->i_dentry));
Chris Mason2c90e5d2007-04-02 10:50:19 -04002723 WARN_ON(inode->i_data.nrpages);
2724
Chris Mason2c90e5d2007-04-02 10:50:19 -04002725 kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
2726}
2727
2728static void init_once(void * foo, struct kmem_cache * cachep,
2729 unsigned long flags)
2730{
2731 struct btrfs_inode *ei = (struct btrfs_inode *) foo;
2732
Chris Masonf9f3c6b2007-05-21 14:05:12 -04002733 if ((flags & (SLAB_CTOR_CONSTRUCTOR)) ==
Chris Mason2c90e5d2007-04-02 10:50:19 -04002734 SLAB_CTOR_CONSTRUCTOR) {
2735 inode_init_once(&ei->vfs_inode);
2736 }
2737}
2738
2739static int init_inodecache(void)
2740{
2741 btrfs_inode_cachep = kmem_cache_create("btrfs_inode_cache",
2742 sizeof(struct btrfs_inode),
2743 0, (SLAB_RECLAIM_ACCOUNT|
2744 SLAB_MEM_SPREAD),
2745 init_once, NULL);
2746 btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle_cache",
2747 sizeof(struct btrfs_trans_handle),
2748 0, (SLAB_RECLAIM_ACCOUNT|
2749 SLAB_MEM_SPREAD),
2750 NULL, NULL);
2751 btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction_cache",
2752 sizeof(struct btrfs_transaction),
2753 0, (SLAB_RECLAIM_ACCOUNT|
2754 SLAB_MEM_SPREAD),
2755 NULL, NULL);
2756 btrfs_path_cachep = kmem_cache_create("btrfs_path_cache",
2757 sizeof(struct btrfs_transaction),
2758 0, (SLAB_RECLAIM_ACCOUNT|
2759 SLAB_MEM_SPREAD),
2760 NULL, NULL);
2761 btrfs_bit_radix_cachep = kmem_cache_create("btrfs_radix",
2762 256,
2763 0, (SLAB_RECLAIM_ACCOUNT|
2764 SLAB_MEM_SPREAD |
2765 SLAB_DESTROY_BY_RCU),
2766 NULL, NULL);
2767 if (btrfs_inode_cachep == NULL || btrfs_trans_handle_cachep == NULL ||
2768 btrfs_transaction_cachep == NULL || btrfs_bit_radix_cachep == NULL)
2769 return -ENOMEM;
2770 return 0;
2771}
2772
2773static void destroy_inodecache(void)
2774{
2775 kmem_cache_destroy(btrfs_inode_cachep);
2776 kmem_cache_destroy(btrfs_trans_handle_cachep);
2777 kmem_cache_destroy(btrfs_transaction_cachep);
2778 kmem_cache_destroy(btrfs_bit_radix_cachep);
2779 kmem_cache_destroy(btrfs_path_cachep);
2780}
2781
Chris Mason2e635a22007-03-21 11:12:56 -04002782static int btrfs_get_sb(struct file_system_type *fs_type,
2783 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
2784{
2785 return get_sb_bdev(fs_type, flags, dev_name, data,
2786 btrfs_fill_super, mnt);
2787}
2788
Chris Mason236454d2007-04-19 13:37:44 -04002789static int btrfs_getattr(struct vfsmount *mnt,
2790 struct dentry *dentry, struct kstat *stat)
2791{
2792 struct inode *inode = dentry->d_inode;
2793 generic_fillattr(inode, stat);
2794 stat->blksize = 256 * 1024;
2795 return 0;
2796}
2797
Chris Mason8fd17792007-04-19 21:01:03 -04002798static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
2799{
2800 struct btrfs_root *root = btrfs_sb(dentry->d_sb);
2801 struct btrfs_super_block *disk_super = root->fs_info->disk_super;
2802
2803 buf->f_namelen = BTRFS_NAME_LEN;
2804 buf->f_blocks = btrfs_super_total_blocks(disk_super);
2805 buf->f_bfree = buf->f_blocks - btrfs_super_blocks_used(disk_super);
2806 buf->f_bavail = buf->f_bfree;
2807 buf->f_bsize = dentry->d_sb->s_blocksize;
2808 buf->f_type = BTRFS_SUPER_MAGIC;
2809 return 0;
2810}
Chris Masonb5133862007-04-24 11:52:22 -04002811
Chris Masone06afa82007-05-23 15:44:28 -04002812static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
2813 struct inode * new_dir,struct dentry *new_dentry)
2814{
2815 struct btrfs_trans_handle *trans;
2816 struct btrfs_root *root = BTRFS_I(old_dir)->root;
2817 struct inode *new_inode = new_dentry->d_inode;
2818 struct inode *old_inode = old_dentry->d_inode;
2819 struct timespec ctime = CURRENT_TIME;
2820 struct btrfs_path *path;
2821 struct btrfs_dir_item *di;
2822 int ret;
2823
2824 if (S_ISDIR(old_inode->i_mode) && new_inode &&
2825 new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) {
2826 return -ENOTEMPTY;
2827 }
2828 mutex_lock(&root->fs_info->fs_mutex);
2829 trans = btrfs_start_transaction(root, 1);
2830 btrfs_set_trans_block_group(trans, new_dir);
2831 path = btrfs_alloc_path();
2832 if (!path) {
2833 ret = -ENOMEM;
2834 goto out_fail;
2835 }
2836
2837 old_dentry->d_inode->i_nlink++;
2838 old_dir->i_ctime = old_dir->i_mtime = ctime;
2839 new_dir->i_ctime = new_dir->i_mtime = ctime;
2840 old_inode->i_ctime = ctime;
2841 if (S_ISDIR(old_inode->i_mode) && old_dir != new_dir) {
2842 struct btrfs_key *location = &BTRFS_I(new_dir)->location;
2843 u64 old_parent_oid;
2844 di = btrfs_lookup_dir_item(trans, root, path, old_inode->i_ino,
2845 "..", 2, -1);
2846 if (IS_ERR(di)) {
2847 ret = PTR_ERR(di);
2848 goto out_fail;
2849 }
2850 if (!di) {
2851 ret = -ENOENT;
2852 goto out_fail;
2853 }
2854 old_parent_oid = btrfs_disk_key_objectid(&di->location);
2855 ret = btrfs_del_item(trans, root, path);
2856 if (ret) {
2857 ret = -EIO;
2858 goto out_fail;
2859 }
2860 btrfs_release_path(root, path);
2861
2862 di = btrfs_lookup_dir_index_item(trans, root, path,
2863 old_inode->i_ino,
2864 old_parent_oid,
2865 "..", 2, -1);
2866 if (IS_ERR(di)) {
2867 ret = PTR_ERR(di);
2868 goto out_fail;
2869 }
2870 if (!di) {
2871 ret = -ENOENT;
2872 goto out_fail;
2873 }
2874 ret = btrfs_del_item(trans, root, path);
2875 if (ret) {
2876 ret = -EIO;
2877 goto out_fail;
2878 }
2879 btrfs_release_path(root, path);
2880
2881 ret = btrfs_insert_dir_item(trans, root, "..", 2,
Chris Masonfabb5682007-06-07 22:13:21 -04002882 old_inode->i_ino, location,
2883 BTRFS_FT_DIR);
Chris Masone06afa82007-05-23 15:44:28 -04002884 if (ret)
2885 goto out_fail;
2886 }
2887
2888
Chris Masone06afa82007-05-23 15:44:28 -04002889 ret = btrfs_unlink_trans(trans, root, old_dir, old_dentry);
2890 if (ret)
2891 goto out_fail;
2892
2893 if (new_inode) {
2894 new_inode->i_ctime = CURRENT_TIME;
Chris Mason2b8d99a2007-05-24 08:34:10 -04002895 ret = btrfs_unlink_trans(trans, root, new_dir, new_dentry);
2896 if (ret)
2897 goto out_fail;
Chris Masone06afa82007-05-23 15:44:28 -04002898 if (S_ISDIR(new_inode->i_mode))
2899 clear_nlink(new_inode);
2900 else
2901 drop_nlink(new_inode);
2902 btrfs_update_inode(trans, root, new_inode);
2903 }
Chris Mason2b8d99a2007-05-24 08:34:10 -04002904 ret = btrfs_add_link(trans, new_dentry, old_inode);
2905 if (ret)
2906 goto out_fail;
2907
Chris Masone06afa82007-05-23 15:44:28 -04002908out_fail:
2909 btrfs_free_path(path);
2910 btrfs_end_transaction(trans, root);
2911 mutex_unlock(&root->fs_info->fs_mutex);
2912 return ret;
2913}
2914
Chris Mason2b8d99a2007-05-24 08:34:10 -04002915static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
2916 const char *symname)
2917{
2918 struct btrfs_trans_handle *trans;
2919 struct btrfs_root *root = BTRFS_I(dir)->root;
2920 struct btrfs_path *path;
2921 struct btrfs_key key;
2922 struct inode *inode;
2923 int err;
2924 int drop_inode = 0;
2925 u64 objectid;
2926 int name_len;
2927 int datasize;
2928 char *ptr;
2929 struct btrfs_file_extent_item *ei;
2930
2931 name_len = strlen(symname) + 1;
2932 if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
2933 return -ENAMETOOLONG;
2934 mutex_lock(&root->fs_info->fs_mutex);
2935 trans = btrfs_start_transaction(root, 1);
2936 btrfs_set_trans_block_group(trans, dir);
2937
2938 err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
2939 if (err) {
2940 err = -ENOSPC;
2941 goto out_unlock;
2942 }
2943
2944 inode = btrfs_new_inode(trans, root, objectid,
2945 BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO);
2946 err = PTR_ERR(inode);
2947 if (IS_ERR(inode))
2948 goto out_unlock;
2949
2950 btrfs_set_trans_block_group(trans, inode);
2951 err = btrfs_add_nondir(trans, dentry, inode);
2952 if (err)
2953 drop_inode = 1;
2954 else {
2955 inode->i_mapping->a_ops = &btrfs_aops;
2956 inode->i_fop = &btrfs_file_operations;
2957 inode->i_op = &btrfs_file_inode_operations;
2958 }
2959 dir->i_sb->s_dirt = 1;
2960 btrfs_update_inode_block_group(trans, inode);
2961 btrfs_update_inode_block_group(trans, dir);
2962 if (drop_inode)
2963 goto out_unlock;
2964
2965 path = btrfs_alloc_path();
2966 BUG_ON(!path);
2967 key.objectid = inode->i_ino;
2968 key.offset = 0;
2969 key.flags = 0;
2970 btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
2971 datasize = btrfs_file_extent_calc_inline_size(name_len);
2972 err = btrfs_insert_empty_item(trans, root, path, &key,
2973 datasize);
2974 BUG_ON(err);
2975 ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
2976 path->slots[0], struct btrfs_file_extent_item);
2977 btrfs_set_file_extent_generation(ei, trans->transid);
2978 btrfs_set_file_extent_type(ei,
2979 BTRFS_FILE_EXTENT_INLINE);
2980 ptr = btrfs_file_extent_inline_start(ei);
2981 btrfs_memcpy(root, path->nodes[0]->b_data,
2982 ptr, symname, name_len);
2983 mark_buffer_dirty(path->nodes[0]);
2984 btrfs_free_path(path);
2985 inode->i_op = &btrfs_symlink_inode_operations;
2986 inode->i_mapping->a_ops = &btrfs_symlink_aops;
2987 inode->i_size = name_len - 1;
2988 btrfs_update_inode(trans, root, inode);
2989 err = 0;
2990
2991out_unlock:
2992 btrfs_end_transaction(trans, root);
2993 mutex_unlock(&root->fs_info->fs_mutex);
2994
2995 if (drop_inode) {
2996 inode_dec_link_count(inode);
2997 iput(inode);
2998 }
2999 btrfs_btree_balance_dirty(root);
3000 return err;
3001}
3002
Chris Mason2e635a22007-03-21 11:12:56 -04003003static struct file_system_type btrfs_fs_type = {
3004 .owner = THIS_MODULE,
3005 .name = "btrfs",
3006 .get_sb = btrfs_get_sb,
3007 .kill_sb = kill_block_super,
3008 .fs_flags = FS_REQUIRES_DEV,
3009};
3010
Chris Masone20d96d2007-03-22 12:13:20 -04003011static struct super_operations btrfs_super_ops = {
Chris Mason134e9732007-03-25 13:44:56 -04003012 .delete_inode = btrfs_delete_inode,
Chris Masone20d96d2007-03-22 12:13:20 -04003013 .put_super = btrfs_put_super,
3014 .read_inode = btrfs_read_locked_inode,
Chris Masond5719762007-03-23 10:01:08 -04003015 .write_super = btrfs_write_super,
3016 .sync_fs = btrfs_sync_fs,
Chris Mason4730a4b2007-03-26 12:00:39 -04003017 .write_inode = btrfs_write_inode,
Chris Masonb5133862007-04-24 11:52:22 -04003018 .dirty_inode = btrfs_dirty_inode,
Chris Mason2c90e5d2007-04-02 10:50:19 -04003019 .alloc_inode = btrfs_alloc_inode,
3020 .destroy_inode = btrfs_destroy_inode,
Chris Mason8fd17792007-04-19 21:01:03 -04003021 .statfs = btrfs_statfs,
Chris Masone20d96d2007-03-22 12:13:20 -04003022};
3023
3024static struct inode_operations btrfs_dir_inode_operations = {
3025 .lookup = btrfs_lookup,
Chris Masond5719762007-03-23 10:01:08 -04003026 .create = btrfs_create,
Chris Mason134e9732007-03-25 13:44:56 -04003027 .unlink = btrfs_unlink,
Chris Mason2b8d99a2007-05-24 08:34:10 -04003028 .link = btrfs_link,
Chris Masonf7922032007-03-25 20:17:36 -04003029 .mkdir = btrfs_mkdir,
Chris Mason5f443fd2007-03-27 13:42:32 -04003030 .rmdir = btrfs_rmdir,
Chris Masone06afa82007-05-23 15:44:28 -04003031 .rename = btrfs_rename,
Chris Mason2b8d99a2007-05-24 08:34:10 -04003032 .symlink = btrfs_symlink,
Chris Mason3a686372007-05-24 13:35:57 -04003033 .setattr = btrfs_setattr,
Chris Masone20d96d2007-03-22 12:13:20 -04003034};
3035
Chris Masond6e4a422007-04-06 15:37:36 -04003036static struct inode_operations btrfs_dir_ro_inode_operations = {
3037 .lookup = btrfs_lookup,
3038};
3039
Chris Masone20d96d2007-03-22 12:13:20 -04003040static struct file_operations btrfs_dir_file_operations = {
3041 .llseek = generic_file_llseek,
3042 .read = generic_read_dir,
3043 .readdir = btrfs_readdir,
Chris Masonc5739bb2007-04-10 09:27:04 -04003044 .ioctl = btrfs_ioctl,
Chris Masone20d96d2007-03-22 12:13:20 -04003045};
3046
Chris Masondee26a92007-03-26 16:00:06 -04003047static struct address_space_operations btrfs_aops = {
3048 .readpage = btrfs_readpage,
Chris Masondee26a92007-03-26 16:00:06 -04003049 .writepage = btrfs_writepage,
3050 .sync_page = block_sync_page,
3051 .prepare_write = btrfs_prepare_write,
Chris Mason75dfe392007-03-29 11:56:46 -04003052 .commit_write = btrfs_commit_write,
Chris Masonfabb5682007-06-07 22:13:21 -04003053 .bmap = btrfs_bmap,
Chris Masondee26a92007-03-26 16:00:06 -04003054};
3055
Chris Mason2b8d99a2007-05-24 08:34:10 -04003056static struct address_space_operations btrfs_symlink_aops = {
3057 .readpage = btrfs_readpage,
3058 .writepage = btrfs_writepage,
3059};
3060
Chris Masondee26a92007-03-26 16:00:06 -04003061static struct inode_operations btrfs_file_inode_operations = {
Chris Masonf4b9aa82007-03-27 11:05:53 -04003062 .truncate = btrfs_truncate,
Chris Mason236454d2007-04-19 13:37:44 -04003063 .getattr = btrfs_getattr,
Chris Mason3a686372007-05-24 13:35:57 -04003064 .setattr = btrfs_setattr,
Chris Masondee26a92007-03-26 16:00:06 -04003065};
3066
3067static struct file_operations btrfs_file_operations = {
3068 .llseek = generic_file_llseek,
3069 .read = do_sync_read,
Chris Masone8f05c42007-04-04 14:30:09 -04003070 .aio_read = btrfs_file_aio_read,
3071 .write = btrfs_file_write,
Chris Masondee26a92007-03-26 16:00:06 -04003072 .mmap = generic_file_mmap,
3073 .open = generic_file_open,
Chris Masonc5739bb2007-04-10 09:27:04 -04003074 .ioctl = btrfs_ioctl,
Chris Mason8fd17792007-04-19 21:01:03 -04003075 .fsync = btrfs_sync_file,
Chris Masondee26a92007-03-26 16:00:06 -04003076};
Chris Masone20d96d2007-03-22 12:13:20 -04003077
Chris Mason2b8d99a2007-05-24 08:34:10 -04003078static struct inode_operations btrfs_symlink_inode_operations = {
3079 .readlink = generic_readlink,
3080 .follow_link = page_follow_link_light,
3081 .put_link = page_put_link,
3082};
3083
Chris Mason2e635a22007-03-21 11:12:56 -04003084static int __init init_btrfs_fs(void)
3085{
Chris Mason2c90e5d2007-04-02 10:50:19 -04003086 int err;
Chris Mason2e635a22007-03-21 11:12:56 -04003087 printk("btrfs loaded!\n");
Chris Mason2c90e5d2007-04-02 10:50:19 -04003088 err = init_inodecache();
3089 if (err)
3090 return err;
Chris Mason2e635a22007-03-21 11:12:56 -04003091 return register_filesystem(&btrfs_fs_type);
Chris Masond6e4a422007-04-06 15:37:36 -04003092 destroy_inodecache();
3093 return err;
Chris Mason2e635a22007-03-21 11:12:56 -04003094}
3095
3096static void __exit exit_btrfs_fs(void)
3097{
Chris Mason2c90e5d2007-04-02 10:50:19 -04003098 destroy_inodecache();
Chris Mason2e635a22007-03-21 11:12:56 -04003099 unregister_filesystem(&btrfs_fs_type);
Chris Mason2e635a22007-03-21 11:12:56 -04003100 printk("btrfs unloaded\n");
3101}
3102
3103module_init(init_btrfs_fs)
3104module_exit(exit_btrfs_fs)
3105
3106MODULE_LICENSE("GPL");