aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2007-10-21 19:42:11 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-22 11:13:20 -0400
commitc38344fe9e73c99d546cc15a2bb97c7a09942aad (patch)
tree83d3cb3f57367ef934fd751e01ff0e11a21bf5e5 /fs/xfs
parenta35132068a91907c29328abc3156d31e50673412 (diff)
xfs: new export ops
This one is a lot more complicated than the previous ones. XFS already had a very clever scheme for supporting 64bit inode numbers in filehandles, and I've reworked this to be some kind of a prototype for the generic 64bit inode filehandle support. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: Neil Brown <neilb@suse.de> Cc: "J. Bruce Fields" <bfields@fieldses.org> Cc: David Chinner <dgc@sgi.com> Cc: Timothy Shimmin <tes@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/linux-2.6/xfs_export.c204
-rw-r--r--fs/xfs/linux-2.6/xfs_export.h50
2 files changed, 130 insertions, 124 deletions
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index 3586c7a28d2c..7178d61f002e 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -33,62 +33,25 @@
33static struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, }; 33static struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, };
34 34
35/* 35/*
36 * XFS encodes and decodes the fileid portion of NFS filehandles 36 * Note that we only accept fileids which are long enough rather than allow
37 * itself instead of letting the generic NFS code do it. This 37 * the parent generation number to default to zero. XFS considers zero a
38 * allows filesystems with 64 bit inode numbers to be exported. 38 * valid generation number not an invalid/wildcard value.
39 *
40 * Note that a side effect is that xfs_vget() won't be passed a
41 * zero inode/generation pair under normal circumstances. As
42 * however a malicious client could send us such data, the check
43 * remains in that code.
44 */ 39 */
45 40static int xfs_fileid_length(int fileid_type)
46STATIC struct dentry *
47xfs_fs_decode_fh(
48 struct super_block *sb,
49 __u32 *fh,
50 int fh_len,
51 int fileid_type,
52 int (*acceptable)(
53 void *context,
54 struct dentry *de),
55 void *context)
56{ 41{
57 xfs_fid_t ifid; 42 switch (fileid_type) {
58 xfs_fid_t pfid; 43 case FILEID_INO32_GEN:
59 void *parent = NULL; 44 return 2;
60 int is64 = 0; 45 case FILEID_INO32_GEN_PARENT:
61 __u32 *p = fh; 46 return 4;
62 47 case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
63#if XFS_BIG_INUMS 48 return 3;
64 is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG); 49 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
65 fileid_type &= ~XFS_FILEID_TYPE_64FLAG; 50 return 6;
66#endif
67
68 /*
69 * Note that we only accept fileids which are long enough
70 * rather than allow the parent generation number to default
71 * to zero. XFS considers zero a valid generation number not
72 * an invalid/wildcard value. There's little point printk'ing
73 * a warning here as we don't have the client information
74 * which would make such a warning useful.
75 */
76 if (fileid_type > 2 ||
77 fh_len < xfs_fileid_length((fileid_type == 2), is64))
78 return NULL;
79
80 p = xfs_fileid_decode_fid2(p, &ifid, is64);
81
82 if (fileid_type == 2) {
83 p = xfs_fileid_decode_fid2(p, &pfid, is64);
84 parent = &pfid;
85 } 51 }
86 52 return 255; /* invalid */
87 fh = (__u32 *)&ifid;
88 return sb->s_export_op->find_exported_dentry(sb, fh, parent, acceptable, context);
89} 53}
90 54
91
92STATIC int 55STATIC int
93xfs_fs_encode_fh( 56xfs_fs_encode_fh(
94 struct dentry *dentry, 57 struct dentry *dentry,
@@ -96,21 +59,21 @@ xfs_fs_encode_fh(
96 int *max_len, 59 int *max_len,
97 int connectable) 60 int connectable)
98{ 61{
62 struct fid *fid = (struct fid *)fh;
63 struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fh;
99 struct inode *inode = dentry->d_inode; 64 struct inode *inode = dentry->d_inode;
100 int type = 1; 65 int fileid_type;
101 __u32 *p = fh;
102 int len; 66 int len;
103 int is64 = 0;
104#if XFS_BIG_INUMS
105 if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS)) {
106 /* filesystem may contain 64bit inode numbers */
107 is64 = XFS_FILEID_TYPE_64FLAG;
108 }
109#endif
110 67
111 /* Directories don't need their parent encoded, they have ".." */ 68 /* Directories don't need their parent encoded, they have ".." */
112 if (S_ISDIR(inode->i_mode)) 69 if (S_ISDIR(inode->i_mode))
113 connectable = 0; 70 fileid_type = FILEID_INO32_GEN;
71 else
72 fileid_type = FILEID_INO32_GEN_PARENT;
73
74 /* filesystem may contain 64bit inode numbers */
75 if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS))
76 fileid_type |= XFS_FILEID_TYPE_64FLAG;
114 77
115 /* 78 /*
116 * Only encode if there is enough space given. In practice 79 * Only encode if there is enough space given. In practice
@@ -118,39 +81,118 @@ xfs_fs_encode_fh(
118 * over NFSv2 with the subtree_check export option; the other 81 * over NFSv2 with the subtree_check export option; the other
119 * seven combinations work. The real answer is "don't use v2". 82 * seven combinations work. The real answer is "don't use v2".
120 */ 83 */
121 len = xfs_fileid_length(connectable, is64); 84 len = xfs_fileid_length(fileid_type);
122 if (*max_len < len) 85 if (*max_len < len)
123 return 255; 86 return 255;
124 *max_len = len; 87 *max_len = len;
125 88
126 p = xfs_fileid_encode_inode(p, inode, is64); 89 switch (fileid_type) {
127 if (connectable) { 90 case FILEID_INO32_GEN_PARENT:
128 spin_lock(&dentry->d_lock); 91 spin_lock(&dentry->d_lock);
129 p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64); 92 fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino;
93 fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation;
130 spin_unlock(&dentry->d_lock); 94 spin_unlock(&dentry->d_lock);
131 type = 2; 95 /*FALLTHRU*/
96 case FILEID_INO32_GEN:
97 fid->i32.ino = inode->i_ino;
98 fid->i32.gen = inode->i_generation;
99 break;
100 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
101 spin_lock(&dentry->d_lock);
102 fid64->parent_ino = dentry->d_parent->d_inode->i_ino;
103 fid64->parent_gen = dentry->d_parent->d_inode->i_generation;
104 spin_unlock(&dentry->d_lock);
105 /*FALLTHRU*/
106 case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
107 fid64->ino = inode->i_ino;
108 fid64->gen = inode->i_generation;
109 break;
132 } 110 }
133 BUG_ON((p - fh) != len); 111
134 return type | is64; 112 return fileid_type;
135} 113}
136 114
137STATIC struct dentry * 115STATIC struct inode *
138xfs_fs_get_dentry( 116xfs_nfs_get_inode(
139 struct super_block *sb, 117 struct super_block *sb,
140 void *data) 118 u64 ino,
141{ 119 u32 generation)
120 {
121 xfs_fid_t xfid;
142 bhv_vnode_t *vp; 122 bhv_vnode_t *vp;
143 struct inode *inode;
144 struct dentry *result;
145 int error; 123 int error;
146 124
147 error = xfs_vget(XFS_M(sb), &vp, data); 125 xfid.fid_len = sizeof(xfs_fid_t) - sizeof(xfid.fid_len);
148 if (error || vp == NULL) 126 xfid.fid_pad = 0;
149 return ERR_PTR(-ESTALE) ; 127 xfid.fid_ino = ino;
128 xfid.fid_gen = generation;
150 129
151 inode = vn_to_inode(vp); 130 error = xfs_vget(XFS_M(sb), &vp, &xfid);
131 if (error)
132 return ERR_PTR(-error);
133
134 return vp ? vn_to_inode(vp) : NULL;
135}
136
137STATIC struct dentry *
138xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
139 int fh_len, int fileid_type)
140{
141 struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
142 struct inode *inode = NULL;
143 struct dentry *result;
144
145 if (fh_len < xfs_fileid_length(fileid_type))
146 return NULL;
147
148 switch (fileid_type) {
149 case FILEID_INO32_GEN_PARENT:
150 case FILEID_INO32_GEN:
151 inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
152 break;
153 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
154 case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
155 inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
156 break;
157 }
158
159 if (!inode)
160 return NULL;
161 if (IS_ERR(inode))
162 return ERR_PTR(PTR_ERR(inode));
163 result = d_alloc_anon(inode);
164 if (!result) {
165 iput(inode);
166 return ERR_PTR(-ENOMEM);
167 }
168 return result;
169}
170
171STATIC struct dentry *
172xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
173 int fh_len, int fileid_type)
174{
175 struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
176 struct inode *inode = NULL;
177 struct dentry *result;
178
179 switch (fileid_type) {
180 case FILEID_INO32_GEN_PARENT:
181 inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
182 fid->i32.parent_gen);
183 break;
184 case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
185 inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
186 fid64->parent_gen);
187 break;
188 }
189
190 if (!inode)
191 return NULL;
192 if (IS_ERR(inode))
193 return ERR_PTR(PTR_ERR(inode));
152 result = d_alloc_anon(inode); 194 result = d_alloc_anon(inode);
153 if (!result) { 195 if (!result) {
154 iput(inode); 196 iput(inode);
155 return ERR_PTR(-ENOMEM); 197 return ERR_PTR(-ENOMEM);
156 } 198 }
@@ -179,8 +221,8 @@ xfs_fs_get_parent(
179} 221}
180 222
181struct export_operations xfs_export_operations = { 223struct export_operations xfs_export_operations = {
182 .decode_fh = xfs_fs_decode_fh,
183 .encode_fh = xfs_fs_encode_fh, 224 .encode_fh = xfs_fs_encode_fh,
225 .fh_to_dentry = xfs_fs_fh_to_dentry,
226 .fh_to_parent = xfs_fs_fh_to_parent,
184 .get_parent = xfs_fs_get_parent, 227 .get_parent = xfs_fs_get_parent,
185 .get_dentry = xfs_fs_get_dentry,
186}; 228};
diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h
index 2f36071a86f7..3272b6ae7a35 100644
--- a/fs/xfs/linux-2.6/xfs_export.h
+++ b/fs/xfs/linux-2.6/xfs_export.h
@@ -59,50 +59,14 @@
59 * a subdirectory) or use the "fsid" export option. 59 * a subdirectory) or use the "fsid" export option.
60 */ 60 */
61 61
62struct xfs_fid64 {
63 u64 ino;
64 u32 gen;
65 u64 parent_ino;
66 u32 parent_gen;
67} __attribute__((packed));
68
62/* This flag goes on the wire. Don't play with it. */ 69/* This flag goes on the wire. Don't play with it. */
63#define XFS_FILEID_TYPE_64FLAG 0x80 /* NFS fileid has 64bit inodes */ 70#define XFS_FILEID_TYPE_64FLAG 0x80 /* NFS fileid has 64bit inodes */
64 71
65/* Calculate the length in u32 units of the fileid data */
66static inline int
67xfs_fileid_length(int hasparent, int is64)
68{
69 return hasparent ? (is64 ? 6 : 4) : (is64 ? 3 : 2);
70}
71
72/*
73 * Decode encoded inode information (either for the inode itself
74 * or the parent) into an xfs_fid_t structure. Advances and
75 * returns the new data pointer
76 */
77static inline __u32 *
78xfs_fileid_decode_fid2(__u32 *p, xfs_fid_t *fid, int is64)
79{
80 fid->fid_len = sizeof(xfs_fid_t) - sizeof(fid->fid_len);
81 fid->fid_pad = 0;
82 fid->fid_ino = *p++;
83#if XFS_BIG_INUMS
84 if (is64)
85 fid->fid_ino |= (((__u64)(*p++)) << 32);
86#endif
87 fid->fid_gen = *p++;
88 return p;
89}
90
91/*
92 * Encode inode information (either for the inode itself or the
93 * parent) into a fileid buffer. Advances and returns the new
94 * data pointer.
95 */
96static inline __u32 *
97xfs_fileid_encode_inode(__u32 *p, struct inode *inode, int is64)
98{
99 *p++ = (__u32)inode->i_ino;
100#if XFS_BIG_INUMS
101 if (is64)
102 *p++ = (__u32)(inode->i_ino >> 32);
103#endif
104 *p++ = inode->i_generation;
105 return p;
106}
107
108#endif /* __XFS_EXPORT_H__ */ 72#endif /* __XFS_EXPORT_H__ */