diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-22 12:13:20 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-22 12:13:20 -0400 |
commit | e20d96d64f9cf9288ffecc9ad4714e91c3b97ca8 (patch) | |
tree | fbe07d48bc7997226075169118ffa2a2e63f5d51 /fs/btrfs/super.c | |
parent | 2e635a278354a1a7951e16cfea4c247d6d0e7c99 (diff) |
Mountable btrfs, with readdir
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 261 |
1 files changed, 241 insertions, 20 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 4ae76044aeab..ccc056aad692 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/buffer_head.h> | ||
2 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
3 | #include <linux/pagemap.h> | 4 | #include <linux/pagemap.h> |
4 | #include <linux/highmem.h> | 5 | #include <linux/highmem.h> |
@@ -8,13 +9,18 @@ | |||
8 | #include <linux/smp_lock.h> | 9 | #include <linux/smp_lock.h> |
9 | #include <linux/backing-dev.h> | 10 | #include <linux/backing-dev.h> |
10 | #include "ctree.h" | 11 | #include "ctree.h" |
12 | #include "disk-io.h" | ||
11 | 13 | ||
12 | #define BTRFS_SUPER_MAGIC 0x9123682E | 14 | #define BTRFS_SUPER_MAGIC 0x9123682E |
15 | |||
16 | static struct inode_operations btrfs_dir_inode_operations; | ||
17 | static struct super_operations btrfs_super_ops; | ||
18 | static struct file_operations btrfs_dir_file_operations; | ||
19 | |||
13 | #if 0 | 20 | #if 0 |
14 | /* some random number */ | 21 | /* some random number */ |
15 | 22 | ||
16 | static struct super_operations ramfs_ops; | 23 | static struct super_operations ramfs_ops; |
17 | static struct inode_operations ramfs_dir_inode_operations; | ||
18 | 24 | ||
19 | static struct backing_dev_info ramfs_backing_dev_info = { | 25 | static struct backing_dev_info ramfs_backing_dev_info = { |
20 | .ra_pages = 0, /* No readahead */ | 26 | .ra_pages = 0, /* No readahead */ |
@@ -129,46 +135,243 @@ static struct inode_operations ramfs_dir_inode_operations = { | |||
129 | }; | 135 | }; |
130 | #endif | 136 | #endif |
131 | 137 | ||
132 | struct inode *btrfs_get_inode(struct super_block *sb, int mode, dev_t dev) | 138 | static void btrfs_read_locked_inode(struct inode *inode) |
133 | { | 139 | { |
134 | struct inode * inode = new_inode(sb); | 140 | struct btrfs_path path; |
141 | struct btrfs_inode_item *inode_item; | ||
142 | struct btrfs_root *root = btrfs_sb(inode->i_sb); | ||
143 | int ret; | ||
144 | printk("read locked inode %lu\n", inode->i_ino); | ||
145 | btrfs_init_path(&path); | ||
146 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); | ||
147 | if (ret) { | ||
148 | make_bad_inode(inode); | ||
149 | return; | ||
150 | } | ||
151 | inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), | ||
152 | path.slots[0], | ||
153 | struct btrfs_inode_item); | ||
135 | 154 | ||
136 | if (inode) { | 155 | printk("found locked inode %lu\n", inode->i_ino); |
137 | inode->i_mode = mode; | 156 | inode->i_mode = btrfs_inode_mode(inode_item); |
138 | inode->i_uid = current->fsuid; | 157 | inode->i_nlink = btrfs_inode_nlink(inode_item); |
139 | inode->i_gid = current->fsgid; | 158 | inode->i_uid = btrfs_inode_uid(inode_item); |
140 | inode->i_blocks = 0; | 159 | inode->i_gid = btrfs_inode_gid(inode_item); |
141 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 160 | inode->i_size = btrfs_inode_size(inode_item); |
161 | inode->i_atime.tv_sec = btrfs_timespec_sec(&inode_item->atime); | ||
162 | inode->i_atime.tv_nsec = btrfs_timespec_nsec(&inode_item->atime); | ||
163 | inode->i_mtime.tv_sec = btrfs_timespec_sec(&inode_item->mtime); | ||
164 | inode->i_mtime.tv_nsec = btrfs_timespec_nsec(&inode_item->mtime); | ||
165 | inode->i_ctime.tv_sec = btrfs_timespec_sec(&inode_item->ctime); | ||
166 | inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime); | ||
167 | inode->i_blocks = btrfs_inode_nblocks(inode_item); | ||
168 | inode->i_generation = btrfs_inode_generation(inode_item); | ||
169 | printk("about to release\n"); | ||
170 | btrfs_release_path(root, &path); | ||
171 | switch (inode->i_mode & S_IFMT) { | ||
172 | #if 0 | ||
173 | default: | ||
174 | init_special_inode(inode, inode->i_mode, | ||
175 | btrfs_inode_rdev(inode_item)); | ||
176 | break; | ||
177 | #endif | ||
178 | case S_IFREG: | ||
179 | printk("inode %lu now a file\n", inode->i_ino); | ||
180 | break; | ||
181 | case S_IFDIR: | ||
182 | printk("inode %lu now a directory\n", inode->i_ino); | ||
183 | inode->i_op = &btrfs_dir_inode_operations; | ||
184 | inode->i_fop = &btrfs_dir_file_operations; | ||
185 | break; | ||
186 | case S_IFLNK: | ||
187 | printk("inode %lu now a link\n", inode->i_ino); | ||
188 | // inode->i_op = &page_symlink_inode_operations; | ||
189 | break; | ||
142 | } | 190 | } |
143 | return inode; | 191 | printk("returning!\n"); |
192 | return; | ||
144 | } | 193 | } |
145 | 194 | ||
146 | static struct super_operations btrfs_ops = { | 195 | static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, |
147 | .statfs = simple_statfs, | 196 | ino_t *ino) |
148 | .drop_inode = generic_delete_inode, | 197 | { |
149 | }; | 198 | const char *name = dentry->d_name.name; |
199 | int namelen = dentry->d_name.len; | ||
200 | struct btrfs_dir_item *di; | ||
201 | struct btrfs_path path; | ||
202 | struct btrfs_root *root = btrfs_sb(dir->i_sb); | ||
203 | int ret; | ||
204 | |||
205 | btrfs_init_path(&path); | ||
206 | ret = btrfs_lookup_dir_item(NULL, root, &path, dir->i_ino, name, | ||
207 | namelen, 0); | ||
208 | if (ret) { | ||
209 | *ino = 0; | ||
210 | goto out; | ||
211 | } | ||
212 | di = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0], | ||
213 | struct btrfs_dir_item); | ||
214 | *ino = btrfs_dir_objectid(di); | ||
215 | out: | ||
216 | btrfs_release_path(root, &path); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | ||
221 | struct nameidata *nd) | ||
222 | { | ||
223 | struct inode * inode; | ||
224 | ino_t ino; | ||
225 | int ret; | ||
226 | |||
227 | if (dentry->d_name.len > BTRFS_NAME_LEN) | ||
228 | return ERR_PTR(-ENAMETOOLONG); | ||
229 | |||
230 | ret = btrfs_inode_by_name(dir, dentry, &ino); | ||
231 | if (ret < 0) | ||
232 | return ERR_PTR(ret); | ||
233 | inode = NULL; | ||
234 | if (ino) { | ||
235 | printk("lookup on %.*s returns %lu\n", dentry->d_name.len, dentry->d_name.name, ino); | ||
236 | inode = iget(dir->i_sb, ino); | ||
237 | if (!inode) | ||
238 | return ERR_PTR(-EACCES); | ||
239 | } | ||
240 | return d_splice_alias(inode, dentry); | ||
241 | } | ||
242 | |||
243 | static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
244 | { | ||
245 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
246 | struct btrfs_root *root = btrfs_sb(inode->i_sb); | ||
247 | struct btrfs_item *item; | ||
248 | struct btrfs_dir_item *di; | ||
249 | struct btrfs_key key; | ||
250 | struct btrfs_path path; | ||
251 | int ret; | ||
252 | u32 nritems; | ||
253 | struct btrfs_leaf *leaf; | ||
254 | int slot; | ||
255 | int advance; | ||
256 | unsigned char d_type = DT_UNKNOWN; | ||
257 | int over; | ||
258 | |||
259 | key.objectid = inode->i_ino; | ||
260 | printk("readdir on dir %Lu pos %Lu\n", key.objectid, filp->f_pos); | ||
261 | key.flags = 0; | ||
262 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | ||
263 | key.offset = filp->f_pos; | ||
264 | btrfs_init_path(&path); | ||
265 | ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); | ||
266 | if (ret < 0) { | ||
267 | goto err; | ||
268 | } | ||
269 | printk("first ret %d\n", ret); | ||
270 | advance = filp->f_pos > 0 && ret != 0; | ||
271 | while(1) { | ||
272 | leaf = btrfs_buffer_leaf(path.nodes[0]); | ||
273 | nritems = btrfs_header_nritems(&leaf->header); | ||
274 | slot = path.slots[0]; | ||
275 | printk("leaf %Lu nritems %lu slot %d\n", path.nodes[0]->b_blocknr, nritems, slot); | ||
276 | if (advance) { | ||
277 | printk("advancing!\n"); | ||
278 | if (slot == nritems -1) { | ||
279 | ret = btrfs_next_leaf(root, &path); | ||
280 | if (ret) | ||
281 | break; | ||
282 | leaf = btrfs_buffer_leaf(path.nodes[0]); | ||
283 | nritems = btrfs_header_nritems(&leaf->header); | ||
284 | slot = path.slots[0]; | ||
285 | printk("2leaf %Lu nritems %lu slot %d\n", path.nodes[0]->b_blocknr, nritems, slot); | ||
286 | } else { | ||
287 | slot++; | ||
288 | path.slots[0]++; | ||
289 | } | ||
290 | } | ||
291 | advance = 1; | ||
292 | item = leaf->items + slot; | ||
293 | printk("item key %Lu %u %Lu\n", btrfs_disk_key_objectid(&item->key), | ||
294 | btrfs_disk_key_flags(&item->key), btrfs_disk_key_offset(&item->key)); | ||
295 | if (btrfs_disk_key_objectid(&item->key) != key.objectid) | ||
296 | break; | ||
297 | if (btrfs_disk_key_type(&item->key) != BTRFS_DIR_ITEM_KEY) | ||
298 | continue; | ||
299 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); | ||
300 | printk("filldir name %.*s, objectid %Lu\n", btrfs_dir_name_len(di), | ||
301 | (const char *)(di + 1), btrfs_dir_objectid(di)); | ||
302 | over = filldir(dirent, (const char *)(di + 1), | ||
303 | btrfs_dir_name_len(di), | ||
304 | btrfs_disk_key_offset(&item->key), | ||
305 | btrfs_dir_objectid(di), d_type); | ||
306 | if (over) | ||
307 | break; | ||
308 | filp->f_pos = btrfs_disk_key_offset(&item->key) + 1; | ||
309 | } | ||
310 | printk("filldir all done\n"); | ||
311 | ret = 0; | ||
312 | err: | ||
313 | btrfs_release_path(root, &path); | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | static void btrfs_put_super (struct super_block * sb) | ||
318 | { | ||
319 | struct btrfs_root *root = btrfs_sb(sb); | ||
320 | int ret; | ||
321 | |||
322 | ret = close_ctree(root); | ||
323 | if (ret) { | ||
324 | printk("close ctree returns %d\n", ret); | ||
325 | } | ||
326 | sb->s_fs_info = NULL; | ||
327 | } | ||
150 | 328 | ||
151 | static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | 329 | static int btrfs_fill_super(struct super_block * sb, void * data, int silent) |
152 | { | 330 | { |
153 | struct inode * inode; | 331 | struct inode * inode; |
154 | struct dentry * root; | 332 | struct dentry * root_dentry; |
333 | struct btrfs_super_block *disk_super; | ||
334 | struct buffer_head *bh; | ||
335 | struct btrfs_root *root; | ||
155 | 336 | ||
156 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 337 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
157 | sb->s_blocksize = PAGE_CACHE_SIZE; | 338 | sb->s_blocksize = PAGE_CACHE_SIZE; |
158 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 339 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
159 | sb->s_magic = BTRFS_SUPER_MAGIC; | 340 | sb->s_magic = BTRFS_SUPER_MAGIC; |
160 | sb->s_op = &btrfs_ops; | 341 | sb->s_op = &btrfs_super_ops; |
161 | sb->s_time_gran = 1; | 342 | sb->s_time_gran = 1; |
162 | inode = btrfs_get_inode(sb, S_IFDIR | 0755, 0); | 343 | |
344 | bh = sb_bread(sb, BTRFS_SUPER_INFO_OFFSET / sb->s_blocksize); | ||
345 | if (!bh) { | ||
346 | printk("btrfs: unable to read on disk super\n"); | ||
347 | return -EIO; | ||
348 | } | ||
349 | disk_super = (struct btrfs_super_block *)bh->b_data; | ||
350 | root = open_ctree(sb, bh, disk_super); | ||
351 | sb->s_fs_info = root; | ||
352 | if (!root) { | ||
353 | printk("btrfs: open_ctree failed\n"); | ||
354 | return -EIO; | ||
355 | } | ||
356 | printk("read in super total blocks %Lu root %Lu\n", | ||
357 | btrfs_super_total_blocks(disk_super), | ||
358 | btrfs_super_root_dir(disk_super)); | ||
359 | |||
360 | inode = iget_locked(sb, btrfs_super_root_dir(disk_super)); | ||
163 | if (!inode) | 361 | if (!inode) |
164 | return -ENOMEM; | 362 | return -ENOMEM; |
363 | if (inode->i_state & I_NEW) { | ||
364 | btrfs_read_locked_inode(inode); | ||
365 | unlock_new_inode(inode); | ||
366 | } | ||
165 | 367 | ||
166 | root = d_alloc_root(inode); | 368 | root_dentry = d_alloc_root(inode); |
167 | if (!root) { | 369 | if (!root_dentry) { |
168 | iput(inode); | 370 | iput(inode); |
169 | return -ENOMEM; | 371 | return -ENOMEM; |
170 | } | 372 | } |
171 | sb->s_root = root; | 373 | sb->s_root = root_dentry; |
374 | |||
172 | return 0; | 375 | return 0; |
173 | } | 376 | } |
174 | 377 | ||
@@ -187,6 +390,24 @@ static struct file_system_type btrfs_fs_type = { | |||
187 | .fs_flags = FS_REQUIRES_DEV, | 390 | .fs_flags = FS_REQUIRES_DEV, |
188 | }; | 391 | }; |
189 | 392 | ||
393 | static struct super_operations btrfs_super_ops = { | ||
394 | .statfs = simple_statfs, | ||
395 | .drop_inode = generic_delete_inode, | ||
396 | .put_super = btrfs_put_super, | ||
397 | .read_inode = btrfs_read_locked_inode, | ||
398 | }; | ||
399 | |||
400 | static struct inode_operations btrfs_dir_inode_operations = { | ||
401 | .lookup = btrfs_lookup, | ||
402 | }; | ||
403 | |||
404 | static struct file_operations btrfs_dir_file_operations = { | ||
405 | .llseek = generic_file_llseek, | ||
406 | .read = generic_read_dir, | ||
407 | .readdir = btrfs_readdir, | ||
408 | }; | ||
409 | |||
410 | |||
190 | static int __init init_btrfs_fs(void) | 411 | static int __init init_btrfs_fs(void) |
191 | { | 412 | { |
192 | printk("btrfs loaded!\n"); | 413 | printk("btrfs loaded!\n"); |