aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c122
1 files changed, 69 insertions, 53 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 8604e35bd48e..ee96a897a29e 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -113,21 +113,21 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
113 113
114 while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); 114 while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
115 115
116 exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle); 116 exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
117 if (IS_ERR(exp2)) { 117 if (IS_ERR(exp2)) {
118 err = PTR_ERR(exp2); 118 err = PTR_ERR(exp2);
119 dput(mounts); 119 dput(mounts);
120 mntput(mnt); 120 mntput(mnt);
121 goto out; 121 goto out;
122 } 122 }
123 if (exp2 && ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2))) { 123 if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
124 /* successfully crossed mount point */ 124 /* successfully crossed mount point */
125 exp_put(exp); 125 exp_put(exp);
126 *expp = exp2; 126 *expp = exp2;
127 dput(dentry); 127 dput(dentry);
128 *dpp = mounts; 128 *dpp = mounts;
129 } else { 129 } else {
130 if (exp2) exp_put(exp2); 130 exp_put(exp2);
131 dput(mounts); 131 dput(mounts);
132 } 132 }
133 mntput(mnt); 133 mntput(mnt);
@@ -135,21 +135,10 @@ out:
135 return err; 135 return err;
136} 136}
137 137
138/*
139 * Look up one component of a pathname.
140 * N.B. After this call _both_ fhp and resfh need an fh_put
141 *
142 * If the lookup would cross a mountpoint, and the mounted filesystem
143 * is exported to the client with NFSEXP_NOHIDE, then the lookup is
144 * accepted as it stands and the mounted directory is
145 * returned. Otherwise the covered directory is returned.
146 * NOTE: this mountpoint crossing is not supported properly by all
147 * clients and is explicitly disallowed for NFSv3
148 * NeilBrown <neilb@cse.unsw.edu.au>
149 */
150__be32 138__be32
151nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, 139nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
152 int len, struct svc_fh *resfh) 140 const char *name, int len,
141 struct svc_export **exp_ret, struct dentry **dentry_ret)
153{ 142{
154 struct svc_export *exp; 143 struct svc_export *exp;
155 struct dentry *dparent; 144 struct dentry *dparent;
@@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
168 exp = fhp->fh_export; 157 exp = fhp->fh_export;
169 exp_get(exp); 158 exp_get(exp);
170 159
171 err = nfserr_acces;
172
173 /* Lookup the name, but don't follow links */ 160 /* Lookup the name, but don't follow links */
174 if (isdotent(name, len)) { 161 if (isdotent(name, len)) {
175 if (len==1) 162 if (len==1)
@@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
190 dput(dentry); 177 dput(dentry);
191 dentry = dp; 178 dentry = dp;
192 179
193 exp2 = exp_parent(exp->ex_client, mnt, dentry, 180 exp2 = rqst_exp_parent(rqstp, mnt, dentry);
194 &rqstp->rq_chandle); 181 if (PTR_ERR(exp2) == -ENOENT) {
195 if (IS_ERR(exp2)) { 182 dput(dentry);
183 dentry = dget(dparent);
184 } else if (IS_ERR(exp2)) {
196 host_err = PTR_ERR(exp2); 185 host_err = PTR_ERR(exp2);
197 dput(dentry); 186 dput(dentry);
198 mntput(mnt); 187 mntput(mnt);
199 goto out_nfserr; 188 goto out_nfserr;
200 }
201 if (!exp2) {
202 dput(dentry);
203 dentry = dget(dparent);
204 } else { 189 } else {
205 exp_put(exp); 190 exp_put(exp);
206 exp = exp2; 191 exp = exp2;
@@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
223 } 208 }
224 } 209 }
225 } 210 }
211 *dentry_ret = dentry;
212 *exp_ret = exp;
213 return 0;
214
215out_nfserr:
216 exp_put(exp);
217 return nfserrno(host_err);
218}
219
220/*
221 * Look up one component of a pathname.
222 * N.B. After this call _both_ fhp and resfh need an fh_put
223 *
224 * If the lookup would cross a mountpoint, and the mounted filesystem
225 * is exported to the client with NFSEXP_NOHIDE, then the lookup is
226 * accepted as it stands and the mounted directory is
227 * returned. Otherwise the covered directory is returned.
228 * NOTE: this mountpoint crossing is not supported properly by all
229 * clients and is explicitly disallowed for NFSv3
230 * NeilBrown <neilb@cse.unsw.edu.au>
231 */
232__be32
233nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
234 int len, struct svc_fh *resfh)
235{
236 struct svc_export *exp;
237 struct dentry *dentry;
238 __be32 err;
239
240 err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
241 if (err)
242 return err;
243 err = check_nfsd_access(exp, rqstp);
244 if (err)
245 goto out;
226 /* 246 /*
227 * Note: we compose the file handle now, but as the 247 * Note: we compose the file handle now, but as the
228 * dentry may be negative, it may need to be updated. 248 * dentry may be negative, it may need to be updated.
@@ -230,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
230 err = fh_compose(resfh, exp, dentry, fhp); 250 err = fh_compose(resfh, exp, dentry, fhp);
231 if (!err && !dentry->d_inode) 251 if (!err && !dentry->d_inode)
232 err = nfserr_noent; 252 err = nfserr_noent;
233 dput(dentry);
234out: 253out:
254 dput(dentry);
235 exp_put(exp); 255 exp_put(exp);
236 return err; 256 return err;
237
238out_nfserr:
239 err = nfserrno(host_err);
240 goto out;
241} 257}
242 258
259
243/* 260/*
244 * Set various file attributes. 261 * Set various file attributes.
245 * N.B. After this call fhp needs an fh_put 262 * N.B. After this call fhp needs an fh_put
@@ -311,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
311 /* The size case is special. It changes the file as well as the attributes. */ 328 /* The size case is special. It changes the file as well as the attributes. */
312 if (iap->ia_valid & ATTR_SIZE) { 329 if (iap->ia_valid & ATTR_SIZE) {
313 if (iap->ia_size < inode->i_size) { 330 if (iap->ia_size < inode->i_size) {
314 err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); 331 err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
315 if (err) 332 if (err)
316 goto out; 333 goto out;
317 } 334 }
@@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
435 /* Get inode */ 452 /* Get inode */
436 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); 453 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
437 if (error) 454 if (error)
438 goto out; 455 return error;
439 456
440 dentry = fhp->fh_dentry; 457 dentry = fhp->fh_dentry;
441 inode = dentry->d_inode; 458 inode = dentry->d_inode;
@@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
444 461
445 host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); 462 host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
446 if (host_error == -EINVAL) { 463 if (host_error == -EINVAL) {
447 error = nfserr_attrnotsupp; 464 return nfserr_attrnotsupp;
448 goto out;
449 } else if (host_error < 0) 465 } else if (host_error < 0)
450 goto out_nfserr; 466 goto out_nfserr;
451 467
452 host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); 468 host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
453 if (host_error < 0) 469 if (host_error < 0)
454 goto out_nfserr; 470 goto out_release;
455 471
456 if (S_ISDIR(inode->i_mode)) { 472 if (S_ISDIR(inode->i_mode))
457 host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); 473 host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
458 if (host_error < 0)
459 goto out_nfserr;
460 }
461 474
462 error = nfs_ok; 475out_release:
463
464out:
465 posix_acl_release(pacl); 476 posix_acl_release(pacl);
466 posix_acl_release(dpacl); 477 posix_acl_release(dpacl);
467 return (error);
468out_nfserr: 478out_nfserr:
469 if (host_error == -EOPNOTSUPP) 479 if (host_error == -EOPNOTSUPP)
470 error = nfserr_attrnotsupp; 480 return nfserr_attrnotsupp;
471 else 481 else
472 error = nfserrno(host_error); 482 return nfserrno(host_error);
473 goto out;
474} 483}
475 484
476static struct posix_acl * 485static struct posix_acl *
@@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
607 616
608 sresult |= map->access; 617 sresult |= map->access;
609 618
610 err2 = nfsd_permission(export, dentry, map->how); 619 err2 = nfsd_permission(rqstp, export, dentry, map->how);
611 switch (err2) { 620 switch (err2) {
612 case nfs_ok: 621 case nfs_ok:
613 result |= map->access; 622 result |= map->access;
@@ -879,6 +888,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
879 .u.data = rqstp, 888 .u.data = rqstp,
880 }; 889 };
881 890
891 rqstp->rq_resused = 1;
882 host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); 892 host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
883 } else { 893 } else {
884 oldfs = get_fs(); 894 oldfs = get_fs();
@@ -1033,7 +1043,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1033 __be32 err; 1043 __be32 err;
1034 1044
1035 if (file) { 1045 if (file) {
1036 err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, 1046 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1037 MAY_READ|MAY_OWNER_OVERRIDE); 1047 MAY_READ|MAY_OWNER_OVERRIDE);
1038 if (err) 1048 if (err)
1039 goto out; 1049 goto out;
@@ -1062,7 +1072,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1062 __be32 err = 0; 1072 __be32 err = 0;
1063 1073
1064 if (file) { 1074 if (file) {
1065 err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, 1075 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1066 MAY_WRITE|MAY_OWNER_OVERRIDE); 1076 MAY_WRITE|MAY_OWNER_OVERRIDE);
1067 if (err) 1077 if (err)
1068 goto out; 1078 goto out;
@@ -1787,11 +1797,17 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
1787 return err; 1797 return err;
1788} 1798}
1789 1799
1800static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp)
1801{
1802 return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY;
1803}
1804
1790/* 1805/*
1791 * Check for a user's access permissions to this inode. 1806 * Check for a user's access permissions to this inode.
1792 */ 1807 */
1793__be32 1808__be32
1794nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) 1809nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1810 struct dentry *dentry, int acc)
1795{ 1811{
1796 struct inode *inode = dentry->d_inode; 1812 struct inode *inode = dentry->d_inode;
1797 int err; 1813 int err;
@@ -1822,7 +1838,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
1822 */ 1838 */
1823 if (!(acc & MAY_LOCAL_ACCESS)) 1839 if (!(acc & MAY_LOCAL_ACCESS))
1824 if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { 1840 if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
1825 if (EX_RDONLY(exp) || IS_RDONLY(inode)) 1841 if (exp_rdonly(rqstp, exp) || IS_RDONLY(inode))
1826 return nfserr_rofs; 1842 return nfserr_rofs;
1827 if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) 1843 if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
1828 return nfserr_perm; 1844 return nfserr_perm;
@@ -1905,7 +1921,7 @@ nfsd_racache_init(int cache_size)
1905 raparm_hash[i].pb_head = NULL; 1921 raparm_hash[i].pb_head = NULL;
1906 spin_lock_init(&raparm_hash[i].pb_lock); 1922 spin_lock_init(&raparm_hash[i].pb_lock);
1907 } 1923 }
1908 nperbucket = cache_size >> RAPARM_HASH_BITS; 1924 nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
1909 for (i = 0; i < cache_size - 1; i++) { 1925 for (i = 0; i < cache_size - 1; i++) {
1910 if (i % nperbucket == 0) 1926 if (i % nperbucket == 0)
1911 raparm_hash[j++].pb_head = raparml + i; 1927 raparm_hash[j++].pb_head = raparml + i;