Commit 8e656fd518784b49453f60c5f78b78703bc85cb2

Authored by Ryusuke Konishi
1 parent 4d8d9293dc

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

  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
... ... @@ -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 };
... ... @@ -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 *);
... ... @@ -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 {