diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-02 15:49:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-02 15:49:58 -0500 |
commit | 1fc576b82b96d9bb033ff0098e1c0bf68de282b2 (patch) | |
tree | c4f8cb6640de3dff75ad7c33de0eedae4e230613 | |
parent | e4178c75049c581114998a850ecdfa5a2811cde6 (diff) | |
parent | 034dd34ff4916ec1f8f74e39ca3efb04eab2f791 (diff) |
Merge tag 'nfsd-4.10-2' of git://linux-nfs.org/~bfields/linux
Pull nfsd fixes from Bruce Fields:
"Three more miscellaneous nfsd bugfixes"
* tag 'nfsd-4.10-2' of git://linux-nfs.org/~bfields/linux:
svcrpc: fix oops in absence of krb5 module
nfsd: special case truncates some more
NFSD: Fix a null reference case in find_or_create_lock_stateid()
-rw-r--r-- | fs/nfsd/nfs4layouts.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 19 | ||||
-rw-r--r-- | fs/nfsd/state.h | 4 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 97 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_rpc_xdr.c | 2 |
5 files changed, 51 insertions, 76 deletions
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 596205d939a1..1fc07a9c70e9 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c | |||
@@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, | |||
223 | struct nfs4_layout_stateid *ls; | 223 | struct nfs4_layout_stateid *ls; |
224 | struct nfs4_stid *stp; | 224 | struct nfs4_stid *stp; |
225 | 225 | ||
226 | stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache); | 226 | stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache, |
227 | nfsd4_free_layout_stateid); | ||
227 | if (!stp) | 228 | if (!stp) |
228 | return NULL; | 229 | return NULL; |
229 | stp->sc_free = nfsd4_free_layout_stateid; | 230 | |
230 | get_nfs4_file(fp); | 231 | get_nfs4_file(fp); |
231 | stp->sc_file = fp; | 232 | stp->sc_file = fp; |
232 | 233 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4b4beaaa4eaa..a0dee8ae9f97 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -633,8 +633,8 @@ out: | |||
633 | return co; | 633 | return co; |
634 | } | 634 | } |
635 | 635 | ||
636 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | 636 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, |
637 | struct kmem_cache *slab) | 637 | void (*sc_free)(struct nfs4_stid *)) |
638 | { | 638 | { |
639 | struct nfs4_stid *stid; | 639 | struct nfs4_stid *stid; |
640 | int new_id; | 640 | int new_id; |
@@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | |||
650 | idr_preload_end(); | 650 | idr_preload_end(); |
651 | if (new_id < 0) | 651 | if (new_id < 0) |
652 | goto out_free; | 652 | goto out_free; |
653 | |||
654 | stid->sc_free = sc_free; | ||
653 | stid->sc_client = cl; | 655 | stid->sc_client = cl; |
654 | stid->sc_stateid.si_opaque.so_id = new_id; | 656 | stid->sc_stateid.si_opaque.so_id = new_id; |
655 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; | 657 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; |
@@ -675,15 +677,12 @@ out_free: | |||
675 | static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) | 677 | static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) |
676 | { | 678 | { |
677 | struct nfs4_stid *stid; | 679 | struct nfs4_stid *stid; |
678 | struct nfs4_ol_stateid *stp; | ||
679 | 680 | ||
680 | stid = nfs4_alloc_stid(clp, stateid_slab); | 681 | stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); |
681 | if (!stid) | 682 | if (!stid) |
682 | return NULL; | 683 | return NULL; |
683 | 684 | ||
684 | stp = openlockstateid(stid); | 685 | return openlockstateid(stid); |
685 | stp->st_stid.sc_free = nfs4_free_ol_stateid; | ||
686 | return stp; | ||
687 | } | 686 | } |
688 | 687 | ||
689 | static void nfs4_free_deleg(struct nfs4_stid *stid) | 688 | static void nfs4_free_deleg(struct nfs4_stid *stid) |
@@ -781,11 +780,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, | |||
781 | goto out_dec; | 780 | goto out_dec; |
782 | if (delegation_blocked(¤t_fh->fh_handle)) | 781 | if (delegation_blocked(¤t_fh->fh_handle)) |
783 | goto out_dec; | 782 | goto out_dec; |
784 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); | 783 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); |
785 | if (dp == NULL) | 784 | if (dp == NULL) |
786 | goto out_dec; | 785 | goto out_dec; |
787 | 786 | ||
788 | dp->dl_stid.sc_free = nfs4_free_deleg; | ||
789 | /* | 787 | /* |
790 | * delegation seqid's are never incremented. The 4.1 special | 788 | * delegation seqid's are never incremented. The 4.1 special |
791 | * meaning of seqid 0 isn't meaningful, really, but let's avoid | 789 | * meaning of seqid 0 isn't meaningful, really, but let's avoid |
@@ -5580,7 +5578,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, | |||
5580 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); | 5578 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); |
5581 | get_nfs4_file(fp); | 5579 | get_nfs4_file(fp); |
5582 | stp->st_stid.sc_file = fp; | 5580 | stp->st_stid.sc_file = fp; |
5583 | stp->st_stid.sc_free = nfs4_free_lock_stateid; | ||
5584 | stp->st_access_bmap = 0; | 5581 | stp->st_access_bmap = 0; |
5585 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 5582 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
5586 | stp->st_openstp = open_stp; | 5583 | stp->st_openstp = open_stp; |
@@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, | |||
5623 | lst = find_lock_stateid(lo, fi); | 5620 | lst = find_lock_stateid(lo, fi); |
5624 | if (lst == NULL) { | 5621 | if (lst == NULL) { |
5625 | spin_unlock(&clp->cl_lock); | 5622 | spin_unlock(&clp->cl_lock); |
5626 | ns = nfs4_alloc_stid(clp, stateid_slab); | 5623 | ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); |
5627 | if (ns == NULL) | 5624 | if (ns == NULL) |
5628 | return NULL; | 5625 | return NULL; |
5629 | 5626 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index c9399366f9df..4516e8b7d776 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, | |||
603 | __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, | 603 | __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, |
604 | stateid_t *stateid, unsigned char typemask, | 604 | stateid_t *stateid, unsigned char typemask, |
605 | struct nfs4_stid **s, struct nfsd_net *nn); | 605 | struct nfs4_stid **s, struct nfsd_net *nn); |
606 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | 606 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, |
607 | struct kmem_cache *slab); | 607 | void (*sc_free)(struct nfs4_stid *)); |
608 | void nfs4_unhash_stid(struct nfs4_stid *s); | 608 | void nfs4_unhash_stid(struct nfs4_stid *s); |
609 | void nfs4_put_stid(struct nfs4_stid *s); | 609 | void nfs4_put_stid(struct nfs4_stid *s); |
610 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); | 610 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 26c6fdb4bf67..ca13236dbb1f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -332,37 +332,6 @@ 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 | |||
366 | /* | 335 | /* |
367 | * Set various file attributes. After this call fhp needs an fh_put. | 336 | * Set various file attributes. After this call fhp needs an fh_put. |
368 | */ | 337 | */ |
@@ -377,7 +346,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
377 | __be32 err; | 346 | __be32 err; |
378 | int host_err; | 347 | int host_err; |
379 | bool get_write_count; | 348 | bool get_write_count; |
380 | int size_change = 0; | ||
381 | 349 | ||
382 | if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) | 350 | if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) |
383 | accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; | 351 | accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; |
@@ -390,11 +358,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
390 | /* Get inode */ | 358 | /* Get inode */ |
391 | err = fh_verify(rqstp, fhp, ftype, accmode); | 359 | err = fh_verify(rqstp, fhp, ftype, accmode); |
392 | if (err) | 360 | if (err) |
393 | goto out; | 361 | return err; |
394 | if (get_write_count) { | 362 | if (get_write_count) { |
395 | host_err = fh_want_write(fhp); | 363 | host_err = fh_want_write(fhp); |
396 | if (host_err) | 364 | if (host_err) |
397 | return nfserrno(host_err); | 365 | goto out_host_err; |
398 | } | 366 | } |
399 | 367 | ||
400 | dentry = fhp->fh_dentry; | 368 | dentry = fhp->fh_dentry; |
@@ -405,50 +373,59 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
405 | iap->ia_valid &= ~ATTR_MODE; | 373 | iap->ia_valid &= ~ATTR_MODE; |
406 | 374 | ||
407 | if (!iap->ia_valid) | 375 | if (!iap->ia_valid) |
408 | goto out; | 376 | return 0; |
409 | 377 | ||
410 | nfsd_sanitize_attrs(inode, iap); | 378 | nfsd_sanitize_attrs(inode, iap); |
411 | 379 | ||
380 | if (check_guard && guardtime != inode->i_ctime.tv_sec) | ||
381 | return nfserr_notsync; | ||
382 | |||
412 | /* | 383 | /* |
413 | * The size case is special, it changes the file in addition to the | 384 | * The size case is special, it changes the file in addition to the |
414 | * attributes. | 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. | ||
415 | */ | 389 | */ |
416 | if (iap->ia_valid & ATTR_SIZE) { | 390 | if (iap->ia_valid & ATTR_SIZE) { |
417 | err = nfsd_get_write_access(rqstp, fhp, iap); | 391 | struct path path = { |
418 | if (err) | 392 | .mnt = fhp->fh_export->ex_path.mnt, |
419 | goto out; | 393 | .dentry = dentry, |
420 | size_change = 1; | 394 | }; |
395 | bool implicit_mtime = false; | ||
421 | 396 | ||
422 | /* | 397 | /* |
423 | * RFC5661, Section 18.30.4: | 398 | * vfs_truncate implicity updates the mtime IFF the file size |
424 | * Changing the size of a file with SETATTR indirectly | 399 | * actually changes. Avoid the additional seattr call below if |
425 | * changes the time_modify and change attributes. | 400 | * the only other attribute that the client sends is the mtime. |
426 | * | ||
427 | * (and similar for the older RFCs) | ||
428 | */ | 401 | */ |
429 | if (iap->ia_size != i_size_read(inode)) | 402 | if (iap->ia_size != i_size_read(inode) && |
430 | iap->ia_valid |= ATTR_MTIME; | 403 | ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0)) |
431 | } | 404 | implicit_mtime = true; |
432 | 405 | ||
433 | iap->ia_valid |= ATTR_CTIME; | 406 | host_err = vfs_truncate(&path, iap->ia_size); |
407 | if (host_err) | ||
408 | goto out_host_err; | ||
434 | 409 | ||
435 | if (check_guard && guardtime != inode->i_ctime.tv_sec) { | 410 | iap->ia_valid &= ~ATTR_SIZE; |
436 | err = nfserr_notsync; | 411 | if (implicit_mtime) |
437 | goto out_put_write_access; | 412 | iap->ia_valid &= ~ATTR_MTIME; |
413 | if (!iap->ia_valid) | ||
414 | goto done; | ||
438 | } | 415 | } |
439 | 416 | ||
417 | iap->ia_valid |= ATTR_CTIME; | ||
418 | |||
440 | fh_lock(fhp); | 419 | fh_lock(fhp); |
441 | host_err = notify_change(dentry, iap, NULL); | 420 | host_err = notify_change(dentry, iap, NULL); |
442 | fh_unlock(fhp); | 421 | fh_unlock(fhp); |
443 | err = nfserrno(host_err); | 422 | if (host_err) |
423 | goto out_host_err; | ||
444 | 424 | ||
445 | out_put_write_access: | 425 | done: |
446 | if (size_change) | 426 | host_err = commit_metadata(fhp); |
447 | put_write_access(inode); | 427 | out_host_err: |
448 | if (!err) | 428 | return nfserrno(host_err); |
449 | err = nfserrno(commit_metadata(fhp)); | ||
450 | out: | ||
451 | return err; | ||
452 | } | 429 | } |
453 | 430 | ||
454 | #if defined(CONFIG_NFSD_V4) | 431 | #if defined(CONFIG_NFSD_V4) |
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index dc6fb79a361f..25d9a9cf7b66 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c | |||
@@ -260,7 +260,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr, | |||
260 | if (!oa->data) | 260 | if (!oa->data) |
261 | return -ENOMEM; | 261 | return -ENOMEM; |
262 | 262 | ||
263 | creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL); | 263 | creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL); |
264 | if (!creds) { | 264 | if (!creds) { |
265 | kfree(oa->data); | 265 | kfree(oa->data); |
266 | return -ENOMEM; | 266 | return -ENOMEM; |