aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2013-11-18 08:07:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-29 14:11:49 -0500
commitb26be14b8e496c6fa14b53ba3390b56a5988df8a (patch)
tree5087dd675557df51668e53460c578993d3de17eb /fs/nfsd
parent8b7330f9057949e8c5df82df8a76068d0129e778 (diff)
nfsd: split up nfsd_setattr
commit 818e5a22e907fbae75e9c1fd78233baec9fa64b6 upstream. Split out two helpers to make the code more readable and easier to verify for correctness. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/vfs.c144
1 files changed, 84 insertions, 60 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index baf149a85263..56b71a9e6271 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -297,41 +297,12 @@ commit_metadata(struct svc_fh *fhp)
297} 297}
298 298
299/* 299/*
300 * Set various file attributes. 300 * Go over the attributes and take care of the small differences between
301 * N.B. After this call fhp needs an fh_put 301 * NFS semantics and what Linux expects.
302 */ 302 */
303__be32 303static void
304nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, 304nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
305 int check_guard, time_t guardtime)
306{ 305{
307 struct dentry *dentry;
308 struct inode *inode;
309 int accmode = NFSD_MAY_SATTR;
310 umode_t ftype = 0;
311 __be32 err;
312 int host_err;
313 int size_change = 0;
314
315 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
316 accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
317 if (iap->ia_valid & ATTR_SIZE)
318 ftype = S_IFREG;
319
320 /* Get inode */
321 err = fh_verify(rqstp, fhp, ftype, accmode);
322 if (err)
323 goto out;
324
325 dentry = fhp->fh_dentry;
326 inode = dentry->d_inode;
327
328 /* Ignore any mode updates on symlinks */
329 if (S_ISLNK(inode->i_mode))
330 iap->ia_valid &= ~ATTR_MODE;
331
332 if (!iap->ia_valid)
333 goto out;
334
335 /* 306 /*
336 * NFSv2 does not differentiate between "set-[ac]time-to-now" 307 * NFSv2 does not differentiate between "set-[ac]time-to-now"
337 * which only requires access, and "set-[ac]time-to-X" which 308 * which only requires access, and "set-[ac]time-to-X" which
@@ -341,8 +312,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
341 * convert to "set to now" instead of "set to explicit time" 312 * convert to "set to now" instead of "set to explicit time"
342 * 313 *
343 * We only call inode_change_ok as the last test as technically 314 * We only call inode_change_ok as the last test as technically
344 * it is not an interface that we should be using. It is only 315 * it is not an interface that we should be using.
345 * valid if the filesystem does not define it's own i_op->setattr.
346 */ 316 */
347#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) 317#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
348#define MAX_TOUCH_TIME_ERROR (30*60) 318#define MAX_TOUCH_TIME_ERROR (30*60)
@@ -368,30 +338,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
368 iap->ia_valid &= ~BOTH_TIME_SET; 338 iap->ia_valid &= ~BOTH_TIME_SET;
369 } 339 }
370 } 340 }
371
372 /*
373 * The size case is special.
374 * It changes the file as well as the attributes.
375 */
376 if (iap->ia_valid & ATTR_SIZE) {
377 if (iap->ia_size < inode->i_size) {
378 err = nfsd_permission(rqstp, fhp->fh_export, dentry,
379 NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE);
380 if (err)
381 goto out;
382 }
383
384 host_err = get_write_access(inode);
385 if (host_err)
386 goto out_nfserr;
387
388 size_change = 1;
389 host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
390 if (host_err) {
391 put_write_access(inode);
392 goto out_nfserr;
393 }
394 }
395 341
396 /* sanitize the mode change */ 342 /* sanitize the mode change */
397 if (iap->ia_valid & ATTR_MODE) { 343 if (iap->ia_valid & ATTR_MODE) {
@@ -414,8 +360,86 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
414 iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); 360 iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
415 } 361 }
416 } 362 }
363}
417 364
418 /* Change the attributes. */ 365static __be32
366nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
367 struct iattr *iap)
368{
369 struct inode *inode = fhp->fh_dentry->d_inode;
370 int host_err;
371
372 if (iap->ia_size < inode->i_size) {
373 __be32 err;
374
375 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
376 NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
377 if (err)
378 return err;
379 }
380
381 host_err = get_write_access(inode);
382 if (host_err)
383 goto out_nfserrno;
384
385 host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
386 if (host_err)
387 goto out_put_write_access;
388 return 0;
389
390out_put_write_access:
391 put_write_access(inode);
392out_nfserrno:
393 return nfserrno(host_err);
394}
395
396/*
397 * Set various file attributes. After this call fhp needs an fh_put.
398 */
399__be32
400nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
401 int check_guard, time_t guardtime)
402{
403 struct dentry *dentry;
404 struct inode *inode;
405 int accmode = NFSD_MAY_SATTR;
406 umode_t ftype = 0;
407 __be32 err;
408 int host_err;
409 int size_change = 0;
410
411 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
412 accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
413 if (iap->ia_valid & ATTR_SIZE)
414 ftype = S_IFREG;
415
416 /* Get inode */
417 err = fh_verify(rqstp, fhp, ftype, accmode);
418 if (err)
419 goto out;
420
421 dentry = fhp->fh_dentry;
422 inode = dentry->d_inode;
423
424 /* Ignore any mode updates on symlinks */
425 if (S_ISLNK(inode->i_mode))
426 iap->ia_valid &= ~ATTR_MODE;
427
428 if (!iap->ia_valid)
429 goto out;
430
431 nfsd_sanitize_attrs(inode, iap);
432
433 /*
434 * The size case is special, it changes the file in addition to the
435 * attributes.
436 */
437 if (iap->ia_valid & ATTR_SIZE) {
438 err = nfsd_get_write_access(rqstp, fhp, iap);
439 if (err)
440 goto out;
441 size_change = 1;
442 }
419 443
420 iap->ia_valid |= ATTR_CTIME; 444 iap->ia_valid |= ATTR_CTIME;
421 445