diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/nfsd/nfs3proc.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/nfsd/nfs3proc.c')
-rw-r--r-- | fs/nfsd/nfs3proc.c | 702 |
1 files changed, 702 insertions, 0 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c new file mode 100644 index 000000000000..041380fe667b --- /dev/null +++ b/fs/nfsd/nfs3proc.c | |||
@@ -0,0 +1,702 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfs3proc.c | ||
3 | * | ||
4 | * Process version 3 NFS requests. | ||
5 | * | ||
6 | * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de> | ||
7 | */ | ||
8 | |||
9 | #include <linux/linkage.h> | ||
10 | #include <linux/time.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/fs.h> | ||
13 | #include <linux/ext2_fs.h> | ||
14 | #include <linux/stat.h> | ||
15 | #include <linux/fcntl.h> | ||
16 | #include <linux/net.h> | ||
17 | #include <linux/in.h> | ||
18 | #include <linux/unistd.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/major.h> | ||
21 | |||
22 | #include <linux/sunrpc/svc.h> | ||
23 | #include <linux/nfsd/nfsd.h> | ||
24 | #include <linux/nfsd/cache.h> | ||
25 | #include <linux/nfsd/xdr3.h> | ||
26 | #include <linux/nfs3.h> | ||
27 | |||
28 | #define NFSDDBG_FACILITY NFSDDBG_PROC | ||
29 | |||
30 | #define RETURN_STATUS(st) { resp->status = (st); return (st); } | ||
31 | |||
32 | static int nfs3_ftypes[] = { | ||
33 | 0, /* NF3NON */ | ||
34 | S_IFREG, /* NF3REG */ | ||
35 | S_IFDIR, /* NF3DIR */ | ||
36 | S_IFBLK, /* NF3BLK */ | ||
37 | S_IFCHR, /* NF3CHR */ | ||
38 | S_IFLNK, /* NF3LNK */ | ||
39 | S_IFSOCK, /* NF3SOCK */ | ||
40 | S_IFIFO, /* NF3FIFO */ | ||
41 | }; | ||
42 | |||
43 | /* | ||
44 | * NULL call. | ||
45 | */ | ||
46 | static int | ||
47 | nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | ||
48 | { | ||
49 | return nfs_ok; | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Get a file's attributes | ||
54 | */ | ||
55 | static int | ||
56 | nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, | ||
57 | struct nfsd3_attrstat *resp) | ||
58 | { | ||
59 | int nfserr; | ||
60 | |||
61 | dprintk("nfsd: GETATTR(3) %s\n", | ||
62 | SVCFH_fmt(&argp->fh)); | ||
63 | |||
64 | fh_copy(&resp->fh, &argp->fh); | ||
65 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | ||
66 | RETURN_STATUS(nfserr); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Set a file's attributes | ||
71 | */ | ||
72 | static int | ||
73 | nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp, | ||
74 | struct nfsd3_attrstat *resp) | ||
75 | { | ||
76 | int nfserr; | ||
77 | |||
78 | dprintk("nfsd: SETATTR(3) %s\n", | ||
79 | SVCFH_fmt(&argp->fh)); | ||
80 | |||
81 | fh_copy(&resp->fh, &argp->fh); | ||
82 | nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, | ||
83 | argp->check_guard, argp->guardtime); | ||
84 | RETURN_STATUS(nfserr); | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Look up a path name component | ||
89 | */ | ||
90 | static int | ||
91 | nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, | ||
92 | struct nfsd3_diropres *resp) | ||
93 | { | ||
94 | int nfserr; | ||
95 | |||
96 | dprintk("nfsd: LOOKUP(3) %s %.*s\n", | ||
97 | SVCFH_fmt(&argp->fh), | ||
98 | argp->len, | ||
99 | argp->name); | ||
100 | |||
101 | fh_copy(&resp->dirfh, &argp->fh); | ||
102 | fh_init(&resp->fh, NFS3_FHSIZE); | ||
103 | |||
104 | nfserr = nfsd_lookup(rqstp, &resp->dirfh, | ||
105 | argp->name, | ||
106 | argp->len, | ||
107 | &resp->fh); | ||
108 | RETURN_STATUS(nfserr); | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Check file access | ||
113 | */ | ||
114 | static int | ||
115 | nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp, | ||
116 | struct nfsd3_accessres *resp) | ||
117 | { | ||
118 | int nfserr; | ||
119 | |||
120 | dprintk("nfsd: ACCESS(3) %s 0x%x\n", | ||
121 | SVCFH_fmt(&argp->fh), | ||
122 | argp->access); | ||
123 | |||
124 | fh_copy(&resp->fh, &argp->fh); | ||
125 | resp->access = argp->access; | ||
126 | nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); | ||
127 | RETURN_STATUS(nfserr); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Read a symlink. | ||
132 | */ | ||
133 | static int | ||
134 | nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp, | ||
135 | struct nfsd3_readlinkres *resp) | ||
136 | { | ||
137 | int nfserr; | ||
138 | |||
139 | dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); | ||
140 | |||
141 | /* Read the symlink. */ | ||
142 | fh_copy(&resp->fh, &argp->fh); | ||
143 | resp->len = NFS3_MAXPATHLEN; | ||
144 | nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len); | ||
145 | RETURN_STATUS(nfserr); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Read a portion of a file. | ||
150 | */ | ||
151 | static int | ||
152 | nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, | ||
153 | struct nfsd3_readres *resp) | ||
154 | { | ||
155 | int nfserr; | ||
156 | |||
157 | dprintk("nfsd: READ(3) %s %lu bytes at %lu\n", | ||
158 | SVCFH_fmt(&argp->fh), | ||
159 | (unsigned long) argp->count, | ||
160 | (unsigned long) argp->offset); | ||
161 | |||
162 | /* Obtain buffer pointer for payload. | ||
163 | * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) | ||
164 | * + 1 (xdr opaque byte count) = 26 | ||
165 | */ | ||
166 | |||
167 | resp->count = argp->count; | ||
168 | if (NFSSVC_MAXBLKSIZE < resp->count) | ||
169 | resp->count = NFSSVC_MAXBLKSIZE; | ||
170 | |||
171 | svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); | ||
172 | |||
173 | fh_copy(&resp->fh, &argp->fh); | ||
174 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, | ||
175 | argp->offset, | ||
176 | argp->vec, argp->vlen, | ||
177 | &resp->count); | ||
178 | if (nfserr == 0) { | ||
179 | struct inode *inode = resp->fh.fh_dentry->d_inode; | ||
180 | |||
181 | resp->eof = (argp->offset + resp->count) >= inode->i_size; | ||
182 | } | ||
183 | |||
184 | RETURN_STATUS(nfserr); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Write data to a file | ||
189 | */ | ||
190 | static int | ||
191 | nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp, | ||
192 | struct nfsd3_writeres *resp) | ||
193 | { | ||
194 | int nfserr; | ||
195 | |||
196 | dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n", | ||
197 | SVCFH_fmt(&argp->fh), | ||
198 | argp->len, | ||
199 | (unsigned long) argp->offset, | ||
200 | argp->stable? " stable" : ""); | ||
201 | |||
202 | fh_copy(&resp->fh, &argp->fh); | ||
203 | resp->committed = argp->stable; | ||
204 | nfserr = nfsd_write(rqstp, &resp->fh, NULL, | ||
205 | argp->offset, | ||
206 | argp->vec, argp->vlen, | ||
207 | argp->len, | ||
208 | &resp->committed); | ||
209 | resp->count = argp->count; | ||
210 | RETURN_STATUS(nfserr); | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * With NFSv3, CREATE processing is a lot easier than with NFSv2. | ||
215 | * At least in theory; we'll see how it fares in practice when the | ||
216 | * first reports about SunOS compatibility problems start to pour in... | ||
217 | */ | ||
218 | static int | ||
219 | nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, | ||
220 | struct nfsd3_diropres *resp) | ||
221 | { | ||
222 | svc_fh *dirfhp, *newfhp = NULL; | ||
223 | struct iattr *attr; | ||
224 | u32 nfserr; | ||
225 | |||
226 | dprintk("nfsd: CREATE(3) %s %.*s\n", | ||
227 | SVCFH_fmt(&argp->fh), | ||
228 | argp->len, | ||
229 | argp->name); | ||
230 | |||
231 | dirfhp = fh_copy(&resp->dirfh, &argp->fh); | ||
232 | newfhp = fh_init(&resp->fh, NFS3_FHSIZE); | ||
233 | attr = &argp->attrs; | ||
234 | |||
235 | /* Get the directory inode */ | ||
236 | nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE); | ||
237 | if (nfserr) | ||
238 | RETURN_STATUS(nfserr); | ||
239 | |||
240 | /* Unfudge the mode bits */ | ||
241 | attr->ia_mode &= ~S_IFMT; | ||
242 | if (!(attr->ia_valid & ATTR_MODE)) { | ||
243 | attr->ia_valid |= ATTR_MODE; | ||
244 | attr->ia_mode = S_IFREG; | ||
245 | } else { | ||
246 | attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG; | ||
247 | } | ||
248 | |||
249 | /* Now create the file and set attributes */ | ||
250 | nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len, | ||
251 | attr, newfhp, | ||
252 | argp->createmode, argp->verf, NULL); | ||
253 | |||
254 | RETURN_STATUS(nfserr); | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Make directory. This operation is not idempotent. | ||
259 | */ | ||
260 | static int | ||
261 | nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, | ||
262 | struct nfsd3_diropres *resp) | ||
263 | { | ||
264 | int nfserr; | ||
265 | |||
266 | dprintk("nfsd: MKDIR(3) %s %.*s\n", | ||
267 | SVCFH_fmt(&argp->fh), | ||
268 | argp->len, | ||
269 | argp->name); | ||
270 | |||
271 | argp->attrs.ia_valid &= ~ATTR_SIZE; | ||
272 | fh_copy(&resp->dirfh, &argp->fh); | ||
273 | fh_init(&resp->fh, NFS3_FHSIZE); | ||
274 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, | ||
275 | &argp->attrs, S_IFDIR, 0, &resp->fh); | ||
276 | |||
277 | RETURN_STATUS(nfserr); | ||
278 | } | ||
279 | |||
280 | static int | ||
281 | nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp, | ||
282 | struct nfsd3_diropres *resp) | ||
283 | { | ||
284 | int nfserr; | ||
285 | |||
286 | dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n", | ||
287 | SVCFH_fmt(&argp->ffh), | ||
288 | argp->flen, argp->fname, | ||
289 | argp->tlen, argp->tname); | ||
290 | |||
291 | fh_copy(&resp->dirfh, &argp->ffh); | ||
292 | fh_init(&resp->fh, NFS3_FHSIZE); | ||
293 | nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, | ||
294 | argp->tname, argp->tlen, | ||
295 | &resp->fh, &argp->attrs); | ||
296 | RETURN_STATUS(nfserr); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Make socket/fifo/device. | ||
301 | */ | ||
302 | static int | ||
303 | nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, | ||
304 | struct nfsd3_diropres *resp) | ||
305 | { | ||
306 | int nfserr, type; | ||
307 | dev_t rdev = 0; | ||
308 | |||
309 | dprintk("nfsd: MKNOD(3) %s %.*s\n", | ||
310 | SVCFH_fmt(&argp->fh), | ||
311 | argp->len, | ||
312 | argp->name); | ||
313 | |||
314 | fh_copy(&resp->dirfh, &argp->fh); | ||
315 | fh_init(&resp->fh, NFS3_FHSIZE); | ||
316 | |||
317 | if (argp->ftype == 0 || argp->ftype >= NF3BAD) | ||
318 | RETURN_STATUS(nfserr_inval); | ||
319 | if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) { | ||
320 | rdev = MKDEV(argp->major, argp->minor); | ||
321 | if (MAJOR(rdev) != argp->major || | ||
322 | MINOR(rdev) != argp->minor) | ||
323 | RETURN_STATUS(nfserr_inval); | ||
324 | } else | ||
325 | if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) | ||
326 | RETURN_STATUS(nfserr_inval); | ||
327 | |||
328 | type = nfs3_ftypes[argp->ftype]; | ||
329 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, | ||
330 | &argp->attrs, type, rdev, &resp->fh); | ||
331 | |||
332 | RETURN_STATUS(nfserr); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * Remove file/fifo/socket etc. | ||
337 | */ | ||
338 | static int | ||
339 | nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, | ||
340 | struct nfsd3_attrstat *resp) | ||
341 | { | ||
342 | int nfserr; | ||
343 | |||
344 | dprintk("nfsd: REMOVE(3) %s %.*s\n", | ||
345 | SVCFH_fmt(&argp->fh), | ||
346 | argp->len, | ||
347 | argp->name); | ||
348 | |||
349 | /* Unlink. -S_IFDIR means file must not be a directory */ | ||
350 | fh_copy(&resp->fh, &argp->fh); | ||
351 | nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); | ||
352 | RETURN_STATUS(nfserr); | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * Remove a directory | ||
357 | */ | ||
358 | static int | ||
359 | nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, | ||
360 | struct nfsd3_attrstat *resp) | ||
361 | { | ||
362 | int nfserr; | ||
363 | |||
364 | dprintk("nfsd: RMDIR(3) %s %.*s\n", | ||
365 | SVCFH_fmt(&argp->fh), | ||
366 | argp->len, | ||
367 | argp->name); | ||
368 | |||
369 | fh_copy(&resp->fh, &argp->fh); | ||
370 | nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); | ||
371 | RETURN_STATUS(nfserr); | ||
372 | } | ||
373 | |||
374 | static int | ||
375 | nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp, | ||
376 | struct nfsd3_renameres *resp) | ||
377 | { | ||
378 | int nfserr; | ||
379 | |||
380 | dprintk("nfsd: RENAME(3) %s %.*s ->\n", | ||
381 | SVCFH_fmt(&argp->ffh), | ||
382 | argp->flen, | ||
383 | argp->fname); | ||
384 | dprintk("nfsd: -> %s %.*s\n", | ||
385 | SVCFH_fmt(&argp->tfh), | ||
386 | argp->tlen, | ||
387 | argp->tname); | ||
388 | |||
389 | fh_copy(&resp->ffh, &argp->ffh); | ||
390 | fh_copy(&resp->tfh, &argp->tfh); | ||
391 | nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, | ||
392 | &resp->tfh, argp->tname, argp->tlen); | ||
393 | RETURN_STATUS(nfserr); | ||
394 | } | ||
395 | |||
396 | static int | ||
397 | nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp, | ||
398 | struct nfsd3_linkres *resp) | ||
399 | { | ||
400 | int nfserr; | ||
401 | |||
402 | dprintk("nfsd: LINK(3) %s ->\n", | ||
403 | SVCFH_fmt(&argp->ffh)); | ||
404 | dprintk("nfsd: -> %s %.*s\n", | ||
405 | SVCFH_fmt(&argp->tfh), | ||
406 | argp->tlen, | ||
407 | argp->tname); | ||
408 | |||
409 | fh_copy(&resp->fh, &argp->ffh); | ||
410 | fh_copy(&resp->tfh, &argp->tfh); | ||
411 | nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, | ||
412 | &resp->fh); | ||
413 | RETURN_STATUS(nfserr); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * Read a portion of a directory. | ||
418 | */ | ||
419 | static int | ||
420 | nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, | ||
421 | struct nfsd3_readdirres *resp) | ||
422 | { | ||
423 | int nfserr, count; | ||
424 | |||
425 | dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", | ||
426 | SVCFH_fmt(&argp->fh), | ||
427 | argp->count, (u32) argp->cookie); | ||
428 | |||
429 | /* Make sure we've room for the NULL ptr & eof flag, and shrink to | ||
430 | * client read size */ | ||
431 | count = (argp->count >> 2) - 2; | ||
432 | |||
433 | /* Read directory and encode entries on the fly */ | ||
434 | fh_copy(&resp->fh, &argp->fh); | ||
435 | |||
436 | resp->buflen = count; | ||
437 | resp->common.err = nfs_ok; | ||
438 | resp->buffer = argp->buffer; | ||
439 | resp->rqstp = rqstp; | ||
440 | nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, | ||
441 | &resp->common, nfs3svc_encode_entry); | ||
442 | memcpy(resp->verf, argp->verf, 8); | ||
443 | resp->count = resp->buffer - argp->buffer; | ||
444 | if (resp->offset) | ||
445 | xdr_encode_hyper(resp->offset, argp->cookie); | ||
446 | |||
447 | RETURN_STATUS(nfserr); | ||
448 | } | ||
449 | |||
450 | /* | ||
451 | * Read a portion of a directory, including file handles and attrs. | ||
452 | * For now, we choose to ignore the dircount parameter. | ||
453 | */ | ||
454 | static int | ||
455 | nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, | ||
456 | struct nfsd3_readdirres *resp) | ||
457 | { | ||
458 | int nfserr, count = 0; | ||
459 | loff_t offset; | ||
460 | int i; | ||
461 | caddr_t page_addr = NULL; | ||
462 | |||
463 | dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n", | ||
464 | SVCFH_fmt(&argp->fh), | ||
465 | argp->count, (u32) argp->cookie); | ||
466 | |||
467 | /* Convert byte count to number of words (i.e. >> 2), | ||
468 | * and reserve room for the NULL ptr & eof flag (-2 words) */ | ||
469 | resp->count = (argp->count >> 2) - 2; | ||
470 | |||
471 | /* Read directory and encode entries on the fly */ | ||
472 | fh_copy(&resp->fh, &argp->fh); | ||
473 | |||
474 | resp->common.err = nfs_ok; | ||
475 | resp->buffer = argp->buffer; | ||
476 | resp->buflen = resp->count; | ||
477 | resp->rqstp = rqstp; | ||
478 | offset = argp->cookie; | ||
479 | nfserr = nfsd_readdir(rqstp, &resp->fh, | ||
480 | &offset, | ||
481 | &resp->common, | ||
482 | nfs3svc_encode_entry_plus); | ||
483 | memcpy(resp->verf, argp->verf, 8); | ||
484 | for (i=1; i<rqstp->rq_resused ; i++) { | ||
485 | page_addr = page_address(rqstp->rq_respages[i]); | ||
486 | |||
487 | if (((caddr_t)resp->buffer >= page_addr) && | ||
488 | ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { | ||
489 | count += (caddr_t)resp->buffer - page_addr; | ||
490 | break; | ||
491 | } | ||
492 | count += PAGE_SIZE; | ||
493 | } | ||
494 | resp->count = count >> 2; | ||
495 | if (resp->offset) { | ||
496 | if (unlikely(resp->offset1)) { | ||
497 | /* we ended up with offset on a page boundary */ | ||
498 | *resp->offset = htonl(offset >> 32); | ||
499 | *resp->offset1 = htonl(offset & 0xffffffff); | ||
500 | resp->offset1 = NULL; | ||
501 | } else { | ||
502 | xdr_encode_hyper(resp->offset, offset); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | RETURN_STATUS(nfserr); | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * Get file system stats | ||
511 | */ | ||
512 | static int | ||
513 | nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | ||
514 | struct nfsd3_fsstatres *resp) | ||
515 | { | ||
516 | int nfserr; | ||
517 | |||
518 | dprintk("nfsd: FSSTAT(3) %s\n", | ||
519 | SVCFH_fmt(&argp->fh)); | ||
520 | |||
521 | nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); | ||
522 | fh_put(&argp->fh); | ||
523 | RETURN_STATUS(nfserr); | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * Get file system info | ||
528 | */ | ||
529 | static int | ||
530 | nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | ||
531 | struct nfsd3_fsinfores *resp) | ||
532 | { | ||
533 | int nfserr; | ||
534 | |||
535 | dprintk("nfsd: FSINFO(3) %s\n", | ||
536 | SVCFH_fmt(&argp->fh)); | ||
537 | |||
538 | resp->f_rtmax = NFSSVC_MAXBLKSIZE; | ||
539 | resp->f_rtpref = NFSSVC_MAXBLKSIZE; | ||
540 | resp->f_rtmult = PAGE_SIZE; | ||
541 | resp->f_wtmax = NFSSVC_MAXBLKSIZE; | ||
542 | resp->f_wtpref = NFSSVC_MAXBLKSIZE; | ||
543 | resp->f_wtmult = PAGE_SIZE; | ||
544 | resp->f_dtpref = PAGE_SIZE; | ||
545 | resp->f_maxfilesize = ~(u32) 0; | ||
546 | resp->f_properties = NFS3_FSF_DEFAULT; | ||
547 | |||
548 | nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); | ||
549 | |||
550 | /* Check special features of the file system. May request | ||
551 | * different read/write sizes for file systems known to have | ||
552 | * problems with large blocks */ | ||
553 | if (nfserr == 0) { | ||
554 | struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; | ||
555 | |||
556 | /* Note that we don't care for remote fs's here */ | ||
557 | if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) { | ||
558 | resp->f_properties = NFS3_FSF_BILLYBOY; | ||
559 | } | ||
560 | resp->f_maxfilesize = sb->s_maxbytes; | ||
561 | } | ||
562 | |||
563 | fh_put(&argp->fh); | ||
564 | RETURN_STATUS(nfserr); | ||
565 | } | ||
566 | |||
567 | /* | ||
568 | * Get pathconf info for the specified file | ||
569 | */ | ||
570 | static int | ||
571 | nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | ||
572 | struct nfsd3_pathconfres *resp) | ||
573 | { | ||
574 | int nfserr; | ||
575 | |||
576 | dprintk("nfsd: PATHCONF(3) %s\n", | ||
577 | SVCFH_fmt(&argp->fh)); | ||
578 | |||
579 | /* Set default pathconf */ | ||
580 | resp->p_link_max = 255; /* at least */ | ||
581 | resp->p_name_max = 255; /* at least */ | ||
582 | resp->p_no_trunc = 0; | ||
583 | resp->p_chown_restricted = 1; | ||
584 | resp->p_case_insensitive = 0; | ||
585 | resp->p_case_preserving = 1; | ||
586 | |||
587 | nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP); | ||
588 | |||
589 | if (nfserr == 0) { | ||
590 | struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb; | ||
591 | |||
592 | /* Note that we don't care for remote fs's here */ | ||
593 | switch (sb->s_magic) { | ||
594 | case EXT2_SUPER_MAGIC: | ||
595 | resp->p_link_max = EXT2_LINK_MAX; | ||
596 | resp->p_name_max = EXT2_NAME_LEN; | ||
597 | break; | ||
598 | case 0x4d44: /* MSDOS_SUPER_MAGIC */ | ||
599 | resp->p_case_insensitive = 1; | ||
600 | resp->p_case_preserving = 0; | ||
601 | break; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | fh_put(&argp->fh); | ||
606 | RETURN_STATUS(nfserr); | ||
607 | } | ||
608 | |||
609 | |||
610 | /* | ||
611 | * Commit a file (range) to stable storage. | ||
612 | */ | ||
613 | static int | ||
614 | nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, | ||
615 | struct nfsd3_commitres *resp) | ||
616 | { | ||
617 | int nfserr; | ||
618 | |||
619 | dprintk("nfsd: COMMIT(3) %s %u@%Lu\n", | ||
620 | SVCFH_fmt(&argp->fh), | ||
621 | argp->count, | ||
622 | (unsigned long long) argp->offset); | ||
623 | |||
624 | if (argp->offset > NFS_OFFSET_MAX) | ||
625 | RETURN_STATUS(nfserr_inval); | ||
626 | |||
627 | fh_copy(&resp->fh, &argp->fh); | ||
628 | nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count); | ||
629 | |||
630 | RETURN_STATUS(nfserr); | ||
631 | } | ||
632 | |||
633 | |||
634 | /* | ||
635 | * NFSv3 Server procedures. | ||
636 | * Only the results of non-idempotent operations are cached. | ||
637 | */ | ||
638 | #define nfs3svc_decode_voidargs NULL | ||
639 | #define nfs3svc_release_void NULL | ||
640 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle | ||
641 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat | ||
642 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat | ||
643 | #define nfsd3_mkdirargs nfsd3_createargs | ||
644 | #define nfsd3_readdirplusargs nfsd3_readdirargs | ||
645 | #define nfsd3_fhandleargs nfsd_fhandle | ||
646 | #define nfsd3_fhandleres nfsd3_attrstat | ||
647 | #define nfsd3_attrstatres nfsd3_attrstat | ||
648 | #define nfsd3_wccstatres nfsd3_attrstat | ||
649 | #define nfsd3_createres nfsd3_diropres | ||
650 | #define nfsd3_voidres nfsd3_voidargs | ||
651 | struct nfsd3_voidargs { int dummy; }; | ||
652 | |||
653 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
654 | { (svc_procfunc) nfsd3_proc_##name, \ | ||
655 | (kxdrproc_t) nfs3svc_decode_##argt##args, \ | ||
656 | (kxdrproc_t) nfs3svc_encode_##rest##res, \ | ||
657 | (kxdrproc_t) nfs3svc_release_##relt, \ | ||
658 | sizeof(struct nfsd3_##argt##args), \ | ||
659 | sizeof(struct nfsd3_##rest##res), \ | ||
660 | 0, \ | ||
661 | cache, \ | ||
662 | respsize, \ | ||
663 | } | ||
664 | |||
665 | #define ST 1 /* status*/ | ||
666 | #define FH 17 /* filehandle with length */ | ||
667 | #define AT 21 /* attributes */ | ||
668 | #define pAT (1+AT) /* post attributes - conditional */ | ||
669 | #define WC (7+pAT) /* WCC attributes */ | ||
670 | |||
671 | static struct svc_procedure nfsd_procedures3[22] = { | ||
672 | PROC(null, void, void, void, RC_NOCACHE, ST), | ||
673 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | ||
674 | PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), | ||
675 | PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), | ||
676 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), | ||
677 | PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), | ||
678 | PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE), | ||
679 | PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), | ||
680 | PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | ||
681 | PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | ||
682 | PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | ||
683 | PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | ||
684 | PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | ||
685 | PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | ||
686 | PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, ST+WC+WC), | ||
687 | PROC(link, link, link, fhandle2, RC_REPLBUFF, ST+pAT+WC), | ||
688 | PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), | ||
689 | PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), | ||
690 | PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, ST+pAT+2*6+1), | ||
691 | PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, ST+pAT+12), | ||
692 | PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, ST+pAT+6), | ||
693 | PROC(commit, commit, commit, fhandle, RC_NOCACHE, ST+WC+2), | ||
694 | }; | ||
695 | |||
696 | struct svc_version nfsd_version3 = { | ||
697 | .vs_vers = 3, | ||
698 | .vs_nproc = 22, | ||
699 | .vs_proc = nfsd_procedures3, | ||
700 | .vs_dispatch = nfsd_dispatch, | ||
701 | .vs_xdrsize = NFS3_SVC_XDRSIZE, | ||
702 | }; | ||