Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-3.13' of git://linux-nfs.org/~bfields/linux

Pull nfsd bugfixes from Bruce Fields:
"A couple nfsd bugfixes"

* 'for-3.13' of git://linux-nfs.org/~bfields/linux:
nfsd4: fix xdr decoding of large non-write compounds
nfsd: make sure to balance get/put_write_access
nfsd: split up nfsd_setattr

+122 -96
+2 -1
fs/nfsd/nfs4xdr.c
··· 141 141 142 142 static void next_decode_page(struct nfsd4_compoundargs *argp) 143 143 { 144 - argp->pagelist++; 145 144 argp->p = page_address(argp->pagelist[0]); 145 + argp->pagelist++; 146 146 if (argp->pagelen < PAGE_SIZE) { 147 147 argp->end = argp->p + (argp->pagelen>>2); 148 148 argp->pagelen = 0; ··· 1229 1229 len -= pages * PAGE_SIZE; 1230 1230 1231 1231 argp->p = (__be32 *)page_address(argp->pagelist[0]); 1232 + argp->pagelist++; 1232 1233 argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); 1233 1234 } 1234 1235 argp->p += XDR_QUADLEN(len);
+120 -95
fs/nfsd/vfs.c
··· 298 298 } 299 299 300 300 /* 301 - * Set various file attributes. 302 - * N.B. After this call fhp needs an fh_put 301 + * Go over the attributes and take care of the small differences between 302 + * NFS semantics and what Linux expects. 303 + */ 304 + static void 305 + nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) 306 + { 307 + /* 308 + * NFSv2 does not differentiate between "set-[ac]time-to-now" 309 + * which only requires access, and "set-[ac]time-to-X" which 310 + * requires ownership. 311 + * So if it looks like it might be "set both to the same time which 312 + * is close to now", and if inode_change_ok fails, then we 313 + * convert to "set to now" instead of "set to explicit time" 314 + * 315 + * We only call inode_change_ok as the last test as technically 316 + * it is not an interface that we should be using. 317 + */ 318 + #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) 319 + #define MAX_TOUCH_TIME_ERROR (30*60) 320 + if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && 321 + iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { 322 + /* 323 + * Looks probable. 324 + * 325 + * Now just make sure time is in the right ballpark. 326 + * Solaris, at least, doesn't seem to care what the time 327 + * request is. We require it be within 30 minutes of now. 328 + */ 329 + time_t delta = iap->ia_atime.tv_sec - get_seconds(); 330 + if (delta < 0) 331 + delta = -delta; 332 + if (delta < MAX_TOUCH_TIME_ERROR && 333 + inode_change_ok(inode, iap) != 0) { 334 + /* 335 + * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. 336 + * This will cause notify_change to set these times 337 + * to "now" 338 + */ 339 + iap->ia_valid &= ~BOTH_TIME_SET; 340 + } 341 + } 342 + 343 + /* sanitize the mode change */ 344 + if (iap->ia_valid & ATTR_MODE) { 345 + iap->ia_mode &= S_IALLUGO; 346 + iap->ia_mode |= (inode->i_mode & ~S_IALLUGO); 347 + } 348 + 349 + /* Revoke setuid/setgid on chown */ 350 + if (!S_ISDIR(inode->i_mode) && 351 + (((iap->ia_valid & ATTR_UID) && !uid_eq(iap->ia_uid, inode->i_uid)) || 352 + ((iap->ia_valid & ATTR_GID) && !gid_eq(iap->ia_gid, inode->i_gid)))) { 353 + iap->ia_valid |= ATTR_KILL_PRIV; 354 + if (iap->ia_valid & ATTR_MODE) { 355 + /* we're setting mode too, just clear the s*id bits */ 356 + iap->ia_mode &= ~S_ISUID; 357 + if (iap->ia_mode & S_IXGRP) 358 + iap->ia_mode &= ~S_ISGID; 359 + } else { 360 + /* set ATTR_KILL_* bits and let VFS handle it */ 361 + iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); 362 + } 363 + } 364 + } 365 + 366 + static __be32 367 + nfsd_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 + 391 + out_put_write_access: 392 + put_write_access(inode); 393 + out_nfserrno: 394 + return nfserrno(host_err); 395 + } 396 + 397 + /* 398 + * Set various file attributes. After this call fhp needs an fh_put. 303 399 */ 304 400 __be32 305 401 nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ··· 429 333 if (!iap->ia_valid) 430 334 goto out; 431 335 336 + nfsd_sanitize_attrs(inode, iap); 337 + 432 338 /* 433 - * NFSv2 does not differentiate between "set-[ac]time-to-now" 434 - * which only requires access, and "set-[ac]time-to-X" which 435 - * requires ownership. 436 - * So if it looks like it might be "set both to the same time which 437 - * is close to now", and if inode_change_ok fails, then we 438 - * convert to "set to now" instead of "set to explicit time" 439 - * 440 - * We only call inode_change_ok as the last test as technically 441 - * it is not an interface that we should be using. It is only 442 - * valid if the filesystem does not define it's own i_op->setattr. 443 - */ 444 - #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) 445 - #define MAX_TOUCH_TIME_ERROR (30*60) 446 - if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && 447 - iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { 448 - /* 449 - * Looks probable. 450 - * 451 - * Now just make sure time is in the right ballpark. 452 - * Solaris, at least, doesn't seem to care what the time 453 - * request is. We require it be within 30 minutes of now. 454 - */ 455 - time_t delta = iap->ia_atime.tv_sec - get_seconds(); 456 - if (delta < 0) 457 - delta = -delta; 458 - if (delta < MAX_TOUCH_TIME_ERROR && 459 - inode_change_ok(inode, iap) != 0) { 460 - /* 461 - * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. 462 - * This will cause notify_change to set these times 463 - * to "now" 464 - */ 465 - iap->ia_valid &= ~BOTH_TIME_SET; 466 - } 467 - } 468 - 469 - /* 470 - * The size case is special. 471 - * It changes the file as well as the attributes. 339 + * The size case is special, it changes the file in addition to the 340 + * attributes. 472 341 */ 473 342 if (iap->ia_valid & ATTR_SIZE) { 474 - if (iap->ia_size < inode->i_size) { 475 - err = nfsd_permission(rqstp, fhp->fh_export, dentry, 476 - NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE); 477 - if (err) 478 - goto out; 479 - } 480 - 481 - host_err = get_write_access(inode); 482 - if (host_err) 483 - goto out_nfserr; 484 - 343 + err = nfsd_get_write_access(rqstp, fhp, iap); 344 + if (err) 345 + goto out; 485 346 size_change = 1; 486 - host_err = locks_verify_truncate(inode, NULL, iap->ia_size); 487 - if (host_err) { 488 - put_write_access(inode); 489 - goto out_nfserr; 490 - } 491 347 } 492 - 493 - /* sanitize the mode change */ 494 - if (iap->ia_valid & ATTR_MODE) { 495 - iap->ia_mode &= S_IALLUGO; 496 - iap->ia_mode |= (inode->i_mode & ~S_IALLUGO); 497 - } 498 - 499 - /* Revoke setuid/setgid on chown */ 500 - if (!S_ISDIR(inode->i_mode) && 501 - (((iap->ia_valid & ATTR_UID) && !uid_eq(iap->ia_uid, inode->i_uid)) || 502 - ((iap->ia_valid & ATTR_GID) && !gid_eq(iap->ia_gid, inode->i_gid)))) { 503 - iap->ia_valid |= ATTR_KILL_PRIV; 504 - if (iap->ia_valid & ATTR_MODE) { 505 - /* we're setting mode too, just clear the s*id bits */ 506 - iap->ia_mode &= ~S_ISUID; 507 - if (iap->ia_mode & S_IXGRP) 508 - iap->ia_mode &= ~S_ISGID; 509 - } else { 510 - /* set ATTR_KILL_* bits and let VFS handle it */ 511 - iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); 512 - } 513 - } 514 - 515 - /* Change the attributes. */ 516 348 517 349 iap->ia_valid |= ATTR_CTIME; 518 350 519 - err = nfserr_notsync; 520 - if (!check_guard || guardtime == inode->i_ctime.tv_sec) { 521 - host_err = nfsd_break_lease(inode); 522 - if (host_err) 523 - goto out_nfserr; 524 - fh_lock(fhp); 525 - 526 - host_err = notify_change(dentry, iap, NULL); 527 - err = nfserrno(host_err); 528 - fh_unlock(fhp); 351 + if (check_guard && guardtime != inode->i_ctime.tv_sec) { 352 + err = nfserr_notsync; 353 + goto out_put_write_access; 529 354 } 355 + 356 + host_err = nfsd_break_lease(inode); 357 + if (host_err) 358 + goto out_put_write_access_nfserror; 359 + 360 + fh_lock(fhp); 361 + host_err = notify_change(dentry, iap, NULL); 362 + fh_unlock(fhp); 363 + 364 + out_put_write_access_nfserror: 365 + err = nfserrno(host_err); 366 + out_put_write_access: 530 367 if (size_change) 531 368 put_write_access(inode); 532 369 if (!err) 533 370 commit_metadata(fhp); 534 371 out: 535 372 return err; 536 - 537 - out_nfserr: 538 - err = nfserrno(host_err); 539 - goto out; 540 373 } 541 374 542 375 #if defined(CONFIG_NFSD_V2_ACL) || \