diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_export.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_export.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c new file mode 100644 index 000000000000..f372a1a5e168 --- /dev/null +++ b/fs/xfs/linux-2.6/xfs_export.c | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of version 2 of the GNU General Public License as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it would be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
11 | * | ||
12 | * Further, this software is distributed without any warranty that it is | ||
13 | * free of the rightful claim of any third person regarding infringement | ||
14 | * or the like. Any license provided herein, whether implied or | ||
15 | * otherwise, applies only to this software file. Patent licenses, if | ||
16 | * any, provided herein do not apply to combinations of this program with | ||
17 | * other software, or any other product whatsoever. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write the Free Software Foundation, Inc., 59 | ||
21 | * Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
22 | * | ||
23 | * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, | ||
24 | * Mountain View, CA 94043, or: | ||
25 | * | ||
26 | * http://www.sgi.com | ||
27 | * | ||
28 | * For further information regarding this notice, see: | ||
29 | * | ||
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ | ||
31 | */ | ||
32 | |||
33 | #include "xfs.h" | ||
34 | #include "xfs_types.h" | ||
35 | #include "xfs_dmapi.h" | ||
36 | #include "xfs_log.h" | ||
37 | #include "xfs_trans.h" | ||
38 | #include "xfs_sb.h" | ||
39 | #include "xfs_dir.h" | ||
40 | #include "xfs_mount.h" | ||
41 | #include "xfs_export.h" | ||
42 | |||
43 | /* | ||
44 | * XFS encode and decodes the fileid portion of NFS filehandles | ||
45 | * itself instead of letting the generic NFS code do it. This | ||
46 | * allows filesystems with 64 bit inode numbers to be exported. | ||
47 | * | ||
48 | * Note that a side effect is that xfs_vget() won't be passed a | ||
49 | * zero inode/generation pair under normal circumstances. As | ||
50 | * however a malicious client could send us such data, the check | ||
51 | * remains in that code. | ||
52 | */ | ||
53 | |||
54 | |||
55 | STATIC struct dentry * | ||
56 | linvfs_decode_fh( | ||
57 | struct super_block *sb, | ||
58 | __u32 *fh, | ||
59 | int fh_len, | ||
60 | int fileid_type, | ||
61 | int (*acceptable)( | ||
62 | void *context, | ||
63 | struct dentry *de), | ||
64 | void *context) | ||
65 | { | ||
66 | xfs_fid2_t ifid; | ||
67 | xfs_fid2_t pfid; | ||
68 | void *parent = NULL; | ||
69 | int is64 = 0; | ||
70 | __u32 *p = fh; | ||
71 | |||
72 | #if XFS_BIG_INUMS | ||
73 | is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG); | ||
74 | fileid_type &= ~XFS_FILEID_TYPE_64FLAG; | ||
75 | #endif | ||
76 | |||
77 | /* | ||
78 | * Note that we only accept fileids which are long enough | ||
79 | * rather than allow the parent generation number to default | ||
80 | * to zero. XFS considers zero a valid generation number not | ||
81 | * an invalid/wildcard value. There's little point printk'ing | ||
82 | * a warning here as we don't have the client information | ||
83 | * which would make such a warning useful. | ||
84 | */ | ||
85 | if (fileid_type > 2 || | ||
86 | fh_len < xfs_fileid_length((fileid_type == 2), is64)) | ||
87 | return NULL; | ||
88 | |||
89 | p = xfs_fileid_decode_fid2(p, &ifid, is64); | ||
90 | |||
91 | if (fileid_type == 2) { | ||
92 | p = xfs_fileid_decode_fid2(p, &pfid, is64); | ||
93 | parent = &pfid; | ||
94 | } | ||
95 | |||
96 | fh = (__u32 *)&ifid; | ||
97 | return find_exported_dentry(sb, fh, parent, acceptable, context); | ||
98 | } | ||
99 | |||
100 | |||
101 | STATIC int | ||
102 | linvfs_encode_fh( | ||
103 | struct dentry *dentry, | ||
104 | __u32 *fh, | ||
105 | int *max_len, | ||
106 | int connectable) | ||
107 | { | ||
108 | struct inode *inode = dentry->d_inode; | ||
109 | int type = 1; | ||
110 | __u32 *p = fh; | ||
111 | int len; | ||
112 | int is64 = 0; | ||
113 | #if XFS_BIG_INUMS | ||
114 | vfs_t *vfs = LINVFS_GET_VFS(inode->i_sb); | ||
115 | xfs_mount_t *mp = XFS_VFSTOM(vfs); | ||
116 | |||
117 | if (!(mp->m_flags & XFS_MOUNT_32BITINOOPT)) { | ||
118 | /* filesystem may contain 64bit inode numbers */ | ||
119 | is64 = XFS_FILEID_TYPE_64FLAG; | ||
120 | } | ||
121 | #endif | ||
122 | |||
123 | /* Directories don't need their parent encoded, they have ".." */ | ||
124 | if (S_ISDIR(inode->i_mode)) | ||
125 | connectable = 0; | ||
126 | |||
127 | /* | ||
128 | * Only encode if there is enough space given. In practice | ||
129 | * this means we can't export a filesystem with 64bit inodes | ||
130 | * over NFSv2 with the subtree_check export option; the other | ||
131 | * seven combinations work. The real answer is "don't use v2". | ||
132 | */ | ||
133 | len = xfs_fileid_length(connectable, is64); | ||
134 | if (*max_len < len) | ||
135 | return 255; | ||
136 | *max_len = len; | ||
137 | |||
138 | p = xfs_fileid_encode_inode(p, inode, is64); | ||
139 | if (connectable) { | ||
140 | spin_lock(&dentry->d_lock); | ||
141 | p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64); | ||
142 | spin_unlock(&dentry->d_lock); | ||
143 | type = 2; | ||
144 | } | ||
145 | BUG_ON((p - fh) != len); | ||
146 | return type | is64; | ||
147 | } | ||
148 | |||
149 | STATIC struct dentry * | ||
150 | linvfs_get_dentry( | ||
151 | struct super_block *sb, | ||
152 | void *data) | ||
153 | { | ||
154 | vnode_t *vp; | ||
155 | struct inode *inode; | ||
156 | struct dentry *result; | ||
157 | vfs_t *vfsp = LINVFS_GET_VFS(sb); | ||
158 | int error; | ||
159 | |||
160 | VFS_VGET(vfsp, &vp, (fid_t *)data, error); | ||
161 | if (error || vp == NULL) | ||
162 | return ERR_PTR(-ESTALE) ; | ||
163 | |||
164 | inode = LINVFS_GET_IP(vp); | ||
165 | result = d_alloc_anon(inode); | ||
166 | if (!result) { | ||
167 | iput(inode); | ||
168 | return ERR_PTR(-ENOMEM); | ||
169 | } | ||
170 | return result; | ||
171 | } | ||
172 | |||
173 | STATIC struct dentry * | ||
174 | linvfs_get_parent( | ||
175 | struct dentry *child) | ||
176 | { | ||
177 | int error; | ||
178 | vnode_t *vp, *cvp; | ||
179 | struct dentry *parent; | ||
180 | struct dentry dotdot; | ||
181 | |||
182 | dotdot.d_name.name = ".."; | ||
183 | dotdot.d_name.len = 2; | ||
184 | dotdot.d_inode = NULL; | ||
185 | |||
186 | cvp = NULL; | ||
187 | vp = LINVFS_GET_VP(child->d_inode); | ||
188 | VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error); | ||
189 | if (unlikely(error)) | ||
190 | return ERR_PTR(-error); | ||
191 | |||
192 | parent = d_alloc_anon(LINVFS_GET_IP(cvp)); | ||
193 | if (unlikely(!parent)) { | ||
194 | VN_RELE(cvp); | ||
195 | return ERR_PTR(-ENOMEM); | ||
196 | } | ||
197 | return parent; | ||
198 | } | ||
199 | |||
200 | struct export_operations linvfs_export_ops = { | ||
201 | .decode_fh = linvfs_decode_fh, | ||
202 | .encode_fh = linvfs_encode_fh, | ||
203 | .get_parent = linvfs_get_parent, | ||
204 | .get_dentry = linvfs_get_dentry, | ||
205 | }; | ||