aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-08-26 11:23:02 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-10-22 20:24:34 -0400
commit8e656fd518784b49453f60c5f78b78703bc85cb2 (patch)
tree7adf4b71aba4bdf31dc05489a06933c48a0ea6f2
parent4d8d9293dce503eb0e083e17a02a328d397e7f00 (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.h17
-rw-r--r--fs/nilfs2/namei.c137
-rw-r--r--fs/nilfs2/nilfs.h3
-rw-r--r--fs/nilfs2/super.c52
-rw-r--r--include/linux/exportfs.h13
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
6extern const struct export_operations nilfs_export_ops;
7
8struct 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
45static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) 49static 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
80struct 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 */
462static 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
482static 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
507static 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
521static 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
533static 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
472const struct inode_operations nilfs_dir_inode_operations = { 568const 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
593const 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 *,
264extern int nilfs_mark_inode_dirty(struct inode *); 264extern int nilfs_mark_inode_dirty(struct inode *);
265extern void nilfs_dirty_inode(struct inode *); 265extern void nilfs_dirty_inode(struct inode *);
266 266
267/* namei.c */
268extern struct dentry *nilfs_get_parent(struct dentry *);
269
270/* super.c */ 267/* super.c */
271extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); 268extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *);
272extern struct inode *nilfs_alloc_inode(struct super_block *); 269extern 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
559static struct inode *
560nilfs_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
587static struct dentry *
588nilfs_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
595static struct dentry *
596nilfs_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
603static 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
609enum { 559enum {
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,
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index a9cd507f8cd2..28028988c862 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -67,6 +67,19 @@ enum fid_type {
67 * 32 bit parent block number, 32 bit parent generation number 67 * 32 bit parent block number, 32 bit parent generation number
68 */ 68 */
69 FILEID_UDF_WITH_PARENT = 0x52, 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
72struct fid { 85struct fid {