aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfsfh.c228
1 files changed, 123 insertions, 105 deletions
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 3e6b3f41ee1f..100ae5641162 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -113,6 +113,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
113} 113}
114 114
115/* 115/*
116 * Use the given filehandle to look up the corresponding export and
117 * dentry. On success, the results are used to set fh_export and
118 * fh_dentry.
119 */
120static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
121{
122 struct knfsd_fh *fh = &fhp->fh_handle;
123 struct fid *fid = NULL, sfid;
124 struct svc_export *exp;
125 struct dentry *dentry;
126 int fileid_type;
127 int data_left = fh->fh_size/4;
128 __be32 error;
129
130 error = nfserr_stale;
131 if (rqstp->rq_vers > 2)
132 error = nfserr_badhandle;
133 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
134 return nfserr_nofilehandle;
135
136 if (fh->fh_version == 1) {
137 int len;
138
139 if (--data_left < 0)
140 return error;
141 if (fh->fh_auth_type != 0)
142 return error;
143 len = key_len(fh->fh_fsid_type) / 4;
144 if (len == 0)
145 return error;
146 if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
147 /* deprecated, convert to type 3 */
148 len = key_len(FSID_ENCODE_DEV)/4;
149 fh->fh_fsid_type = FSID_ENCODE_DEV;
150 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
151 fh->fh_fsid[1] = fh->fh_fsid[2];
152 }
153 data_left -= len;
154 if (data_left < 0)
155 return error;
156 exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
157 fid = (struct fid *)(fh->fh_auth + len);
158 } else {
159 __u32 tfh[2];
160 dev_t xdev;
161 ino_t xino;
162
163 if (fh->fh_size != NFS_FHSIZE)
164 return error;
165 /* assume old filehandle format */
166 xdev = old_decode_dev(fh->ofh_xdev);
167 xino = u32_to_ino_t(fh->ofh_xino);
168 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
169 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
170 }
171
172 error = nfserr_stale;
173 if (PTR_ERR(exp) == -ENOENT)
174 return error;
175
176 if (IS_ERR(exp))
177 return nfserrno(PTR_ERR(exp));
178
179 error = nfsd_setuser_and_check_port(rqstp, exp);
180 if (error)
181 goto out;
182
183 /*
184 * Look up the dentry using the NFS file handle.
185 */
186 error = nfserr_stale;
187 if (rqstp->rq_vers > 2)
188 error = nfserr_badhandle;
189
190 if (fh->fh_version != 1) {
191 sfid.i32.ino = fh->ofh_ino;
192 sfid.i32.gen = fh->ofh_generation;
193 sfid.i32.parent_ino = fh->ofh_dirino;
194 fid = &sfid;
195 data_left = 3;
196 if (fh->ofh_dirino == 0)
197 fileid_type = FILEID_INO32_GEN;
198 else
199 fileid_type = FILEID_INO32_GEN_PARENT;
200 } else
201 fileid_type = fh->fh_fileid_type;
202
203 if (fileid_type == FILEID_ROOT)
204 dentry = dget(exp->ex_path.dentry);
205 else {
206 dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
207 data_left, fileid_type,
208 nfsd_acceptable, exp);
209 }
210 if (dentry == NULL)
211 goto out;
212 if (IS_ERR(dentry)) {
213 if (PTR_ERR(dentry) != -EINVAL)
214 error = nfserrno(PTR_ERR(dentry));
215 goto out;
216 }
217
218 if (S_ISDIR(dentry->d_inode->i_mode) &&
219 (dentry->d_flags & DCACHE_DISCONNECTED)) {
220 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
221 dentry->d_parent->d_name.name, dentry->d_name.name);
222 }
223
224 fhp->fh_dentry = dentry;
225 fhp->fh_export = exp;
226 nfsd_nr_verified++;
227 return 0;
228out:
229 exp_put(exp);
230 return error;
231}
232
233/*
116 * Perform sanity checks on the dentry in a client's file handle. 234 * Perform sanity checks on the dentry in a client's file handle.
117 * 235 *
118 * Note that the file handle dentry may need to be freed even after 236 * Note that the file handle dentry may need to be freed even after
@@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
124__be32 242__be32
125fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) 243fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
126{ 244{
127 struct knfsd_fh *fh = &fhp->fh_handle; 245 struct svc_export *exp;
128 struct svc_export *exp = NULL;
129 struct dentry *dentry; 246 struct dentry *dentry;
130 __be32 error = 0; 247 __be32 error;
131 248
132 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); 249 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
133 250
134 if (!fhp->fh_dentry) { 251 if (!fhp->fh_dentry) {
135 struct fid *fid = NULL, sfid; 252 error = nfsd_set_fh_dentry(rqstp, fhp);
136 int fileid_type;
137 int data_left = fh->fh_size/4;
138
139 error = nfserr_stale;
140 if (rqstp->rq_vers > 2)
141 error = nfserr_badhandle;
142 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
143 return nfserr_nofilehandle;
144
145 if (fh->fh_version == 1) {
146 int len;
147 if (--data_left<0) goto out;
148 switch (fh->fh_auth_type) {
149 case 0: break;
150 default: goto out;
151 }
152 len = key_len(fh->fh_fsid_type) / 4;
153 if (len == 0) goto out;
154 if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
155 /* deprecated, convert to type 3 */
156 len = key_len(FSID_ENCODE_DEV)/4;
157 fh->fh_fsid_type = FSID_ENCODE_DEV;
158 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
159 fh->fh_fsid[1] = fh->fh_fsid[2];
160 }
161 if ((data_left -= len)<0) goto out;
162 exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
163 fh->fh_auth);
164 fid = (struct fid *)(fh->fh_auth + len);
165 } else {
166 __u32 tfh[2];
167 dev_t xdev;
168 ino_t xino;
169 if (fh->fh_size != NFS_FHSIZE)
170 goto out;
171 /* assume old filehandle format */
172 xdev = old_decode_dev(fh->ofh_xdev);
173 xino = u32_to_ino_t(fh->ofh_xino);
174 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
175 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
176 }
177
178 error = nfserr_stale;
179 if (PTR_ERR(exp) == -ENOENT)
180 goto out;
181
182 if (IS_ERR(exp)) {
183 error = nfserrno(PTR_ERR(exp));
184 goto out;
185 }
186
187 error = nfsd_setuser_and_check_port(rqstp, exp);
188 if (error) 253 if (error)
189 goto out; 254 goto out;
190 255 dentry = fhp->fh_dentry;
191 /* 256 exp = fhp->fh_export;
192 * Look up the dentry using the NFS file handle.
193 */
194 error = nfserr_stale;
195 if (rqstp->rq_vers > 2)
196 error = nfserr_badhandle;
197
198 if (fh->fh_version != 1) {
199 sfid.i32.ino = fh->ofh_ino;
200 sfid.i32.gen = fh->ofh_generation;
201 sfid.i32.parent_ino = fh->ofh_dirino;
202 fid = &sfid;
203 data_left = 3;
204 if (fh->ofh_dirino == 0)
205 fileid_type = FILEID_INO32_GEN;
206 else
207 fileid_type = FILEID_INO32_GEN_PARENT;
208 } else
209 fileid_type = fh->fh_fileid_type;
210
211 if (fileid_type == FILEID_ROOT)
212 dentry = dget(exp->ex_path.dentry);
213 else {
214 dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
215 data_left, fileid_type,
216 nfsd_acceptable, exp);
217 }
218 if (dentry == NULL)
219 goto out;
220 if (IS_ERR(dentry)) {
221 if (PTR_ERR(dentry) != -EINVAL)
222 error = nfserrno(PTR_ERR(dentry));
223 goto out;
224 }
225
226 if (S_ISDIR(dentry->d_inode->i_mode) &&
227 (dentry->d_flags & DCACHE_DISCONNECTED)) {
228 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
229 dentry->d_parent->d_name.name, dentry->d_name.name);
230 }
231
232 fhp->fh_dentry = dentry;
233 fhp->fh_export = exp;
234 nfsd_nr_verified++;
235 cache_get(&exp->h);
236 } else { 257 } else {
237 /* 258 /*
238 * just rechecking permissions 259 * just rechecking permissions
@@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
242 dprintk("nfsd: fh_verify - just checking\n"); 263 dprintk("nfsd: fh_verify - just checking\n");
243 dentry = fhp->fh_dentry; 264 dentry = fhp->fh_dentry;
244 exp = fhp->fh_export; 265 exp = fhp->fh_export;
245 cache_get(&exp->h);
246 /* 266 /*
247 * Set user creds for this exportpoint; necessary even 267 * Set user creds for this exportpoint; necessary even
248 * in the "just checking" case because this may be a 268 * in the "just checking" case because this may be a
@@ -281,8 +301,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
281 access, ntohl(error)); 301 access, ntohl(error));
282 } 302 }
283out: 303out:
284 if (exp && !IS_ERR(exp))
285 exp_put(exp);
286 if (error == nfserr_stale) 304 if (error == nfserr_stale)
287 nfsdstats.fh_stale++; 305 nfsdstats.fh_stale++;
288 return error; 306 return error;