History

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.

J. Bruce Fields committed 9 years ago

Commit 0839ffb1 parent d5adbfc1 file · +60 −37Browse files

Unified · Split

fs/nfsd/vfs.c+60−37
@@ -332,6 +332,37 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) · 331 unmodified lines
332332 }
333333 }
334334
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+
335366 /*
336367 * Set various file attributes. After this call fhp needs an fh_put.
337368 */
@@ -346,6 +377,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, · 8 unmodified lines
346377 __be32 err;
347378 int host_err;
348379 bool get_write_count;
380+ int size_change = 0;
349381
350382 if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
351383 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, · 6 unmodified lines
358390 /* Get inode */
359391 err = fh_verify(rqstp, fhp, ftype, accmode);
360392 if (err)
361− return err;
393+ goto out;
362394 if (get_write_count) {
363395 host_err = fh_want_write(fhp);
364396 if (host_err)
365− goto out_host_err;
397+ return nfserrno(host_err);
366398 }
367399
368400 dentry = fhp->fh_dentry;
@@ -373,59 +405,50 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, · 4 unmodified lines
373405 iap->ia_valid &= ~ATTR_MODE;
374406
375407 if (!iap->ia_valid)
376− return 0;
408+ goto out;
377409
378410 nfsd_sanitize_attrs(inode, iap);
379411
380− if (check_guard && guardtime != inode->i_ctime.tv_sec)
381− return nfserr_notsync;
382−
383412 /*
384413 * 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
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.
414+ * attributes.
389415 */
390416 if (iap->ia_valid & ATTR_SIZE) {
391− struct path path = {
392− .mnt = fhp->fh_export->ex_path.mnt,
393− .dentry = dentry,
394− };
395− bool implicit_mtime = false;
417+ err = nfsd_get_write_access(rqstp, fhp, iap);
418+ if (err)
419+ goto out;
420+ size_change = 1;
396421
397422 /*
398− * vfs_truncate implicity updates the mtime IFF the file size
399− * actually changes. Avoid the additional seattr call below if
400− * the only other attribute that the client sends is the mtime.
423+ * RFC5661, Section 18.30.4:
424+ * Changing the size of a file with SETATTR indirectly
425+ * changes the time_modify and change attributes.
426+ *
427+ * (and similar for the older RFCs)
401428 */
402− if (iap->ia_size != i_size_read(inode) &&
403− ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0))
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;
429+ if (iap->ia_size != i_size_read(inode))
430+ iap->ia_valid |= ATTR_MTIME;
415431 }
416432
417433 iap->ia_valid |= ATTR_CTIME;
418434
435+ if (check_guard && guardtime != inode->i_ctime.tv_sec) {
436+ err = nfserr_notsync;
437+ goto out_put_write_access;
438+ }
439+
419440 fh_lock(fhp);
420441 host_err = notify_change(dentry, iap, NULL);
421442 fh_unlock(fhp);
422− if (host_err)
423− goto out_host_err;
443+ err = nfserrno(host_err);
424444
425−done:
426− host_err = commit_metadata(fhp);
427−out_host_err:
428− return nfserrno(host_err);
445+out_put_write_access:
446+ if (size_change)
447+ put_write_access(inode);
448+ if (!err)
449+ err = nfserrno(commit_metadata(fhp));
450+out:
451+ return err;
429452 }
430453
431454 #if defined(CONFIG_NFSD_V4)