diff options
author | Christoph Hellwig <hch@infradead.org> | 2013-11-18 08:07:30 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-29 14:11:49 -0500 |
commit | b26be14b8e496c6fa14b53ba3390b56a5988df8a (patch) | |
tree | 5087dd675557df51668e53460c578993d3de17eb /fs/nfsd | |
parent | 8b7330f9057949e8c5df82df8a76068d0129e778 (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.c | 144 |
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 | 303 | static void |
304 | nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | 304 | nfsd_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. */ | 365 | static __be32 |
366 | nfsd_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 | |||
390 | out_put_write_access: | ||
391 | put_write_access(inode); | ||
392 | out_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 | ||
400 | nfsd_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 | ||