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 | |
| 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>
| -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 | ||||
| -rw-r--r-- | include/linux/exportfs.h | 13 |
5 files changed, 151 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 *); | ||
