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