diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-08-26 11:23:02 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-10-22 20:24:34 -0400 |
commit | 8e656fd518784b49453f60c5f78b78703bc85cb2 (patch) | |
tree | 7adf4b71aba4bdf31dc05489a06933c48a0ea6f2 /fs/nilfs2 | |
parent | 4d8d9293dce503eb0e083e17a02a328d397e7f00 (diff) |
nilfs2: make snapshots in checkpoint tree exportable
The previous export operations cannot handle multiple versions of
a filesystem if they belong to the same sb instance.
This adds a new type of file handle and extends export operations so
that they can get the inode specified by a checkpoint number as well
as an inode number and a generation number.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2')
-rw-r--r-- | fs/nilfs2/export.h | 17 | ||||
-rw-r--r-- | fs/nilfs2/namei.c | 137 | ||||
-rw-r--r-- | fs/nilfs2/nilfs.h | 3 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 52 |
4 files changed, 138 insertions, 71 deletions
diff --git a/fs/nilfs2/export.h b/fs/nilfs2/export.h new file mode 100644 index 000000000000..a71cc412b651 --- /dev/null +++ b/fs/nilfs2/export.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef NILFS_EXPORT_H | ||
2 | #define NILFS_EXPORT_H | ||
3 | |||
4 | #include <linux/exportfs.h> | ||
5 | |||
6 | extern const struct export_operations nilfs_export_ops; | ||
7 | |||
8 | struct nilfs_fid { | ||
9 | u64 cno; | ||
10 | u64 ino; | ||
11 | u32 gen; | ||
12 | |||
13 | u32 parent_gen; | ||
14 | u64 parent_ino; | ||
15 | } __attribute__ ((packed)); | ||
16 | |||
17 | #endif | ||
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 1110d56a23f5..a65f46560fbe 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c | |||
@@ -40,7 +40,11 @@ | |||
40 | 40 | ||
41 | #include <linux/pagemap.h> | 41 | #include <linux/pagemap.h> |
42 | #include "nilfs.h" | 42 | #include "nilfs.h" |
43 | #include "export.h" | ||
43 | 44 | ||
45 | #define NILFS_FID_SIZE_NON_CONNECTABLE \ | ||
46 | (offsetof(struct nilfs_fid, parent_gen) / 4) | ||
47 | #define NILFS_FID_SIZE_CONNECTABLE (sizeof(struct nilfs_fid) / 4) | ||
44 | 48 | ||
45 | static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) | 49 | static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) |
46 | { | 50 | { |
@@ -77,23 +81,6 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
77 | return d_splice_alias(inode, dentry); | 81 | return d_splice_alias(inode, dentry); |
78 | } | 82 | } |
79 | 83 | ||
80 | struct dentry *nilfs_get_parent(struct dentry *child) | ||
81 | { | ||
82 | unsigned long ino; | ||
83 | struct inode *inode; | ||
84 | struct qstr dotdot = {.name = "..", .len = 2}; | ||
85 | |||
86 | ino = nilfs_inode_by_name(child->d_inode, &dotdot); | ||
87 | if (!ino) | ||
88 | return ERR_PTR(-ENOENT); | ||
89 | |||
90 | inode = nilfs_iget(child->d_inode->i_sb, | ||
91 | NILFS_I(child->d_inode)->i_root, ino); | ||
92 | if (IS_ERR(inode)) | ||
93 | return ERR_CAST(inode); | ||
94 | return d_obtain_alias(inode); | ||
95 | } | ||
96 | |||
97 | /* | 84 | /* |
98 | * By the time this is called, we already have created | 85 | * By the time this is called, we already have created |
99 | * the directory cache entry for the new file, but it | 86 | * the directory cache entry for the new file, but it |
@@ -469,6 +456,115 @@ out: | |||
469 | return err; | 456 | return err; |
470 | } | 457 | } |
471 | 458 | ||
459 | /* | ||
460 | * Export operations | ||
461 | */ | ||
462 | static struct dentry *nilfs_get_parent(struct dentry *child) | ||
463 | { | ||
464 | unsigned long ino; | ||
465 | struct inode *inode; | ||
466 | struct qstr dotdot = {.name = "..", .len = 2}; | ||
467 | struct nilfs_root *root; | ||
468 | |||
469 | ino = nilfs_inode_by_name(child->d_inode, &dotdot); | ||
470 | if (!ino) | ||
471 | return ERR_PTR(-ENOENT); | ||
472 | |||
473 | root = NILFS_I(child->d_inode)->i_root; | ||
474 | |||
475 | inode = nilfs_iget(child->d_inode->i_sb, root, ino); | ||
476 | if (IS_ERR(inode)) | ||
477 | return ERR_CAST(inode); | ||
478 | |||
479 | return d_obtain_alias(inode); | ||
480 | } | ||
481 | |||
482 | static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno, | ||
483 | u64 ino, u32 gen) | ||
484 | { | ||
485 | struct nilfs_root *root; | ||
486 | struct inode *inode; | ||
487 | |||
488 | if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO) | ||
489 | return ERR_PTR(-ESTALE); | ||
490 | |||
491 | root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno); | ||
492 | if (!root) | ||
493 | return ERR_PTR(-ESTALE); | ||
494 | |||
495 | inode = nilfs_iget(sb, root, ino); | ||
496 | nilfs_put_root(root); | ||
497 | |||
498 | if (IS_ERR(inode)) | ||
499 | return ERR_CAST(inode); | ||
500 | if (gen && inode->i_generation != gen) { | ||
501 | iput(inode); | ||
502 | return ERR_PTR(-ESTALE); | ||
503 | } | ||
504 | return d_obtain_alias(inode); | ||
505 | } | ||
506 | |||
507 | static struct dentry *nilfs_fh_to_dentry(struct super_block *sb, struct fid *fh, | ||
508 | int fh_len, int fh_type) | ||
509 | { | ||
510 | struct nilfs_fid *fid = (struct nilfs_fid *)fh; | ||
511 | |||
512 | if ((fh_len != NILFS_FID_SIZE_NON_CONNECTABLE && | ||
513 | fh_len != NILFS_FID_SIZE_CONNECTABLE) || | ||
514 | (fh_type != FILEID_NILFS_WITH_PARENT && | ||
515 | fh_type != FILEID_NILFS_WITHOUT_PARENT)) | ||
516 | return NULL; | ||
517 | |||
518 | return nilfs_get_dentry(sb, fid->cno, fid->ino, fid->gen); | ||
519 | } | ||
520 | |||
521 | static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh, | ||
522 | int fh_len, int fh_type) | ||
523 | { | ||
524 | struct nilfs_fid *fid = (struct nilfs_fid *)fh; | ||
525 | |||
526 | if (fh_len != NILFS_FID_SIZE_CONNECTABLE || | ||
527 | fh_type != FILEID_NILFS_WITH_PARENT) | ||
528 | return NULL; | ||
529 | |||
530 | return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen); | ||
531 | } | ||
532 | |||
533 | static int nilfs_encode_fh(struct dentry *dentry, __u32 *fh, int *lenp, | ||
534 | int connectable) | ||
535 | { | ||
536 | struct nilfs_fid *fid = (struct nilfs_fid *)fh; | ||
537 | struct inode *inode = dentry->d_inode; | ||
538 | struct nilfs_root *root = NILFS_I(inode)->i_root; | ||
539 | int type; | ||
540 | |||
541 | if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE || | ||
542 | (connectable && *lenp < NILFS_FID_SIZE_CONNECTABLE)) | ||
543 | return 255; | ||
544 | |||
545 | fid->cno = root->cno; | ||
546 | fid->ino = inode->i_ino; | ||
547 | fid->gen = inode->i_generation; | ||
548 | |||
549 | if (connectable && !S_ISDIR(inode->i_mode)) { | ||
550 | struct inode *parent; | ||
551 | |||
552 | spin_lock(&dentry->d_lock); | ||
553 | parent = dentry->d_parent->d_inode; | ||
554 | fid->parent_ino = parent->i_ino; | ||
555 | fid->parent_gen = parent->i_generation; | ||
556 | spin_unlock(&dentry->d_lock); | ||
557 | |||
558 | type = FILEID_NILFS_WITH_PARENT; | ||
559 | *lenp = NILFS_FID_SIZE_CONNECTABLE; | ||
560 | } else { | ||
561 | type = FILEID_NILFS_WITHOUT_PARENT; | ||
562 | *lenp = NILFS_FID_SIZE_NON_CONNECTABLE; | ||
563 | } | ||
564 | |||
565 | return type; | ||
566 | } | ||
567 | |||
472 | const struct inode_operations nilfs_dir_inode_operations = { | 568 | const struct inode_operations nilfs_dir_inode_operations = { |
473 | .create = nilfs_create, | 569 | .create = nilfs_create, |
474 | .lookup = nilfs_lookup, | 570 | .lookup = nilfs_lookup, |
@@ -493,3 +589,10 @@ const struct inode_operations nilfs_symlink_inode_operations = { | |||
493 | .follow_link = page_follow_link_light, | 589 | .follow_link = page_follow_link_light, |
494 | .put_link = page_put_link, | 590 | .put_link = page_put_link, |
495 | }; | 591 | }; |
592 | |||
593 | const struct export_operations nilfs_export_ops = { | ||
594 | .encode_fh = nilfs_encode_fh, | ||
595 | .fh_to_dentry = nilfs_fh_to_dentry, | ||
596 | .fh_to_parent = nilfs_fh_to_parent, | ||
597 | .get_parent = nilfs_get_parent, | ||
598 | }; | ||
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 21d90c4b4e2d..aa7940f7ecf1 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -264,9 +264,6 @@ extern int nilfs_set_file_dirty(struct nilfs_sb_info *, struct inode *, | |||
264 | extern int nilfs_mark_inode_dirty(struct inode *); | 264 | extern int nilfs_mark_inode_dirty(struct inode *); |
265 | extern void nilfs_dirty_inode(struct inode *); | 265 | extern void nilfs_dirty_inode(struct inode *); |
266 | 266 | ||
267 | /* namei.c */ | ||
268 | extern struct dentry *nilfs_get_parent(struct dentry *); | ||
269 | |||
270 | /* super.c */ | 267 | /* super.c */ |
271 | extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); | 268 | extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); |
272 | extern struct inode *nilfs_alloc_inode(struct super_block *); | 269 | extern struct inode *nilfs_alloc_inode(struct super_block *); |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index a1c0e38a7706..adbf5826b837 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -48,10 +48,10 @@ | |||
48 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
49 | #include <linux/writeback.h> | 49 | #include <linux/writeback.h> |
50 | #include <linux/kobject.h> | 50 | #include <linux/kobject.h> |
51 | #include <linux/exportfs.h> | ||
52 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
53 | #include <linux/mount.h> | 52 | #include <linux/mount.h> |
54 | #include "nilfs.h" | 53 | #include "nilfs.h" |
54 | #include "export.h" | ||
55 | #include "mdt.h" | 55 | #include "mdt.h" |
56 | #include "alloc.h" | 56 | #include "alloc.h" |
57 | #include "btree.h" | 57 | #include "btree.h" |
@@ -556,56 +556,6 @@ static const struct super_operations nilfs_sops = { | |||
556 | .show_options = nilfs_show_options | 556 | .show_options = nilfs_show_options |
557 | }; | 557 | }; |
558 | 558 | ||
559 | static struct inode * | ||
560 | nilfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) | ||
561 | { | ||
562 | struct inode *inode; | ||
563 | struct nilfs_root *root; | ||
564 | |||
565 | if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO && | ||
566 | ino != NILFS_SKETCH_INO) | ||
567 | return ERR_PTR(-ESTALE); | ||
568 | |||
569 | root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, | ||
570 | NILFS_CPTREE_CURRENT_CNO); | ||
571 | if (!root) | ||
572 | return ERR_PTR(-ESTALE); | ||
573 | |||
574 | /* new file handle type is required to export snapshots */ | ||
575 | inode = nilfs_iget(sb, root, ino); | ||
576 | nilfs_put_root(root); | ||
577 | if (IS_ERR(inode)) | ||
578 | return ERR_CAST(inode); | ||
579 | if (generation && inode->i_generation != generation) { | ||
580 | iput(inode); | ||
581 | return ERR_PTR(-ESTALE); | ||
582 | } | ||
583 | |||
584 | return inode; | ||
585 | } | ||
586 | |||
587 | static struct dentry * | ||
588 | nilfs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, | ||
589 | int fh_type) | ||
590 | { | ||
591 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | ||
592 | nilfs_nfs_get_inode); | ||
593 | } | ||
594 | |||
595 | static struct dentry * | ||
596 | nilfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, | ||
597 | int fh_type) | ||
598 | { | ||
599 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, | ||
600 | nilfs_nfs_get_inode); | ||
601 | } | ||
602 | |||
603 | static const struct export_operations nilfs_export_ops = { | ||
604 | .fh_to_dentry = nilfs_fh_to_dentry, | ||
605 | .fh_to_parent = nilfs_fh_to_parent, | ||
606 | .get_parent = nilfs_get_parent, | ||
607 | }; | ||
608 | |||
609 | enum { | 559 | enum { |
610 | Opt_err_cont, Opt_err_panic, Opt_err_ro, | 560 | Opt_err_cont, Opt_err_panic, Opt_err_ro, |
611 | Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, | 561 | Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, |