Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+151 -71
+17
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
+120 -17
fs/nilfs2/namei.c
··· 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 { ··· 79 75 return ERR_CAST(inode); 80 76 } 81 77 return d_splice_alias(inode, dentry); 82 - } 83 - 84 - struct dentry *nilfs_get_parent(struct dentry *child) 85 - { 86 - unsigned long ino; 87 - struct inode *inode; 88 - struct qstr dotdot = {.name = "..", .len = 2}; 89 - 90 - ino = nilfs_inode_by_name(child->d_inode, &dotdot); 91 - if (!ino) 92 - return ERR_PTR(-ENOENT); 93 - 94 - inode = nilfs_iget(child->d_inode->i_sb, 95 - NILFS_I(child->d_inode)->i_root, ino); 96 - if (IS_ERR(inode)) 97 - return ERR_CAST(inode); 98 - return d_obtain_alias(inode); 99 78 } 100 79 101 80 /* ··· 456 469 return err; 457 470 } 458 471 472 + /* 473 + * Export operations 474 + */ 475 + static struct dentry *nilfs_get_parent(struct dentry *child) 476 + { 477 + unsigned long ino; 478 + struct inode *inode; 479 + struct qstr dotdot = {.name = "..", .len = 2}; 480 + struct nilfs_root *root; 481 + 482 + ino = nilfs_inode_by_name(child->d_inode, &dotdot); 483 + if (!ino) 484 + return ERR_PTR(-ENOENT); 485 + 486 + root = NILFS_I(child->d_inode)->i_root; 487 + 488 + inode = nilfs_iget(child->d_inode->i_sb, root, ino); 489 + if (IS_ERR(inode)) 490 + return ERR_CAST(inode); 491 + 492 + return d_obtain_alias(inode); 493 + } 494 + 495 + static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno, 496 + u64 ino, u32 gen) 497 + { 498 + struct nilfs_root *root; 499 + struct inode *inode; 500 + 501 + if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO) 502 + return ERR_PTR(-ESTALE); 503 + 504 + root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno); 505 + if (!root) 506 + return ERR_PTR(-ESTALE); 507 + 508 + inode = nilfs_iget(sb, root, ino); 509 + nilfs_put_root(root); 510 + 511 + if (IS_ERR(inode)) 512 + return ERR_CAST(inode); 513 + if (gen && inode->i_generation != gen) { 514 + iput(inode); 515 + return ERR_PTR(-ESTALE); 516 + } 517 + return d_obtain_alias(inode); 518 + } 519 + 520 + static struct dentry *nilfs_fh_to_dentry(struct super_block *sb, struct fid *fh, 521 + int fh_len, int fh_type) 522 + { 523 + struct nilfs_fid *fid = (struct nilfs_fid *)fh; 524 + 525 + if ((fh_len != NILFS_FID_SIZE_NON_CONNECTABLE && 526 + fh_len != NILFS_FID_SIZE_CONNECTABLE) || 527 + (fh_type != FILEID_NILFS_WITH_PARENT && 528 + fh_type != FILEID_NILFS_WITHOUT_PARENT)) 529 + return NULL; 530 + 531 + return nilfs_get_dentry(sb, fid->cno, fid->ino, fid->gen); 532 + } 533 + 534 + static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh, 535 + int fh_len, int fh_type) 536 + { 537 + struct nilfs_fid *fid = (struct nilfs_fid *)fh; 538 + 539 + if (fh_len != NILFS_FID_SIZE_CONNECTABLE || 540 + fh_type != FILEID_NILFS_WITH_PARENT) 541 + return NULL; 542 + 543 + return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen); 544 + } 545 + 546 + static int nilfs_encode_fh(struct dentry *dentry, __u32 *fh, int *lenp, 547 + int connectable) 548 + { 549 + struct nilfs_fid *fid = (struct nilfs_fid *)fh; 550 + struct inode *inode = dentry->d_inode; 551 + struct nilfs_root *root = NILFS_I(inode)->i_root; 552 + int type; 553 + 554 + if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE || 555 + (connectable && *lenp < NILFS_FID_SIZE_CONNECTABLE)) 556 + return 255; 557 + 558 + fid->cno = root->cno; 559 + fid->ino = inode->i_ino; 560 + fid->gen = inode->i_generation; 561 + 562 + if (connectable && !S_ISDIR(inode->i_mode)) { 563 + struct inode *parent; 564 + 565 + spin_lock(&dentry->d_lock); 566 + parent = dentry->d_parent->d_inode; 567 + fid->parent_ino = parent->i_ino; 568 + fid->parent_gen = parent->i_generation; 569 + spin_unlock(&dentry->d_lock); 570 + 571 + type = FILEID_NILFS_WITH_PARENT; 572 + *lenp = NILFS_FID_SIZE_CONNECTABLE; 573 + } else { 574 + type = FILEID_NILFS_WITHOUT_PARENT; 575 + *lenp = NILFS_FID_SIZE_NON_CONNECTABLE; 576 + } 577 + 578 + return type; 579 + } 580 + 459 581 const struct inode_operations nilfs_dir_inode_operations = { 460 582 .create = nilfs_create, 461 583 .lookup = nilfs_lookup, ··· 588 492 .readlink = generic_readlink, 589 493 .follow_link = page_follow_link_light, 590 494 .put_link = page_put_link, 495 + }; 496 + 497 + const struct export_operations nilfs_export_ops = { 498 + .encode_fh = nilfs_encode_fh, 499 + .fh_to_dentry = nilfs_fh_to_dentry, 500 + .fh_to_parent = nilfs_fh_to_parent, 501 + .get_parent = nilfs_get_parent, 591 502 };
-3
fs/nilfs2/nilfs.h
··· 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 *);
+1 -51
fs/nilfs2/super.c
··· 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 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 {
+13
include/linux/exportfs.h
··· 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 {