diff options
author | J. Bruce Fields <bfields@redhat.com> | 2017-02-09 14:20:42 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-02-09 20:49:20 -0500 |
commit | 0839ffb83e44e5ff1843e932592525fc2bff23ff (patch) | |
tree | b5ac49bc5f31db6937c2333612148977efd395af | |
parent | d5adbfcd5f7bcc6fa58a41c5c5ada0e5c826ce2c (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.c | 97 |
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 | ||
335 | static __be32 | ||
336 | nfsd_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 | |||
360 | out_put_write_access: | ||
361 | put_write_access(inode); | ||
362 | out_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 | ||
425 | done: | 445 | out_put_write_access: |
426 | host_err = commit_metadata(fhp); | 446 | if (size_change) |
427 | out_host_err: | 447 | put_write_access(inode); |
428 | return nfserrno(host_err); | 448 | if (!err) |
449 | err = nfserrno(commit_metadata(fhp)); | ||
450 | out: | ||
451 | return err; | ||
429 | } | 452 | } |
430 | 453 | ||
431 | #if defined(CONFIG_NFSD_V4) | 454 | #if defined(CONFIG_NFSD_V4) |