diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 381 |
1 files changed, 213 insertions, 168 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 443ebc52e382..f21e917bb8ed 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/nfsd_idmap.h> | 54 | #include <linux/nfsd_idmap.h> |
55 | #include <linux/security.h> | 55 | #include <linux/security.h> |
56 | #endif /* CONFIG_NFSD_V4 */ | 56 | #endif /* CONFIG_NFSD_V4 */ |
57 | #include <linux/jhash.h> | ||
57 | 58 | ||
58 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
59 | 60 | ||
@@ -81,10 +82,19 @@ struct raparms { | |||
81 | dev_t p_dev; | 82 | dev_t p_dev; |
82 | int p_set; | 83 | int p_set; |
83 | struct file_ra_state p_ra; | 84 | struct file_ra_state p_ra; |
85 | unsigned int p_hindex; | ||
84 | }; | 86 | }; |
85 | 87 | ||
88 | struct raparm_hbucket { | ||
89 | struct raparms *pb_head; | ||
90 | spinlock_t pb_lock; | ||
91 | } ____cacheline_aligned_in_smp; | ||
92 | |||
86 | static struct raparms * raparml; | 93 | static struct raparms * raparml; |
87 | static struct raparms * raparm_cache; | 94 | #define RAPARM_HASH_BITS 4 |
95 | #define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS) | ||
96 | #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) | ||
97 | static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; | ||
88 | 98 | ||
89 | /* | 99 | /* |
90 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed | 100 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed |
@@ -100,7 +110,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
100 | struct dentry *dentry = *dpp; | 110 | struct dentry *dentry = *dpp; |
101 | struct vfsmount *mnt = mntget(exp->ex_mnt); | 111 | struct vfsmount *mnt = mntget(exp->ex_mnt); |
102 | struct dentry *mounts = dget(dentry); | 112 | struct dentry *mounts = dget(dentry); |
103 | int err = nfs_ok; | 113 | int err = 0; |
104 | 114 | ||
105 | while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); | 115 | while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); |
106 | 116 | ||
@@ -138,14 +148,15 @@ out: | |||
138 | * clients and is explicitly disallowed for NFSv3 | 148 | * clients and is explicitly disallowed for NFSv3 |
139 | * NeilBrown <neilb@cse.unsw.edu.au> | 149 | * NeilBrown <neilb@cse.unsw.edu.au> |
140 | */ | 150 | */ |
141 | int | 151 | __be32 |
142 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | 152 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, |
143 | int len, struct svc_fh *resfh) | 153 | int len, struct svc_fh *resfh) |
144 | { | 154 | { |
145 | struct svc_export *exp; | 155 | struct svc_export *exp; |
146 | struct dentry *dparent; | 156 | struct dentry *dparent; |
147 | struct dentry *dentry; | 157 | struct dentry *dentry; |
148 | int err; | 158 | __be32 err; |
159 | int host_err; | ||
149 | 160 | ||
150 | dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); | 161 | dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); |
151 | 162 | ||
@@ -183,7 +194,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
183 | exp2 = exp_parent(exp->ex_client, mnt, dentry, | 194 | exp2 = exp_parent(exp->ex_client, mnt, dentry, |
184 | &rqstp->rq_chandle); | 195 | &rqstp->rq_chandle); |
185 | if (IS_ERR(exp2)) { | 196 | if (IS_ERR(exp2)) { |
186 | err = PTR_ERR(exp2); | 197 | host_err = PTR_ERR(exp2); |
187 | dput(dentry); | 198 | dput(dentry); |
188 | mntput(mnt); | 199 | mntput(mnt); |
189 | goto out_nfserr; | 200 | goto out_nfserr; |
@@ -200,14 +211,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
200 | } else { | 211 | } else { |
201 | fh_lock(fhp); | 212 | fh_lock(fhp); |
202 | dentry = lookup_one_len(name, dparent, len); | 213 | dentry = lookup_one_len(name, dparent, len); |
203 | err = PTR_ERR(dentry); | 214 | host_err = PTR_ERR(dentry); |
204 | if (IS_ERR(dentry)) | 215 | if (IS_ERR(dentry)) |
205 | goto out_nfserr; | 216 | goto out_nfserr; |
206 | /* | 217 | /* |
207 | * check if we have crossed a mount point ... | 218 | * check if we have crossed a mount point ... |
208 | */ | 219 | */ |
209 | if (d_mountpoint(dentry)) { | 220 | if (d_mountpoint(dentry)) { |
210 | if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { | 221 | if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { |
211 | dput(dentry); | 222 | dput(dentry); |
212 | goto out_nfserr; | 223 | goto out_nfserr; |
213 | } | 224 | } |
@@ -226,7 +237,7 @@ out: | |||
226 | return err; | 237 | return err; |
227 | 238 | ||
228 | out_nfserr: | 239 | out_nfserr: |
229 | err = nfserrno(err); | 240 | err = nfserrno(host_err); |
230 | goto out; | 241 | goto out; |
231 | } | 242 | } |
232 | 243 | ||
@@ -234,7 +245,7 @@ out_nfserr: | |||
234 | * Set various file attributes. | 245 | * Set various file attributes. |
235 | * N.B. After this call fhp needs an fh_put | 246 | * N.B. After this call fhp needs an fh_put |
236 | */ | 247 | */ |
237 | int | 248 | __be32 |
238 | nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | 249 | nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, |
239 | int check_guard, time_t guardtime) | 250 | int check_guard, time_t guardtime) |
240 | { | 251 | { |
@@ -243,7 +254,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
243 | int accmode = MAY_SATTR; | 254 | int accmode = MAY_SATTR; |
244 | int ftype = 0; | 255 | int ftype = 0; |
245 | int imode; | 256 | int imode; |
246 | int err; | 257 | __be32 err; |
258 | int host_err; | ||
247 | int size_change = 0; | 259 | int size_change = 0; |
248 | 260 | ||
249 | if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) | 261 | if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) |
@@ -309,19 +321,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
309 | * If we are changing the size of the file, then | 321 | * If we are changing the size of the file, then |
310 | * we need to break all leases. | 322 | * we need to break all leases. |
311 | */ | 323 | */ |
312 | err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); | 324 | host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); |
313 | if (err == -EWOULDBLOCK) | 325 | if (host_err == -EWOULDBLOCK) |
314 | err = -ETIMEDOUT; | 326 | host_err = -ETIMEDOUT; |
315 | if (err) /* ENOMEM or EWOULDBLOCK */ | 327 | if (host_err) /* ENOMEM or EWOULDBLOCK */ |
316 | goto out_nfserr; | 328 | goto out_nfserr; |
317 | 329 | ||
318 | err = get_write_access(inode); | 330 | host_err = get_write_access(inode); |
319 | if (err) | 331 | if (host_err) |
320 | goto out_nfserr; | 332 | goto out_nfserr; |
321 | 333 | ||
322 | size_change = 1; | 334 | size_change = 1; |
323 | err = locks_verify_truncate(inode, NULL, iap->ia_size); | 335 | host_err = locks_verify_truncate(inode, NULL, iap->ia_size); |
324 | if (err) { | 336 | if (host_err) { |
325 | put_write_access(inode); | 337 | put_write_access(inode); |
326 | goto out_nfserr; | 338 | goto out_nfserr; |
327 | } | 339 | } |
@@ -347,8 +359,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
347 | err = nfserr_notsync; | 359 | err = nfserr_notsync; |
348 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { | 360 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { |
349 | fh_lock(fhp); | 361 | fh_lock(fhp); |
350 | err = notify_change(dentry, iap); | 362 | host_err = notify_change(dentry, iap); |
351 | err = nfserrno(err); | 363 | err = nfserrno(host_err); |
352 | fh_unlock(fhp); | 364 | fh_unlock(fhp); |
353 | } | 365 | } |
354 | if (size_change) | 366 | if (size_change) |
@@ -360,7 +372,7 @@ out: | |||
360 | return err; | 372 | return err; |
361 | 373 | ||
362 | out_nfserr: | 374 | out_nfserr: |
363 | err = nfserrno(err); | 375 | err = nfserrno(host_err); |
364 | goto out; | 376 | goto out; |
365 | } | 377 | } |
366 | 378 | ||
@@ -410,11 +422,12 @@ out: | |||
410 | return error; | 422 | return error; |
411 | } | 423 | } |
412 | 424 | ||
413 | int | 425 | __be32 |
414 | nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | 426 | nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, |
415 | struct nfs4_acl *acl) | 427 | struct nfs4_acl *acl) |
416 | { | 428 | { |
417 | int error; | 429 | __be32 error; |
430 | int host_error; | ||
418 | struct dentry *dentry; | 431 | struct dentry *dentry; |
419 | struct inode *inode; | 432 | struct inode *inode; |
420 | struct posix_acl *pacl = NULL, *dpacl = NULL; | 433 | struct posix_acl *pacl = NULL, *dpacl = NULL; |
@@ -430,22 +443,20 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
430 | if (S_ISDIR(inode->i_mode)) | 443 | if (S_ISDIR(inode->i_mode)) |
431 | flags = NFS4_ACL_DIR; | 444 | flags = NFS4_ACL_DIR; |
432 | 445 | ||
433 | error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); | 446 | host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); |
434 | if (error == -EINVAL) { | 447 | if (host_error == -EINVAL) { |
435 | error = nfserr_attrnotsupp; | 448 | error = nfserr_attrnotsupp; |
436 | goto out; | 449 | goto out; |
437 | } else if (error < 0) | 450 | } else if (host_error < 0) |
438 | goto out_nfserr; | 451 | goto out_nfserr; |
439 | 452 | ||
440 | if (pacl) { | 453 | host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); |
441 | error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); | 454 | if (host_error < 0) |
442 | if (error < 0) | 455 | goto out_nfserr; |
443 | goto out_nfserr; | ||
444 | } | ||
445 | 456 | ||
446 | if (dpacl) { | 457 | if (S_ISDIR(inode->i_mode)) { |
447 | error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); | 458 | host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); |
448 | if (error < 0) | 459 | if (host_error < 0) |
449 | goto out_nfserr; | 460 | goto out_nfserr; |
450 | } | 461 | } |
451 | 462 | ||
@@ -456,7 +467,7 @@ out: | |||
456 | posix_acl_release(dpacl); | 467 | posix_acl_release(dpacl); |
457 | return (error); | 468 | return (error); |
458 | out_nfserr: | 469 | out_nfserr: |
459 | error = nfserrno(error); | 470 | error = nfserrno(host_error); |
460 | goto out; | 471 | goto out; |
461 | } | 472 | } |
462 | 473 | ||
@@ -563,14 +574,14 @@ static struct accessmap nfs3_anyaccess[] = { | |||
563 | { 0, 0 } | 574 | { 0, 0 } |
564 | }; | 575 | }; |
565 | 576 | ||
566 | int | 577 | __be32 |
567 | nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported) | 578 | nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported) |
568 | { | 579 | { |
569 | struct accessmap *map; | 580 | struct accessmap *map; |
570 | struct svc_export *export; | 581 | struct svc_export *export; |
571 | struct dentry *dentry; | 582 | struct dentry *dentry; |
572 | u32 query, result = 0, sresult = 0; | 583 | u32 query, result = 0, sresult = 0; |
573 | unsigned int error; | 584 | __be32 error; |
574 | 585 | ||
575 | error = fh_verify(rqstp, fhp, 0, MAY_NOP); | 586 | error = fh_verify(rqstp, fhp, 0, MAY_NOP); |
576 | if (error) | 587 | if (error) |
@@ -590,7 +601,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor | |||
590 | query = *access; | 601 | query = *access; |
591 | for (; map->access; map++) { | 602 | for (; map->access; map++) { |
592 | if (map->access & query) { | 603 | if (map->access & query) { |
593 | unsigned int err2; | 604 | __be32 err2; |
594 | 605 | ||
595 | sresult |= map->access; | 606 | sresult |= map->access; |
596 | 607 | ||
@@ -629,13 +640,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor | |||
629 | * The access argument indicates the type of open (read/write/lock) | 640 | * The access argument indicates the type of open (read/write/lock) |
630 | * N.B. After this call fhp needs an fh_put | 641 | * N.B. After this call fhp needs an fh_put |
631 | */ | 642 | */ |
632 | int | 643 | __be32 |
633 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | 644 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, |
634 | int access, struct file **filp) | 645 | int access, struct file **filp) |
635 | { | 646 | { |
636 | struct dentry *dentry; | 647 | struct dentry *dentry; |
637 | struct inode *inode; | 648 | struct inode *inode; |
638 | int flags = O_RDONLY|O_LARGEFILE, err; | 649 | int flags = O_RDONLY|O_LARGEFILE; |
650 | __be32 err; | ||
651 | int host_err; | ||
639 | 652 | ||
640 | /* | 653 | /* |
641 | * If we get here, then the client has already done an "open", | 654 | * If we get here, then the client has already done an "open", |
@@ -665,10 +678,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
665 | * Check to see if there are any leases on this file. | 678 | * Check to see if there are any leases on this file. |
666 | * This may block while leases are broken. | 679 | * This may block while leases are broken. |
667 | */ | 680 | */ |
668 | err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); | 681 | host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); |
669 | if (err == -EWOULDBLOCK) | 682 | if (host_err == -EWOULDBLOCK) |
670 | err = -ETIMEDOUT; | 683 | host_err = -ETIMEDOUT; |
671 | if (err) /* NOMEM or WOULDBLOCK */ | 684 | if (host_err) /* NOMEM or WOULDBLOCK */ |
672 | goto out_nfserr; | 685 | goto out_nfserr; |
673 | 686 | ||
674 | if (access & MAY_WRITE) { | 687 | if (access & MAY_WRITE) { |
@@ -681,10 +694,9 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
681 | } | 694 | } |
682 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags); | 695 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags); |
683 | if (IS_ERR(*filp)) | 696 | if (IS_ERR(*filp)) |
684 | err = PTR_ERR(*filp); | 697 | host_err = PTR_ERR(*filp); |
685 | out_nfserr: | 698 | out_nfserr: |
686 | if (err) | 699 | err = nfserrno(host_err); |
687 | err = nfserrno(err); | ||
688 | out: | 700 | out: |
689 | return err; | 701 | return err; |
690 | } | 702 | } |
@@ -743,16 +755,20 @@ nfsd_sync_dir(struct dentry *dp) | |||
743 | * Obtain the readahead parameters for the file | 755 | * Obtain the readahead parameters for the file |
744 | * specified by (dev, ino). | 756 | * specified by (dev, ino). |
745 | */ | 757 | */ |
746 | static DEFINE_SPINLOCK(ra_lock); | ||
747 | 758 | ||
748 | static inline struct raparms * | 759 | static inline struct raparms * |
749 | nfsd_get_raparms(dev_t dev, ino_t ino) | 760 | nfsd_get_raparms(dev_t dev, ino_t ino) |
750 | { | 761 | { |
751 | struct raparms *ra, **rap, **frap = NULL; | 762 | struct raparms *ra, **rap, **frap = NULL; |
752 | int depth = 0; | 763 | int depth = 0; |
764 | unsigned int hash; | ||
765 | struct raparm_hbucket *rab; | ||
753 | 766 | ||
754 | spin_lock(&ra_lock); | 767 | hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK; |
755 | for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) { | 768 | rab = &raparm_hash[hash]; |
769 | |||
770 | spin_lock(&rab->pb_lock); | ||
771 | for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) { | ||
756 | if (ra->p_ino == ino && ra->p_dev == dev) | 772 | if (ra->p_ino == ino && ra->p_dev == dev) |
757 | goto found; | 773 | goto found; |
758 | depth++; | 774 | depth++; |
@@ -761,7 +777,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino) | |||
761 | } | 777 | } |
762 | depth = nfsdstats.ra_size*11/10; | 778 | depth = nfsdstats.ra_size*11/10; |
763 | if (!frap) { | 779 | if (!frap) { |
764 | spin_unlock(&ra_lock); | 780 | spin_unlock(&rab->pb_lock); |
765 | return NULL; | 781 | return NULL; |
766 | } | 782 | } |
767 | rap = frap; | 783 | rap = frap; |
@@ -769,15 +785,16 @@ nfsd_get_raparms(dev_t dev, ino_t ino) | |||
769 | ra->p_dev = dev; | 785 | ra->p_dev = dev; |
770 | ra->p_ino = ino; | 786 | ra->p_ino = ino; |
771 | ra->p_set = 0; | 787 | ra->p_set = 0; |
788 | ra->p_hindex = hash; | ||
772 | found: | 789 | found: |
773 | if (rap != &raparm_cache) { | 790 | if (rap != &rab->pb_head) { |
774 | *rap = ra->p_next; | 791 | *rap = ra->p_next; |
775 | ra->p_next = raparm_cache; | 792 | ra->p_next = rab->pb_head; |
776 | raparm_cache = ra; | 793 | rab->pb_head = ra; |
777 | } | 794 | } |
778 | ra->p_count++; | 795 | ra->p_count++; |
779 | nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; | 796 | nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; |
780 | spin_unlock(&ra_lock); | 797 | spin_unlock(&rab->pb_lock); |
781 | return ra; | 798 | return ra; |
782 | } | 799 | } |
783 | 800 | ||
@@ -791,36 +808,41 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset | |||
791 | { | 808 | { |
792 | unsigned long count = desc->count; | 809 | unsigned long count = desc->count; |
793 | struct svc_rqst *rqstp = desc->arg.data; | 810 | struct svc_rqst *rqstp = desc->arg.data; |
811 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; | ||
794 | 812 | ||
795 | if (size > count) | 813 | if (size > count) |
796 | size = count; | 814 | size = count; |
797 | 815 | ||
798 | if (rqstp->rq_res.page_len == 0) { | 816 | if (rqstp->rq_res.page_len == 0) { |
799 | get_page(page); | 817 | get_page(page); |
800 | rqstp->rq_respages[rqstp->rq_resused++] = page; | 818 | put_page(*pp); |
819 | *pp = page; | ||
820 | rqstp->rq_resused++; | ||
801 | rqstp->rq_res.page_base = offset; | 821 | rqstp->rq_res.page_base = offset; |
802 | rqstp->rq_res.page_len = size; | 822 | rqstp->rq_res.page_len = size; |
803 | } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) { | 823 | } else if (page != pp[-1]) { |
804 | get_page(page); | 824 | get_page(page); |
805 | rqstp->rq_respages[rqstp->rq_resused++] = page; | 825 | put_page(*pp); |
826 | *pp = page; | ||
827 | rqstp->rq_resused++; | ||
806 | rqstp->rq_res.page_len += size; | 828 | rqstp->rq_res.page_len += size; |
807 | } else { | 829 | } else |
808 | rqstp->rq_res.page_len += size; | 830 | rqstp->rq_res.page_len += size; |
809 | } | ||
810 | 831 | ||
811 | desc->count = count - size; | 832 | desc->count = count - size; |
812 | desc->written += size; | 833 | desc->written += size; |
813 | return size; | 834 | return size; |
814 | } | 835 | } |
815 | 836 | ||
816 | static int | 837 | static __be32 |
817 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 838 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
818 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 839 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
819 | { | 840 | { |
820 | struct inode *inode; | 841 | struct inode *inode; |
821 | struct raparms *ra; | 842 | struct raparms *ra; |
822 | mm_segment_t oldfs; | 843 | mm_segment_t oldfs; |
823 | int err; | 844 | __be32 err; |
845 | int host_err; | ||
824 | 846 | ||
825 | err = nfserr_perm; | 847 | err = nfserr_perm; |
826 | inode = file->f_dentry->d_inode; | 848 | inode = file->f_dentry->d_inode; |
@@ -837,32 +859,33 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
837 | file->f_ra = ra->p_ra; | 859 | file->f_ra = ra->p_ra; |
838 | 860 | ||
839 | if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { | 861 | if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { |
840 | svc_pushback_unused_pages(rqstp); | 862 | rqstp->rq_resused = 1; |
841 | err = file->f_op->sendfile(file, &offset, *count, | 863 | host_err = file->f_op->sendfile(file, &offset, *count, |
842 | nfsd_read_actor, rqstp); | 864 | nfsd_read_actor, rqstp); |
843 | } else { | 865 | } else { |
844 | oldfs = get_fs(); | 866 | oldfs = get_fs(); |
845 | set_fs(KERNEL_DS); | 867 | set_fs(KERNEL_DS); |
846 | err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); | 868 | host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); |
847 | set_fs(oldfs); | 869 | set_fs(oldfs); |
848 | } | 870 | } |
849 | 871 | ||
850 | /* Write back readahead params */ | 872 | /* Write back readahead params */ |
851 | if (ra) { | 873 | if (ra) { |
852 | spin_lock(&ra_lock); | 874 | struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; |
875 | spin_lock(&rab->pb_lock); | ||
853 | ra->p_ra = file->f_ra; | 876 | ra->p_ra = file->f_ra; |
854 | ra->p_set = 1; | 877 | ra->p_set = 1; |
855 | ra->p_count--; | 878 | ra->p_count--; |
856 | spin_unlock(&ra_lock); | 879 | spin_unlock(&rab->pb_lock); |
857 | } | 880 | } |
858 | 881 | ||
859 | if (err >= 0) { | 882 | if (host_err >= 0) { |
860 | nfsdstats.io_read += err; | 883 | nfsdstats.io_read += host_err; |
861 | *count = err; | 884 | *count = host_err; |
862 | err = 0; | 885 | err = 0; |
863 | fsnotify_access(file->f_dentry); | 886 | fsnotify_access(file->f_dentry); |
864 | } else | 887 | } else |
865 | err = nfserrno(err); | 888 | err = nfserrno(host_err); |
866 | out: | 889 | out: |
867 | return err; | 890 | return err; |
868 | } | 891 | } |
@@ -877,7 +900,7 @@ static void kill_suid(struct dentry *dentry) | |||
877 | mutex_unlock(&dentry->d_inode->i_mutex); | 900 | mutex_unlock(&dentry->d_inode->i_mutex); |
878 | } | 901 | } |
879 | 902 | ||
880 | static int | 903 | static __be32 |
881 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 904 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
882 | loff_t offset, struct kvec *vec, int vlen, | 905 | loff_t offset, struct kvec *vec, int vlen, |
883 | unsigned long cnt, int *stablep) | 906 | unsigned long cnt, int *stablep) |
@@ -886,7 +909,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
886 | struct dentry *dentry; | 909 | struct dentry *dentry; |
887 | struct inode *inode; | 910 | struct inode *inode; |
888 | mm_segment_t oldfs; | 911 | mm_segment_t oldfs; |
889 | int err = 0; | 912 | __be32 err = 0; |
913 | int host_err; | ||
890 | int stable = *stablep; | 914 | int stable = *stablep; |
891 | 915 | ||
892 | #ifdef MSNFS | 916 | #ifdef MSNFS |
@@ -922,18 +946,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
922 | 946 | ||
923 | /* Write the data. */ | 947 | /* Write the data. */ |
924 | oldfs = get_fs(); set_fs(KERNEL_DS); | 948 | oldfs = get_fs(); set_fs(KERNEL_DS); |
925 | err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); | 949 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); |
926 | set_fs(oldfs); | 950 | set_fs(oldfs); |
927 | if (err >= 0) { | 951 | if (host_err >= 0) { |
928 | nfsdstats.io_write += cnt; | 952 | nfsdstats.io_write += cnt; |
929 | fsnotify_modify(file->f_dentry); | 953 | fsnotify_modify(file->f_dentry); |
930 | } | 954 | } |
931 | 955 | ||
932 | /* clear setuid/setgid flag after write */ | 956 | /* clear setuid/setgid flag after write */ |
933 | if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) | 957 | if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) |
934 | kill_suid(dentry); | 958 | kill_suid(dentry); |
935 | 959 | ||
936 | if (err >= 0 && stable) { | 960 | if (host_err >= 0 && stable) { |
937 | static ino_t last_ino; | 961 | static ino_t last_ino; |
938 | static dev_t last_dev; | 962 | static dev_t last_dev; |
939 | 963 | ||
@@ -959,7 +983,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
959 | 983 | ||
960 | if (inode->i_state & I_DIRTY) { | 984 | if (inode->i_state & I_DIRTY) { |
961 | dprintk("nfsd: write sync %d\n", current->pid); | 985 | dprintk("nfsd: write sync %d\n", current->pid); |
962 | err=nfsd_sync(file); | 986 | host_err=nfsd_sync(file); |
963 | } | 987 | } |
964 | #if 0 | 988 | #if 0 |
965 | wake_up(&inode->i_wait); | 989 | wake_up(&inode->i_wait); |
@@ -969,11 +993,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
969 | last_dev = inode->i_sb->s_dev; | 993 | last_dev = inode->i_sb->s_dev; |
970 | } | 994 | } |
971 | 995 | ||
972 | dprintk("nfsd: write complete err=%d\n", err); | 996 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
973 | if (err >= 0) | 997 | if (host_err >= 0) |
974 | err = 0; | 998 | err = 0; |
975 | else | 999 | else |
976 | err = nfserrno(err); | 1000 | err = nfserrno(host_err); |
977 | out: | 1001 | out: |
978 | return err; | 1002 | return err; |
979 | } | 1003 | } |
@@ -983,12 +1007,12 @@ out: | |||
983 | * on entry. On return, *count contains the number of bytes actually read. | 1007 | * on entry. On return, *count contains the number of bytes actually read. |
984 | * N.B. After this call fhp needs an fh_put | 1008 | * N.B. After this call fhp needs an fh_put |
985 | */ | 1009 | */ |
986 | int | 1010 | __be32 |
987 | nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1011 | nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
988 | loff_t offset, struct kvec *vec, int vlen, | 1012 | loff_t offset, struct kvec *vec, int vlen, |
989 | unsigned long *count) | 1013 | unsigned long *count) |
990 | { | 1014 | { |
991 | int err; | 1015 | __be32 err; |
992 | 1016 | ||
993 | if (file) { | 1017 | if (file) { |
994 | err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, | 1018 | err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, |
@@ -1012,12 +1036,12 @@ out: | |||
1012 | * The stable flag requests synchronous writes. | 1036 | * The stable flag requests synchronous writes. |
1013 | * N.B. After this call fhp needs an fh_put | 1037 | * N.B. After this call fhp needs an fh_put |
1014 | */ | 1038 | */ |
1015 | int | 1039 | __be32 |
1016 | nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1040 | nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
1017 | loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, | 1041 | loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, |
1018 | int *stablep) | 1042 | int *stablep) |
1019 | { | 1043 | { |
1020 | int err = 0; | 1044 | __be32 err = 0; |
1021 | 1045 | ||
1022 | if (file) { | 1046 | if (file) { |
1023 | err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, | 1047 | err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, |
@@ -1049,12 +1073,12 @@ out: | |||
1049 | * Unfortunately we cannot lock the file to make sure we return full WCC | 1073 | * Unfortunately we cannot lock the file to make sure we return full WCC |
1050 | * data to the client, as locking happens lower down in the filesystem. | 1074 | * data to the client, as locking happens lower down in the filesystem. |
1051 | */ | 1075 | */ |
1052 | int | 1076 | __be32 |
1053 | nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1077 | nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, |
1054 | loff_t offset, unsigned long count) | 1078 | loff_t offset, unsigned long count) |
1055 | { | 1079 | { |
1056 | struct file *file; | 1080 | struct file *file; |
1057 | int err; | 1081 | __be32 err; |
1058 | 1082 | ||
1059 | if ((u64)count > ~(u64)offset) | 1083 | if ((u64)count > ~(u64)offset) |
1060 | return nfserr_inval; | 1084 | return nfserr_inval; |
@@ -1082,14 +1106,15 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1082 | * | 1106 | * |
1083 | * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp | 1107 | * N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp |
1084 | */ | 1108 | */ |
1085 | int | 1109 | __be32 |
1086 | nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1110 | nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, |
1087 | char *fname, int flen, struct iattr *iap, | 1111 | char *fname, int flen, struct iattr *iap, |
1088 | int type, dev_t rdev, struct svc_fh *resfhp) | 1112 | int type, dev_t rdev, struct svc_fh *resfhp) |
1089 | { | 1113 | { |
1090 | struct dentry *dentry, *dchild = NULL; | 1114 | struct dentry *dentry, *dchild = NULL; |
1091 | struct inode *dirp; | 1115 | struct inode *dirp; |
1092 | int err; | 1116 | __be32 err; |
1117 | int host_err; | ||
1093 | 1118 | ||
1094 | err = nfserr_perm; | 1119 | err = nfserr_perm; |
1095 | if (!flen) | 1120 | if (!flen) |
@@ -1116,7 +1141,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1116 | /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ | 1141 | /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ |
1117 | fh_lock_nested(fhp, I_MUTEX_PARENT); | 1142 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
1118 | dchild = lookup_one_len(fname, dentry, flen); | 1143 | dchild = lookup_one_len(fname, dentry, flen); |
1119 | err = PTR_ERR(dchild); | 1144 | host_err = PTR_ERR(dchild); |
1120 | if (IS_ERR(dchild)) | 1145 | if (IS_ERR(dchild)) |
1121 | goto out_nfserr; | 1146 | goto out_nfserr; |
1122 | err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); | 1147 | err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); |
@@ -1155,22 +1180,22 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1155 | err = nfserr_perm; | 1180 | err = nfserr_perm; |
1156 | switch (type) { | 1181 | switch (type) { |
1157 | case S_IFREG: | 1182 | case S_IFREG: |
1158 | err = vfs_create(dirp, dchild, iap->ia_mode, NULL); | 1183 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); |
1159 | break; | 1184 | break; |
1160 | case S_IFDIR: | 1185 | case S_IFDIR: |
1161 | err = vfs_mkdir(dirp, dchild, iap->ia_mode); | 1186 | host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); |
1162 | break; | 1187 | break; |
1163 | case S_IFCHR: | 1188 | case S_IFCHR: |
1164 | case S_IFBLK: | 1189 | case S_IFBLK: |
1165 | case S_IFIFO: | 1190 | case S_IFIFO: |
1166 | case S_IFSOCK: | 1191 | case S_IFSOCK: |
1167 | err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); | 1192 | host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); |
1168 | break; | 1193 | break; |
1169 | default: | 1194 | default: |
1170 | printk("nfsd: bad file type %o in nfsd_create\n", type); | 1195 | printk("nfsd: bad file type %o in nfsd_create\n", type); |
1171 | err = -EINVAL; | 1196 | host_err = -EINVAL; |
1172 | } | 1197 | } |
1173 | if (err < 0) | 1198 | if (host_err < 0) |
1174 | goto out_nfserr; | 1199 | goto out_nfserr; |
1175 | 1200 | ||
1176 | if (EX_ISSYNC(fhp->fh_export)) { | 1201 | if (EX_ISSYNC(fhp->fh_export)) { |
@@ -1185,7 +1210,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1185 | * directories via NFS. | 1210 | * directories via NFS. |
1186 | */ | 1211 | */ |
1187 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { | 1212 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { |
1188 | int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1213 | __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1189 | if (err2) | 1214 | if (err2) |
1190 | err = err2; | 1215 | err = err2; |
1191 | } | 1216 | } |
@@ -1200,7 +1225,7 @@ out: | |||
1200 | return err; | 1225 | return err; |
1201 | 1226 | ||
1202 | out_nfserr: | 1227 | out_nfserr: |
1203 | err = nfserrno(err); | 1228 | err = nfserrno(host_err); |
1204 | goto out; | 1229 | goto out; |
1205 | } | 1230 | } |
1206 | 1231 | ||
@@ -1208,7 +1233,7 @@ out_nfserr: | |||
1208 | /* | 1233 | /* |
1209 | * NFSv3 version of nfsd_create | 1234 | * NFSv3 version of nfsd_create |
1210 | */ | 1235 | */ |
1211 | int | 1236 | __be32 |
1212 | nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1237 | nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, |
1213 | char *fname, int flen, struct iattr *iap, | 1238 | char *fname, int flen, struct iattr *iap, |
1214 | struct svc_fh *resfhp, int createmode, u32 *verifier, | 1239 | struct svc_fh *resfhp, int createmode, u32 *verifier, |
@@ -1216,7 +1241,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1216 | { | 1241 | { |
1217 | struct dentry *dentry, *dchild = NULL; | 1242 | struct dentry *dentry, *dchild = NULL; |
1218 | struct inode *dirp; | 1243 | struct inode *dirp; |
1219 | int err; | 1244 | __be32 err; |
1245 | int host_err; | ||
1220 | __u32 v_mtime=0, v_atime=0; | 1246 | __u32 v_mtime=0, v_atime=0; |
1221 | int v_mode=0; | 1247 | int v_mode=0; |
1222 | 1248 | ||
@@ -1246,7 +1272,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1246 | * Compose the response file handle. | 1272 | * Compose the response file handle. |
1247 | */ | 1273 | */ |
1248 | dchild = lookup_one_len(fname, dentry, flen); | 1274 | dchild = lookup_one_len(fname, dentry, flen); |
1249 | err = PTR_ERR(dchild); | 1275 | host_err = PTR_ERR(dchild); |
1250 | if (IS_ERR(dchild)) | 1276 | if (IS_ERR(dchild)) |
1251 | goto out_nfserr; | 1277 | goto out_nfserr; |
1252 | 1278 | ||
@@ -1302,8 +1328,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1302 | goto out; | 1328 | goto out; |
1303 | } | 1329 | } |
1304 | 1330 | ||
1305 | err = vfs_create(dirp, dchild, iap->ia_mode, NULL); | 1331 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); |
1306 | if (err < 0) | 1332 | if (host_err < 0) |
1307 | goto out_nfserr; | 1333 | goto out_nfserr; |
1308 | 1334 | ||
1309 | if (EX_ISSYNC(fhp->fh_export)) { | 1335 | if (EX_ISSYNC(fhp->fh_export)) { |
@@ -1332,7 +1358,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1332 | */ | 1358 | */ |
1333 | set_attr: | 1359 | set_attr: |
1334 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { | 1360 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { |
1335 | int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1361 | __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1336 | if (err2) | 1362 | if (err2) |
1337 | err = err2; | 1363 | err = err2; |
1338 | } | 1364 | } |
@@ -1350,7 +1376,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1350 | return err; | 1376 | return err; |
1351 | 1377 | ||
1352 | out_nfserr: | 1378 | out_nfserr: |
1353 | err = nfserrno(err); | 1379 | err = nfserrno(host_err); |
1354 | goto out; | 1380 | goto out; |
1355 | } | 1381 | } |
1356 | #endif /* CONFIG_NFSD_V3 */ | 1382 | #endif /* CONFIG_NFSD_V3 */ |
@@ -1360,13 +1386,14 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1360 | * fits into the buffer. On return, it contains the true length. | 1386 | * fits into the buffer. On return, it contains the true length. |
1361 | * N.B. After this call fhp needs an fh_put | 1387 | * N.B. After this call fhp needs an fh_put |
1362 | */ | 1388 | */ |
1363 | int | 1389 | __be32 |
1364 | nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) | 1390 | nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) |
1365 | { | 1391 | { |
1366 | struct dentry *dentry; | 1392 | struct dentry *dentry; |
1367 | struct inode *inode; | 1393 | struct inode *inode; |
1368 | mm_segment_t oldfs; | 1394 | mm_segment_t oldfs; |
1369 | int err; | 1395 | __be32 err; |
1396 | int host_err; | ||
1370 | 1397 | ||
1371 | err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); | 1398 | err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); |
1372 | if (err) | 1399 | if (err) |
@@ -1385,18 +1412,18 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) | |||
1385 | */ | 1412 | */ |
1386 | 1413 | ||
1387 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1414 | oldfs = get_fs(); set_fs(KERNEL_DS); |
1388 | err = inode->i_op->readlink(dentry, buf, *lenp); | 1415 | host_err = inode->i_op->readlink(dentry, buf, *lenp); |
1389 | set_fs(oldfs); | 1416 | set_fs(oldfs); |
1390 | 1417 | ||
1391 | if (err < 0) | 1418 | if (host_err < 0) |
1392 | goto out_nfserr; | 1419 | goto out_nfserr; |
1393 | *lenp = err; | 1420 | *lenp = host_err; |
1394 | err = 0; | 1421 | err = 0; |
1395 | out: | 1422 | out: |
1396 | return err; | 1423 | return err; |
1397 | 1424 | ||
1398 | out_nfserr: | 1425 | out_nfserr: |
1399 | err = nfserrno(err); | 1426 | err = nfserrno(host_err); |
1400 | goto out; | 1427 | goto out; |
1401 | } | 1428 | } |
1402 | 1429 | ||
@@ -1404,7 +1431,7 @@ out_nfserr: | |||
1404 | * Create a symlink and look up its inode | 1431 | * Create a symlink and look up its inode |
1405 | * N.B. After this call _both_ fhp and resfhp need an fh_put | 1432 | * N.B. After this call _both_ fhp and resfhp need an fh_put |
1406 | */ | 1433 | */ |
1407 | int | 1434 | __be32 |
1408 | nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1435 | nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, |
1409 | char *fname, int flen, | 1436 | char *fname, int flen, |
1410 | char *path, int plen, | 1437 | char *path, int plen, |
@@ -1412,7 +1439,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1412 | struct iattr *iap) | 1439 | struct iattr *iap) |
1413 | { | 1440 | { |
1414 | struct dentry *dentry, *dnew; | 1441 | struct dentry *dentry, *dnew; |
1415 | int err, cerr; | 1442 | __be32 err, cerr; |
1443 | int host_err; | ||
1416 | umode_t mode; | 1444 | umode_t mode; |
1417 | 1445 | ||
1418 | err = nfserr_noent; | 1446 | err = nfserr_noent; |
@@ -1428,7 +1456,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1428 | fh_lock(fhp); | 1456 | fh_lock(fhp); |
1429 | dentry = fhp->fh_dentry; | 1457 | dentry = fhp->fh_dentry; |
1430 | dnew = lookup_one_len(fname, dentry, flen); | 1458 | dnew = lookup_one_len(fname, dentry, flen); |
1431 | err = PTR_ERR(dnew); | 1459 | host_err = PTR_ERR(dnew); |
1432 | if (IS_ERR(dnew)) | 1460 | if (IS_ERR(dnew)) |
1433 | goto out_nfserr; | 1461 | goto out_nfserr; |
1434 | 1462 | ||
@@ -1440,21 +1468,21 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1440 | if (unlikely(path[plen] != 0)) { | 1468 | if (unlikely(path[plen] != 0)) { |
1441 | char *path_alloced = kmalloc(plen+1, GFP_KERNEL); | 1469 | char *path_alloced = kmalloc(plen+1, GFP_KERNEL); |
1442 | if (path_alloced == NULL) | 1470 | if (path_alloced == NULL) |
1443 | err = -ENOMEM; | 1471 | host_err = -ENOMEM; |
1444 | else { | 1472 | else { |
1445 | strncpy(path_alloced, path, plen); | 1473 | strncpy(path_alloced, path, plen); |
1446 | path_alloced[plen] = 0; | 1474 | path_alloced[plen] = 0; |
1447 | err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); | 1475 | host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); |
1448 | kfree(path_alloced); | 1476 | kfree(path_alloced); |
1449 | } | 1477 | } |
1450 | } else | 1478 | } else |
1451 | err = vfs_symlink(dentry->d_inode, dnew, path, mode); | 1479 | host_err = vfs_symlink(dentry->d_inode, dnew, path, mode); |
1452 | 1480 | ||
1453 | if (!err) | 1481 | if (!host_err) { |
1454 | if (EX_ISSYNC(fhp->fh_export)) | 1482 | if (EX_ISSYNC(fhp->fh_export)) |
1455 | err = nfsd_sync_dir(dentry); | 1483 | host_err = nfsd_sync_dir(dentry); |
1456 | if (err) | 1484 | } |
1457 | err = nfserrno(err); | 1485 | err = nfserrno(host_err); |
1458 | fh_unlock(fhp); | 1486 | fh_unlock(fhp); |
1459 | 1487 | ||
1460 | cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); | 1488 | cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); |
@@ -1464,7 +1492,7 @@ out: | |||
1464 | return err; | 1492 | return err; |
1465 | 1493 | ||
1466 | out_nfserr: | 1494 | out_nfserr: |
1467 | err = nfserrno(err); | 1495 | err = nfserrno(host_err); |
1468 | goto out; | 1496 | goto out; |
1469 | } | 1497 | } |
1470 | 1498 | ||
@@ -1472,13 +1500,14 @@ out_nfserr: | |||
1472 | * Create a hardlink | 1500 | * Create a hardlink |
1473 | * N.B. After this call _both_ ffhp and tfhp need an fh_put | 1501 | * N.B. After this call _both_ ffhp and tfhp need an fh_put |
1474 | */ | 1502 | */ |
1475 | int | 1503 | __be32 |
1476 | nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | 1504 | nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, |
1477 | char *name, int len, struct svc_fh *tfhp) | 1505 | char *name, int len, struct svc_fh *tfhp) |
1478 | { | 1506 | { |
1479 | struct dentry *ddir, *dnew, *dold; | 1507 | struct dentry *ddir, *dnew, *dold; |
1480 | struct inode *dirp, *dest; | 1508 | struct inode *dirp, *dest; |
1481 | int err; | 1509 | __be32 err; |
1510 | int host_err; | ||
1482 | 1511 | ||
1483 | err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); | 1512 | err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); |
1484 | if (err) | 1513 | if (err) |
@@ -1499,24 +1528,25 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1499 | dirp = ddir->d_inode; | 1528 | dirp = ddir->d_inode; |
1500 | 1529 | ||
1501 | dnew = lookup_one_len(name, ddir, len); | 1530 | dnew = lookup_one_len(name, ddir, len); |
1502 | err = PTR_ERR(dnew); | 1531 | host_err = PTR_ERR(dnew); |
1503 | if (IS_ERR(dnew)) | 1532 | if (IS_ERR(dnew)) |
1504 | goto out_nfserr; | 1533 | goto out_nfserr; |
1505 | 1534 | ||
1506 | dold = tfhp->fh_dentry; | 1535 | dold = tfhp->fh_dentry; |
1507 | dest = dold->d_inode; | 1536 | dest = dold->d_inode; |
1508 | 1537 | ||
1509 | err = vfs_link(dold, dirp, dnew); | 1538 | host_err = vfs_link(dold, dirp, dnew); |
1510 | if (!err) { | 1539 | if (!host_err) { |
1511 | if (EX_ISSYNC(ffhp->fh_export)) { | 1540 | if (EX_ISSYNC(ffhp->fh_export)) { |
1512 | err = nfserrno(nfsd_sync_dir(ddir)); | 1541 | err = nfserrno(nfsd_sync_dir(ddir)); |
1513 | write_inode_now(dest, 1); | 1542 | write_inode_now(dest, 1); |
1514 | } | 1543 | } |
1544 | err = 0; | ||
1515 | } else { | 1545 | } else { |
1516 | if (err == -EXDEV && rqstp->rq_vers == 2) | 1546 | if (host_err == -EXDEV && rqstp->rq_vers == 2) |
1517 | err = nfserr_acces; | 1547 | err = nfserr_acces; |
1518 | else | 1548 | else |
1519 | err = nfserrno(err); | 1549 | err = nfserrno(host_err); |
1520 | } | 1550 | } |
1521 | 1551 | ||
1522 | dput(dnew); | 1552 | dput(dnew); |
@@ -1526,7 +1556,7 @@ out: | |||
1526 | return err; | 1556 | return err; |
1527 | 1557 | ||
1528 | out_nfserr: | 1558 | out_nfserr: |
1529 | err = nfserrno(err); | 1559 | err = nfserrno(host_err); |
1530 | goto out_unlock; | 1560 | goto out_unlock; |
1531 | } | 1561 | } |
1532 | 1562 | ||
@@ -1534,13 +1564,14 @@ out_nfserr: | |||
1534 | * Rename a file | 1564 | * Rename a file |
1535 | * N.B. After this call _both_ ffhp and tfhp need an fh_put | 1565 | * N.B. After this call _both_ ffhp and tfhp need an fh_put |
1536 | */ | 1566 | */ |
1537 | int | 1567 | __be32 |
1538 | nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | 1568 | nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, |
1539 | struct svc_fh *tfhp, char *tname, int tlen) | 1569 | struct svc_fh *tfhp, char *tname, int tlen) |
1540 | { | 1570 | { |
1541 | struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap; | 1571 | struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap; |
1542 | struct inode *fdir, *tdir; | 1572 | struct inode *fdir, *tdir; |
1543 | int err; | 1573 | __be32 err; |
1574 | int host_err; | ||
1544 | 1575 | ||
1545 | err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); | 1576 | err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); |
1546 | if (err) | 1577 | if (err) |
@@ -1571,22 +1602,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1571 | fill_pre_wcc(tfhp); | 1602 | fill_pre_wcc(tfhp); |
1572 | 1603 | ||
1573 | odentry = lookup_one_len(fname, fdentry, flen); | 1604 | odentry = lookup_one_len(fname, fdentry, flen); |
1574 | err = PTR_ERR(odentry); | 1605 | host_err = PTR_ERR(odentry); |
1575 | if (IS_ERR(odentry)) | 1606 | if (IS_ERR(odentry)) |
1576 | goto out_nfserr; | 1607 | goto out_nfserr; |
1577 | 1608 | ||
1578 | err = -ENOENT; | 1609 | host_err = -ENOENT; |
1579 | if (!odentry->d_inode) | 1610 | if (!odentry->d_inode) |
1580 | goto out_dput_old; | 1611 | goto out_dput_old; |
1581 | err = -EINVAL; | 1612 | host_err = -EINVAL; |
1582 | if (odentry == trap) | 1613 | if (odentry == trap) |
1583 | goto out_dput_old; | 1614 | goto out_dput_old; |
1584 | 1615 | ||
1585 | ndentry = lookup_one_len(tname, tdentry, tlen); | 1616 | ndentry = lookup_one_len(tname, tdentry, tlen); |
1586 | err = PTR_ERR(ndentry); | 1617 | host_err = PTR_ERR(ndentry); |
1587 | if (IS_ERR(ndentry)) | 1618 | if (IS_ERR(ndentry)) |
1588 | goto out_dput_old; | 1619 | goto out_dput_old; |
1589 | err = -ENOTEMPTY; | 1620 | host_err = -ENOTEMPTY; |
1590 | if (ndentry == trap) | 1621 | if (ndentry == trap) |
1591 | goto out_dput_new; | 1622 | goto out_dput_new; |
1592 | 1623 | ||
@@ -1594,14 +1625,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1594 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1625 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1595 | ((atomic_read(&odentry->d_count) > 1) | 1626 | ((atomic_read(&odentry->d_count) > 1) |
1596 | || (atomic_read(&ndentry->d_count) > 1))) { | 1627 | || (atomic_read(&ndentry->d_count) > 1))) { |
1597 | err = -EPERM; | 1628 | host_err = -EPERM; |
1598 | } else | 1629 | } else |
1599 | #endif | 1630 | #endif |
1600 | err = vfs_rename(fdir, odentry, tdir, ndentry); | 1631 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1601 | if (!err && EX_ISSYNC(tfhp->fh_export)) { | 1632 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { |
1602 | err = nfsd_sync_dir(tdentry); | 1633 | host_err = nfsd_sync_dir(tdentry); |
1603 | if (!err) | 1634 | if (!host_err) |
1604 | err = nfsd_sync_dir(fdentry); | 1635 | host_err = nfsd_sync_dir(fdentry); |
1605 | } | 1636 | } |
1606 | 1637 | ||
1607 | out_dput_new: | 1638 | out_dput_new: |
@@ -1609,8 +1640,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1609 | out_dput_old: | 1640 | out_dput_old: |
1610 | dput(odentry); | 1641 | dput(odentry); |
1611 | out_nfserr: | 1642 | out_nfserr: |
1612 | if (err) | 1643 | err = nfserrno(host_err); |
1613 | err = nfserrno(err); | ||
1614 | 1644 | ||
1615 | /* we cannot reply on fh_unlock on the two filehandles, | 1645 | /* we cannot reply on fh_unlock on the two filehandles, |
1616 | * as that would do the wrong thing if the two directories | 1646 | * as that would do the wrong thing if the two directories |
@@ -1629,13 +1659,14 @@ out: | |||
1629 | * Unlink a file or directory | 1659 | * Unlink a file or directory |
1630 | * N.B. After this call fhp needs an fh_put | 1660 | * N.B. After this call fhp needs an fh_put |
1631 | */ | 1661 | */ |
1632 | int | 1662 | __be32 |
1633 | nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | 1663 | nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, |
1634 | char *fname, int flen) | 1664 | char *fname, int flen) |
1635 | { | 1665 | { |
1636 | struct dentry *dentry, *rdentry; | 1666 | struct dentry *dentry, *rdentry; |
1637 | struct inode *dirp; | 1667 | struct inode *dirp; |
1638 | int err; | 1668 | __be32 err; |
1669 | int host_err; | ||
1639 | 1670 | ||
1640 | err = nfserr_acces; | 1671 | err = nfserr_acces; |
1641 | if (!flen || isdotent(fname, flen)) | 1672 | if (!flen || isdotent(fname, flen)) |
@@ -1649,7 +1680,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1649 | dirp = dentry->d_inode; | 1680 | dirp = dentry->d_inode; |
1650 | 1681 | ||
1651 | rdentry = lookup_one_len(fname, dentry, flen); | 1682 | rdentry = lookup_one_len(fname, dentry, flen); |
1652 | err = PTR_ERR(rdentry); | 1683 | host_err = PTR_ERR(rdentry); |
1653 | if (IS_ERR(rdentry)) | 1684 | if (IS_ERR(rdentry)) |
1654 | goto out_nfserr; | 1685 | goto out_nfserr; |
1655 | 1686 | ||
@@ -1666,22 +1697,23 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1666 | #ifdef MSNFS | 1697 | #ifdef MSNFS |
1667 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1698 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1668 | (atomic_read(&rdentry->d_count) > 1)) { | 1699 | (atomic_read(&rdentry->d_count) > 1)) { |
1669 | err = -EPERM; | 1700 | host_err = -EPERM; |
1670 | } else | 1701 | } else |
1671 | #endif | 1702 | #endif |
1672 | err = vfs_unlink(dirp, rdentry); | 1703 | host_err = vfs_unlink(dirp, rdentry); |
1673 | } else { /* It's RMDIR */ | 1704 | } else { /* It's RMDIR */ |
1674 | err = vfs_rmdir(dirp, rdentry); | 1705 | host_err = vfs_rmdir(dirp, rdentry); |
1675 | } | 1706 | } |
1676 | 1707 | ||
1677 | dput(rdentry); | 1708 | dput(rdentry); |
1678 | 1709 | ||
1679 | if (err == 0 && | 1710 | if (host_err) |
1680 | EX_ISSYNC(fhp->fh_export)) | 1711 | goto out_nfserr; |
1681 | err = nfsd_sync_dir(dentry); | 1712 | if (EX_ISSYNC(fhp->fh_export)) |
1713 | host_err = nfsd_sync_dir(dentry); | ||
1682 | 1714 | ||
1683 | out_nfserr: | 1715 | out_nfserr: |
1684 | err = nfserrno(err); | 1716 | err = nfserrno(host_err); |
1685 | out: | 1717 | out: |
1686 | return err; | 1718 | return err; |
1687 | } | 1719 | } |
@@ -1690,11 +1722,12 @@ out: | |||
1690 | * Read entries from a directory. | 1722 | * Read entries from a directory. |
1691 | * The NFSv3/4 verifier we ignore for now. | 1723 | * The NFSv3/4 verifier we ignore for now. |
1692 | */ | 1724 | */ |
1693 | int | 1725 | __be32 |
1694 | nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | 1726 | nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, |
1695 | struct readdir_cd *cdp, encode_dent_fn func) | 1727 | struct readdir_cd *cdp, encode_dent_fn func) |
1696 | { | 1728 | { |
1697 | int err; | 1729 | __be32 err; |
1730 | int host_err; | ||
1698 | struct file *file; | 1731 | struct file *file; |
1699 | loff_t offset = *offsetp; | 1732 | loff_t offset = *offsetp; |
1700 | 1733 | ||
@@ -1716,10 +1749,10 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, | |||
1716 | 1749 | ||
1717 | do { | 1750 | do { |
1718 | cdp->err = nfserr_eof; /* will be cleared on successful read */ | 1751 | cdp->err = nfserr_eof; /* will be cleared on successful read */ |
1719 | err = vfs_readdir(file, (filldir_t) func, cdp); | 1752 | host_err = vfs_readdir(file, (filldir_t) func, cdp); |
1720 | } while (err >=0 && cdp->err == nfs_ok); | 1753 | } while (host_err >=0 && cdp->err == nfs_ok); |
1721 | if (err) | 1754 | if (host_err) |
1722 | err = nfserrno(err); | 1755 | err = nfserrno(host_err); |
1723 | else | 1756 | else |
1724 | err = cdp->err; | 1757 | err = cdp->err; |
1725 | *offsetp = vfs_llseek(file, 0, 1); | 1758 | *offsetp = vfs_llseek(file, 0, 1); |
@@ -1736,10 +1769,10 @@ out: | |||
1736 | * Get file system stats | 1769 | * Get file system stats |
1737 | * N.B. After this call fhp needs an fh_put | 1770 | * N.B. After this call fhp needs an fh_put |
1738 | */ | 1771 | */ |
1739 | int | 1772 | __be32 |
1740 | nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) | 1773 | nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) |
1741 | { | 1774 | { |
1742 | int err = fh_verify(rqstp, fhp, 0, MAY_NOP); | 1775 | __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP); |
1743 | if (!err && vfs_statfs(fhp->fh_dentry,stat)) | 1776 | if (!err && vfs_statfs(fhp->fh_dentry,stat)) |
1744 | err = nfserr_io; | 1777 | err = nfserr_io; |
1745 | return err; | 1778 | return err; |
@@ -1748,7 +1781,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) | |||
1748 | /* | 1781 | /* |
1749 | * Check for a user's access permissions to this inode. | 1782 | * Check for a user's access permissions to this inode. |
1750 | */ | 1783 | */ |
1751 | int | 1784 | __be32 |
1752 | nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | 1785 | nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) |
1753 | { | 1786 | { |
1754 | struct inode *inode = dentry->d_inode; | 1787 | struct inode *inode = dentry->d_inode; |
@@ -1829,11 +1862,11 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | |||
1829 | void | 1862 | void |
1830 | nfsd_racache_shutdown(void) | 1863 | nfsd_racache_shutdown(void) |
1831 | { | 1864 | { |
1832 | if (!raparm_cache) | 1865 | if (!raparml) |
1833 | return; | 1866 | return; |
1834 | dprintk("nfsd: freeing readahead buffers.\n"); | 1867 | dprintk("nfsd: freeing readahead buffers.\n"); |
1835 | kfree(raparml); | 1868 | kfree(raparml); |
1836 | raparm_cache = raparml = NULL; | 1869 | raparml = NULL; |
1837 | } | 1870 | } |
1838 | /* | 1871 | /* |
1839 | * Initialize readahead param cache | 1872 | * Initialize readahead param cache |
@@ -1842,19 +1875,31 @@ int | |||
1842 | nfsd_racache_init(int cache_size) | 1875 | nfsd_racache_init(int cache_size) |
1843 | { | 1876 | { |
1844 | int i; | 1877 | int i; |
1878 | int j = 0; | ||
1879 | int nperbucket; | ||
1880 | |||
1845 | 1881 | ||
1846 | if (raparm_cache) | 1882 | if (raparml) |
1847 | return 0; | 1883 | return 0; |
1884 | if (cache_size < 2*RAPARM_HASH_SIZE) | ||
1885 | cache_size = 2*RAPARM_HASH_SIZE; | ||
1848 | raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL); | 1886 | raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL); |
1849 | 1887 | ||
1850 | if (raparml != NULL) { | 1888 | if (raparml != NULL) { |
1851 | dprintk("nfsd: allocating %d readahead buffers.\n", | 1889 | dprintk("nfsd: allocating %d readahead buffers.\n", |
1852 | cache_size); | 1890 | cache_size); |
1891 | for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) { | ||
1892 | raparm_hash[i].pb_head = NULL; | ||
1893 | spin_lock_init(&raparm_hash[i].pb_lock); | ||
1894 | } | ||
1895 | nperbucket = cache_size >> RAPARM_HASH_BITS; | ||
1853 | memset(raparml, 0, sizeof(struct raparms) * cache_size); | 1896 | memset(raparml, 0, sizeof(struct raparms) * cache_size); |
1854 | for (i = 0; i < cache_size - 1; i++) { | 1897 | for (i = 0; i < cache_size - 1; i++) { |
1855 | raparml[i].p_next = raparml + i + 1; | 1898 | if (i % nperbucket == 0) |
1899 | raparm_hash[j++].pb_head = raparml + i; | ||
1900 | if (i % nperbucket < nperbucket-1) | ||
1901 | raparml[i].p_next = raparml + i + 1; | ||
1856 | } | 1902 | } |
1857 | raparm_cache = raparml; | ||
1858 | } else { | 1903 | } else { |
1859 | printk(KERN_WARNING | 1904 | printk(KERN_WARNING |
1860 | "nfsd: Could not allocate memory read-ahead cache.\n"); | 1905 | "nfsd: Could not allocate memory read-ahead cache.\n"); |