Commit 8e656fd518784b49453f60c5f78b78703bc85cb2
1 parent
4d8d9293dc
Exists in
master
and in
4 other branches
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>
Showing 5 changed files with 151 additions and 71 deletions Side-by-side Diff
fs/nilfs2/export.h
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 |
fs/nilfs2/namei.c
... | ... | @@ -40,7 +40,11 @@ |
40 | 40 | |
41 | 41 | #include <linux/pagemap.h> |
42 | 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 | 49 | static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) |
46 | 50 | { |
... | ... | @@ -77,23 +81,6 @@ |
77 | 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 | 85 | * By the time this is called, we already have created |
99 | 86 | * the directory cache entry for the new file, but it |
... | ... | @@ -469,6 +456,115 @@ |
469 | 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 | 568 | const struct inode_operations nilfs_dir_inode_operations = { |
473 | 569 | .create = nilfs_create, |
474 | 570 | .lookup = nilfs_lookup, |
... | ... | @@ -492,5 +588,12 @@ |
492 | 588 | .readlink = generic_readlink, |
493 | 589 | .follow_link = page_follow_link_light, |
494 | 590 | .put_link = page_put_link, |
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, | |
495 | 598 | }; |
fs/nilfs2/nilfs.h
... | ... | @@ -264,9 +264,6 @@ |
264 | 264 | extern int nilfs_mark_inode_dirty(struct inode *); |
265 | 265 | extern void nilfs_dirty_inode(struct inode *); |
266 | 266 | |
267 | -/* namei.c */ | |
268 | -extern struct dentry *nilfs_get_parent(struct dentry *); | |
269 | - | |
270 | 267 | /* super.c */ |
271 | 268 | extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); |
272 | 269 | extern struct inode *nilfs_alloc_inode(struct super_block *); |
fs/nilfs2/super.c
... | ... | @@ -48,10 +48,10 @@ |
48 | 48 | #include <linux/vfs.h> |
49 | 49 | #include <linux/writeback.h> |
50 | 50 | #include <linux/kobject.h> |
51 | -#include <linux/exportfs.h> | |
52 | 51 | #include <linux/seq_file.h> |
53 | 52 | #include <linux/mount.h> |
54 | 53 | #include "nilfs.h" |
54 | +#include "export.h" | |
55 | 55 | #include "mdt.h" |
56 | 56 | #include "alloc.h" |
57 | 57 | #include "btree.h" |
... | ... | @@ -554,56 +554,6 @@ |
554 | 554 | .remount_fs = nilfs_remount, |
555 | 555 | /* .umount_begin */ |
556 | 556 | .show_options = nilfs_show_options |
557 | -}; | |
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 | 557 | }; |
608 | 558 | |
609 | 559 | enum { |
include/linux/exportfs.h
... | ... | @@ -67,6 +67,19 @@ |
67 | 67 | * 32 bit parent block number, 32 bit parent generation number |
68 | 68 | */ |
69 | 69 | FILEID_UDF_WITH_PARENT = 0x52, |
70 | + | |
71 | + /* | |
72 | + * 64 bit checkpoint number, 64 bit inode number, | |
73 | + * 32 bit generation number. | |
74 | + */ | |
75 | + FILEID_NILFS_WITHOUT_PARENT = 0x61, | |
76 | + | |
77 | + /* | |
78 | + * 64 bit checkpoint number, 64 bit inode number, | |
79 | + * 32 bit generation number, 32 bit parent generation. | |
80 | + * 64 bit parent inode number. | |
81 | + */ | |
82 | + FILEID_NILFS_WITH_PARENT = 0x62, | |
70 | 83 | }; |
71 | 84 | |
72 | 85 | struct fid { |