aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2017-02-09 14:20:42 -0500
committerJ. Bruce Fields <bfields@redhat.com>2017-02-09 20:49:20 -0500
commit0839ffb83e44e5ff1843e932592525fc2bff23ff (patch)
treeb5ac49bc5f31db6937c2333612148977efd395af
parentd5adbfcd5f7bcc6fa58a41c5c5ada0e5c826ce2c (diff)
nfsd: Revert "nfsd: special case truncates some more"
This patch incorrectly attempted nested mnt_want_write, and incorrectly disabled nfsd's owner override for truncate. We'll fix those problems and make another attempt soon, for the moment I think the safest is to revert. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/vfs.c97
1 files changed, 60 insertions, 37 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index ca13236dbb1f..26c6fdb4bf67 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -332,6 +332,37 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
332 } 332 }
333} 333}
334 334
335static __be32
336nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
337 struct iattr *iap)
338{
339 struct inode *inode = d_inode(fhp->fh_dentry);
340 int host_err;
341
342 if (iap->ia_size < inode->i_size) {
343 __be32 err;
344
345 err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
346 NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
347 if (err)
348 return err;
349 }
350
351 host_err = get_write_access(inode);
352 if (host_err)
353 goto out_nfserrno;
354
355 host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
356 if (host_err)
357 goto out_put_write_access;
358 return 0;
359
360out_put_write_access:
361 put_write_access(inode);
362out_nfserrno:
363 return nfserrno(host_err);
364}
365
335/* 366/*
336 * Set various file attributes. After this call fhp needs an fh_put. 367 * Set various file attributes. After this call fhp needs an fh_put.
337 */ 368 */
@@ -346,6 +377,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
346 __be32 err; 377 __be32 err;
347 int host_err; 378 int host_err;
348 bool get_write_count; 379 bool get_write_count;
380 int size_change = 0;
349 381
350 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) 382 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
351 accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; 383 accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
@@ -358,11 +390,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
358 /* Get inode */ 390 /* Get inode */
359 err = fh_verify(rqstp, fhp, ftype, accmode); 391 err = fh_verify(rqstp, fhp, ftype, accmode);
360 if (err) 392 if (err)
361 return err; 393 goto out;
362 if (get_write_count) { 394 if (get_write_count) {
363 host_err = fh_want_write(fhp); 395 host_err = fh_want_write(fhp);
364 if (host_err) 396 if (host_err)
365 goto out_host_err; 397 return nfserrno(host_err);
366 } 398 }
367 399
368 dentry = fhp->fh_dentry; 400 dentry = fhp->fh_dentry;
@@ -373,59 +405,50 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
373 iap->ia_valid &= ~ATTR_MODE; 405 iap->ia_valid &= ~ATTR_MODE;
374 406
375 if (!iap->ia_valid) 407 if (!iap->ia_valid)
376 return 0; 408 goto out;
377 409
378 nfsd_sanitize_attrs(inode, iap); 410 nfsd_sanitize_attrs(inode, iap);
379 411
380 if (check_guard && guardtime != inode->i_ctime.tv_sec)
381 return nfserr_notsync;
382
383 /* 412 /*
384 * The size case is special, it changes the file in addition to the 413 * The size case is special, it changes the file in addition to the
385 * attributes, and file systems don't expect it to be mixed with 414 * attributes.
386 * "random" attribute changes. We thus split out the size change
387 * into a separate call for vfs_truncate, and do the rest as a
388 * a separate setattr call.
389 */ 415 */
390 if (iap->ia_valid & ATTR_SIZE) { 416 if (iap->ia_valid & ATTR_SIZE) {
391 struct path path = { 417 err = nfsd_get_write_access(rqstp, fhp, iap);
392 .mnt = fhp->fh_export->ex_path.mnt, 418 if (err)
393 .dentry = dentry, 419 goto out;
394 }; 420 size_change = 1;
395 bool implicit_mtime = false;
396 421
397 /* 422 /*
398 * vfs_truncate implicity updates the mtime IFF the file size 423 * RFC5661, Section 18.30.4:
399 * actually changes. Avoid the additional seattr call below if 424 * Changing the size of a file with SETATTR indirectly
400 * the only other attribute that the client sends is the mtime. 425 * changes the time_modify and change attributes.
426 *
427 * (and similar for the older RFCs)
401 */ 428 */
402 if (iap->ia_size != i_size_read(inode) && 429 if (iap->ia_size != i_size_read(inode))
403 ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0)) 430 iap->ia_valid |= ATTR_MTIME;
404 implicit_mtime = true;
405
406 host_err = vfs_truncate(&path, iap->ia_size);
407 if (host_err)
408 goto out_host_err;
409
410 iap->ia_valid &= ~ATTR_SIZE;
411 if (implicit_mtime)
412 iap->ia_valid &= ~ATTR_MTIME;
413 if (!iap->ia_valid)
414 goto done;
415 } 431 }
416 432
417 iap->ia_valid |= ATTR_CTIME; 433 iap->ia_valid |= ATTR_CTIME;
418 434
435 if (check_guard && guardtime != inode->i_ctime.tv_sec) {
436 err = nfserr_notsync;
437 goto out_put_write_access;
438 }
439
419 fh_lock(fhp); 440 fh_lock(fhp);
420 host_err = notify_change(dentry, iap, NULL); 441 host_err = notify_change(dentry, iap, NULL);
421 fh_unlock(fhp); 442 fh_unlock(fhp);
422 if (host_err) 443 err = nfserrno(host_err);
423 goto out_host_err;
424 444
425done: 445out_put_write_access:
426 host_err = commit_metadata(fhp); 446 if (size_change)
427out_host_err: 447 put_write_access(inode);
428 return nfserrno(host_err); 448 if (!err)
449 err = nfserrno(commit_metadata(fhp));
450out:
451 return err;
429} 452}
430 453
431#if defined(CONFIG_NFSD_V4) 454#if defined(CONFIG_NFSD_V4)