diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/client.c | 2 | ||||
| -rw-r--r-- | fs/nfs/delegation.c | 45 | ||||
| -rw-r--r-- | fs/nfs/dir.c | 22 | ||||
| -rw-r--r-- | fs/nfs/file.c | 11 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 111 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs3proc.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs3xdr.c | 5 | ||||
| -rw-r--r-- | fs/nfs/nfs4client.c | 9 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 31 | ||||
| -rw-r--r-- | fs/nfs/nfs4session.h | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 18 | ||||
| -rw-r--r-- | fs/nfs/proc.c | 6 | ||||
| -rw-r--r-- | fs/nfs/write.c | 30 |
14 files changed, 237 insertions, 59 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index f9f4845db989..19874151e95c 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -433,7 +433,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
| 433 | 433 | ||
| 434 | static bool nfs_client_init_is_complete(const struct nfs_client *clp) | 434 | static bool nfs_client_init_is_complete(const struct nfs_client *clp) |
| 435 | { | 435 | { |
| 436 | return clp->cl_cons_state != NFS_CS_INITING; | 436 | return clp->cl_cons_state <= NFS_CS_READY; |
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | int nfs_wait_client_init_complete(const struct nfs_client *clp) | 439 | int nfs_wait_client_init_complete(const struct nfs_client *clp) |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index a1f0685b42ff..a6ad68865880 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -181,8 +181,8 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, | |||
| 181 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, | 181 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, |
| 182 | &delegation->flags); | 182 | &delegation->flags); |
| 183 | spin_unlock(&delegation->lock); | 183 | spin_unlock(&delegation->lock); |
| 184 | put_rpccred(oldcred); | ||
| 185 | rcu_read_unlock(); | 184 | rcu_read_unlock(); |
| 185 | put_rpccred(oldcred); | ||
| 186 | trace_nfs4_reclaim_delegation(inode, res->delegation_type); | 186 | trace_nfs4_reclaim_delegation(inode, res->delegation_type); |
| 187 | } else { | 187 | } else { |
| 188 | /* We appear to have raced with a delegation return. */ | 188 | /* We appear to have raced with a delegation return. */ |
| @@ -370,7 +370,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 370 | delegation = NULL; | 370 | delegation = NULL; |
| 371 | goto out; | 371 | goto out; |
| 372 | } | 372 | } |
| 373 | freeme = nfs_detach_delegation_locked(nfsi, | 373 | if (test_and_set_bit(NFS_DELEGATION_RETURNING, |
| 374 | &old_delegation->flags)) | ||
| 375 | goto out; | ||
| 376 | freeme = nfs_detach_delegation_locked(nfsi, | ||
| 374 | old_delegation, clp); | 377 | old_delegation, clp); |
| 375 | if (freeme == NULL) | 378 | if (freeme == NULL) |
| 376 | goto out; | 379 | goto out; |
| @@ -433,6 +436,8 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation) | |||
| 433 | { | 436 | { |
| 434 | bool ret = false; | 437 | bool ret = false; |
| 435 | 438 | ||
| 439 | if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) | ||
| 440 | goto out; | ||
| 436 | if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags)) | 441 | if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags)) |
| 437 | ret = true; | 442 | ret = true; |
| 438 | if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) { | 443 | if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) { |
| @@ -444,6 +449,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation) | |||
| 444 | ret = true; | 449 | ret = true; |
| 445 | spin_unlock(&delegation->lock); | 450 | spin_unlock(&delegation->lock); |
| 446 | } | 451 | } |
| 452 | out: | ||
| 447 | return ret; | 453 | return ret; |
| 448 | } | 454 | } |
| 449 | 455 | ||
| @@ -471,14 +477,20 @@ restart: | |||
| 471 | super_list) { | 477 | super_list) { |
| 472 | if (!nfs_delegation_need_return(delegation)) | 478 | if (!nfs_delegation_need_return(delegation)) |
| 473 | continue; | 479 | continue; |
| 474 | inode = nfs_delegation_grab_inode(delegation); | 480 | if (!nfs_sb_active(server->super)) |
| 475 | if (inode == NULL) | ||
| 476 | continue; | 481 | continue; |
| 482 | inode = nfs_delegation_grab_inode(delegation); | ||
| 483 | if (inode == NULL) { | ||
| 484 | rcu_read_unlock(); | ||
| 485 | nfs_sb_deactive(server->super); | ||
| 486 | goto restart; | ||
| 487 | } | ||
| 477 | delegation = nfs_start_delegation_return_locked(NFS_I(inode)); | 488 | delegation = nfs_start_delegation_return_locked(NFS_I(inode)); |
| 478 | rcu_read_unlock(); | 489 | rcu_read_unlock(); |
| 479 | 490 | ||
| 480 | err = nfs_end_delegation_return(inode, delegation, 0); | 491 | err = nfs_end_delegation_return(inode, delegation, 0); |
| 481 | iput(inode); | 492 | iput(inode); |
| 493 | nfs_sb_deactive(server->super); | ||
| 482 | if (!err) | 494 | if (!err) |
| 483 | goto restart; | 495 | goto restart; |
| 484 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | 496 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); |
| @@ -809,19 +821,30 @@ restart: | |||
| 809 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 821 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
| 810 | list_for_each_entry_rcu(delegation, &server->delegations, | 822 | list_for_each_entry_rcu(delegation, &server->delegations, |
| 811 | super_list) { | 823 | super_list) { |
| 824 | if (test_bit(NFS_DELEGATION_RETURNING, | ||
| 825 | &delegation->flags)) | ||
| 826 | continue; | ||
| 812 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, | 827 | if (test_bit(NFS_DELEGATION_NEED_RECLAIM, |
| 813 | &delegation->flags) == 0) | 828 | &delegation->flags) == 0) |
| 814 | continue; | 829 | continue; |
| 815 | inode = nfs_delegation_grab_inode(delegation); | 830 | if (!nfs_sb_active(server->super)) |
| 816 | if (inode == NULL) | ||
| 817 | continue; | 831 | continue; |
| 818 | delegation = nfs_detach_delegation(NFS_I(inode), | 832 | inode = nfs_delegation_grab_inode(delegation); |
| 819 | delegation, server); | 833 | if (inode == NULL) { |
| 834 | rcu_read_unlock(); | ||
| 835 | nfs_sb_deactive(server->super); | ||
| 836 | goto restart; | ||
| 837 | } | ||
| 838 | delegation = nfs_start_delegation_return_locked(NFS_I(inode)); | ||
| 820 | rcu_read_unlock(); | 839 | rcu_read_unlock(); |
| 821 | 840 | if (delegation != NULL) { | |
| 822 | if (delegation != NULL) | 841 | delegation = nfs_detach_delegation(NFS_I(inode), |
| 823 | nfs_free_delegation(delegation); | 842 | delegation, server); |
| 843 | if (delegation != NULL) | ||
| 844 | nfs_free_delegation(delegation); | ||
| 845 | } | ||
| 824 | iput(inode); | 846 | iput(inode); |
| 847 | nfs_sb_deactive(server->super); | ||
| 825 | goto restart; | 848 | goto restart; |
| 826 | } | 849 | } |
| 827 | } | 850 | } |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 9b0c55cb2a2e..c19e16f0b2d0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -408,14 +408,22 @@ static int xdr_decode(nfs_readdir_descriptor_t *desc, | |||
| 408 | return 0; | 408 | return 0; |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | /* Match file and dirent using either filehandle or fileid | ||
| 412 | * Note: caller is responsible for checking the fsid | ||
| 413 | */ | ||
| 411 | static | 414 | static |
| 412 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) | 415 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) |
| 413 | { | 416 | { |
| 417 | struct nfs_inode *nfsi; | ||
| 418 | |||
| 414 | if (dentry->d_inode == NULL) | 419 | if (dentry->d_inode == NULL) |
| 415 | goto different; | 420 | goto different; |
| 416 | if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0) | 421 | |
| 417 | goto different; | 422 | nfsi = NFS_I(dentry->d_inode); |
| 418 | return 1; | 423 | if (entry->fattr->fileid == nfsi->fileid) |
| 424 | return 1; | ||
| 425 | if (nfs_compare_fh(entry->fh, &nfsi->fh) == 0) | ||
| 426 | return 1; | ||
| 419 | different: | 427 | different: |
| 420 | return 0; | 428 | return 0; |
| 421 | } | 429 | } |
| @@ -469,6 +477,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
| 469 | struct inode *inode; | 477 | struct inode *inode; |
| 470 | int status; | 478 | int status; |
| 471 | 479 | ||
| 480 | if (!(entry->fattr->valid & NFS_ATTR_FATTR_FILEID)) | ||
| 481 | return; | ||
| 482 | if (!(entry->fattr->valid & NFS_ATTR_FATTR_FSID)) | ||
| 483 | return; | ||
| 472 | if (filename.name[0] == '.') { | 484 | if (filename.name[0] == '.') { |
| 473 | if (filename.len == 1) | 485 | if (filename.len == 1) |
| 474 | return; | 486 | return; |
| @@ -479,6 +491,10 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
| 479 | 491 | ||
| 480 | dentry = d_lookup(parent, &filename); | 492 | dentry = d_lookup(parent, &filename); |
| 481 | if (dentry != NULL) { | 493 | if (dentry != NULL) { |
| 494 | /* Is there a mountpoint here? If so, just exit */ | ||
| 495 | if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid, | ||
| 496 | &entry->fattr->fsid)) | ||
| 497 | goto out; | ||
| 482 | if (nfs_same_file(dentry, entry)) { | 498 | if (nfs_same_file(dentry, entry)) { |
| 483 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 499 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 484 | status = nfs_refresh_inode(dentry->d_inode, entry->fattr); | 500 | status = nfs_refresh_inode(dentry->d_inode, entry->fattr); |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 94712fc781fa..e679d24c39d3 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to) | |||
| 178 | iocb->ki_filp, | 178 | iocb->ki_filp, |
| 179 | iov_iter_count(to), (unsigned long) iocb->ki_pos); | 179 | iov_iter_count(to), (unsigned long) iocb->ki_pos); |
| 180 | 180 | ||
| 181 | result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | 181 | result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping); |
| 182 | if (!result) { | 182 | if (!result) { |
| 183 | result = generic_file_read_iter(iocb, to); | 183 | result = generic_file_read_iter(iocb, to); |
| 184 | if (result > 0) | 184 | if (result > 0) |
| @@ -199,7 +199,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
| 199 | dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", | 199 | dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", |
| 200 | filp, (unsigned long) count, (unsigned long long) *ppos); | 200 | filp, (unsigned long) count, (unsigned long long) *ppos); |
| 201 | 201 | ||
| 202 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 202 | res = nfs_revalidate_mapping_protected(inode, filp->f_mapping); |
| 203 | if (!res) { | 203 | if (!res) { |
| 204 | res = generic_file_splice_read(filp, ppos, pipe, count, flags); | 204 | res = generic_file_splice_read(filp, ppos, pipe, count, flags); |
| 205 | if (res > 0) | 205 | if (res > 0) |
| @@ -372,6 +372,10 @@ start: | |||
| 372 | nfs_wait_bit_killable, TASK_KILLABLE); | 372 | nfs_wait_bit_killable, TASK_KILLABLE); |
| 373 | if (ret) | 373 | if (ret) |
| 374 | return ret; | 374 | return ret; |
| 375 | /* | ||
| 376 | * Wait for O_DIRECT to complete | ||
| 377 | */ | ||
| 378 | nfs_inode_dio_wait(mapping->host); | ||
| 375 | 379 | ||
| 376 | page = grab_cache_page_write_begin(mapping, index, flags); | 380 | page = grab_cache_page_write_begin(mapping, index, flags); |
| 377 | if (!page) | 381 | if (!page) |
| @@ -619,6 +623,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 619 | /* make sure the cache has finished storing the page */ | 623 | /* make sure the cache has finished storing the page */ |
| 620 | nfs_fscache_wait_on_page_write(NFS_I(inode), page); | 624 | nfs_fscache_wait_on_page_write(NFS_I(inode), page); |
| 621 | 625 | ||
| 626 | wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING, | ||
| 627 | nfs_wait_bit_killable, TASK_KILLABLE); | ||
| 628 | |||
| 622 | lock_page(page); | 629 | lock_page(page); |
| 623 | mapping = page_file_mapping(page); | 630 | mapping = page_file_mapping(page); |
| 624 | if (mapping != inode->i_mapping) | 631 | if (mapping != inode->i_mapping) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 83107be3dd01..d42dff6d5e98 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -556,6 +556,7 @@ EXPORT_SYMBOL_GPL(nfs_setattr); | |||
| 556 | * This is a copy of the common vmtruncate, but with the locking | 556 | * This is a copy of the common vmtruncate, but with the locking |
| 557 | * corrected to take into account the fact that NFS requires | 557 | * corrected to take into account the fact that NFS requires |
| 558 | * inode->i_size to be updated under the inode->i_lock. | 558 | * inode->i_size to be updated under the inode->i_lock. |
| 559 | * Note: must be called with inode->i_lock held! | ||
| 559 | */ | 560 | */ |
| 560 | static int nfs_vmtruncate(struct inode * inode, loff_t offset) | 561 | static int nfs_vmtruncate(struct inode * inode, loff_t offset) |
| 561 | { | 562 | { |
| @@ -565,14 +566,14 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset) | |||
| 565 | if (err) | 566 | if (err) |
| 566 | goto out; | 567 | goto out; |
| 567 | 568 | ||
| 568 | spin_lock(&inode->i_lock); | ||
| 569 | i_size_write(inode, offset); | 569 | i_size_write(inode, offset); |
| 570 | /* Optimisation */ | 570 | /* Optimisation */ |
| 571 | if (offset == 0) | 571 | if (offset == 0) |
| 572 | NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA; | 572 | NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA; |
| 573 | spin_unlock(&inode->i_lock); | ||
| 574 | 573 | ||
| 574 | spin_unlock(&inode->i_lock); | ||
| 575 | truncate_pagecache(inode, offset); | 575 | truncate_pagecache(inode, offset); |
| 576 | spin_lock(&inode->i_lock); | ||
| 576 | out: | 577 | out: |
| 577 | return err; | 578 | return err; |
| 578 | } | 579 | } |
| @@ -585,10 +586,15 @@ out: | |||
| 585 | * Note: we do this in the *proc.c in order to ensure that | 586 | * Note: we do this in the *proc.c in order to ensure that |
| 586 | * it works for things like exclusive creates too. | 587 | * it works for things like exclusive creates too. |
| 587 | */ | 588 | */ |
| 588 | void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) | 589 | void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, |
| 590 | struct nfs_fattr *fattr) | ||
| 589 | { | 591 | { |
| 592 | /* Barrier: bump the attribute generation count. */ | ||
| 593 | nfs_fattr_set_barrier(fattr); | ||
| 594 | |||
| 595 | spin_lock(&inode->i_lock); | ||
| 596 | NFS_I(inode)->attr_gencount = fattr->gencount; | ||
| 590 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) { | 597 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) { |
| 591 | spin_lock(&inode->i_lock); | ||
| 592 | if ((attr->ia_valid & ATTR_MODE) != 0) { | 598 | if ((attr->ia_valid & ATTR_MODE) != 0) { |
| 593 | int mode = attr->ia_mode & S_IALLUGO; | 599 | int mode = attr->ia_mode & S_IALLUGO; |
| 594 | mode |= inode->i_mode & ~S_IALLUGO; | 600 | mode |= inode->i_mode & ~S_IALLUGO; |
| @@ -600,12 +606,13 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) | |||
| 600 | inode->i_gid = attr->ia_gid; | 606 | inode->i_gid = attr->ia_gid; |
| 601 | nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS | 607 | nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS |
| 602 | | NFS_INO_INVALID_ACL); | 608 | | NFS_INO_INVALID_ACL); |
| 603 | spin_unlock(&inode->i_lock); | ||
| 604 | } | 609 | } |
| 605 | if ((attr->ia_valid & ATTR_SIZE) != 0) { | 610 | if ((attr->ia_valid & ATTR_SIZE) != 0) { |
| 606 | nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); | 611 | nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); |
| 607 | nfs_vmtruncate(inode, attr->ia_size); | 612 | nfs_vmtruncate(inode, attr->ia_size); |
| 608 | } | 613 | } |
| 614 | nfs_update_inode(inode, fattr); | ||
| 615 | spin_unlock(&inode->i_lock); | ||
| 609 | } | 616 | } |
| 610 | EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); | 617 | EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); |
| 611 | 618 | ||
| @@ -1028,6 +1035,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map | |||
| 1028 | 1035 | ||
| 1029 | if (mapping->nrpages != 0) { | 1036 | if (mapping->nrpages != 0) { |
| 1030 | if (S_ISREG(inode->i_mode)) { | 1037 | if (S_ISREG(inode->i_mode)) { |
| 1038 | unmap_mapping_range(mapping, 0, 0, 0); | ||
| 1031 | ret = nfs_sync_mapping(mapping); | 1039 | ret = nfs_sync_mapping(mapping); |
| 1032 | if (ret < 0) | 1040 | if (ret < 0) |
| 1033 | return ret; | 1041 | return ret; |
| @@ -1060,11 +1068,14 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode) | |||
| 1060 | } | 1068 | } |
| 1061 | 1069 | ||
| 1062 | /** | 1070 | /** |
| 1063 | * nfs_revalidate_mapping - Revalidate the pagecache | 1071 | * __nfs_revalidate_mapping - Revalidate the pagecache |
| 1064 | * @inode - pointer to host inode | 1072 | * @inode - pointer to host inode |
| 1065 | * @mapping - pointer to mapping | 1073 | * @mapping - pointer to mapping |
| 1074 | * @may_lock - take inode->i_mutex? | ||
| 1066 | */ | 1075 | */ |
| 1067 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | 1076 | static int __nfs_revalidate_mapping(struct inode *inode, |
| 1077 | struct address_space *mapping, | ||
| 1078 | bool may_lock) | ||
| 1068 | { | 1079 | { |
| 1069 | struct nfs_inode *nfsi = NFS_I(inode); | 1080 | struct nfs_inode *nfsi = NFS_I(inode); |
| 1070 | unsigned long *bitlock = &nfsi->flags; | 1081 | unsigned long *bitlock = &nfsi->flags; |
| @@ -1113,7 +1124,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
| 1113 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; | 1124 | nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; |
| 1114 | spin_unlock(&inode->i_lock); | 1125 | spin_unlock(&inode->i_lock); |
| 1115 | trace_nfs_invalidate_mapping_enter(inode); | 1126 | trace_nfs_invalidate_mapping_enter(inode); |
| 1116 | ret = nfs_invalidate_mapping(inode, mapping); | 1127 | if (may_lock) { |
| 1128 | mutex_lock(&inode->i_mutex); | ||
| 1129 | ret = nfs_invalidate_mapping(inode, mapping); | ||
| 1130 | mutex_unlock(&inode->i_mutex); | ||
| 1131 | } else | ||
| 1132 | ret = nfs_invalidate_mapping(inode, mapping); | ||
| 1117 | trace_nfs_invalidate_mapping_exit(inode, ret); | 1133 | trace_nfs_invalidate_mapping_exit(inode, ret); |
| 1118 | 1134 | ||
| 1119 | clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); | 1135 | clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); |
| @@ -1123,6 +1139,29 @@ out: | |||
| 1123 | return ret; | 1139 | return ret; |
| 1124 | } | 1140 | } |
| 1125 | 1141 | ||
| 1142 | /** | ||
| 1143 | * nfs_revalidate_mapping - Revalidate the pagecache | ||
| 1144 | * @inode - pointer to host inode | ||
| 1145 | * @mapping - pointer to mapping | ||
| 1146 | */ | ||
| 1147 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
| 1148 | { | ||
| 1149 | return __nfs_revalidate_mapping(inode, mapping, false); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | /** | ||
| 1153 | * nfs_revalidate_mapping_protected - Revalidate the pagecache | ||
| 1154 | * @inode - pointer to host inode | ||
| 1155 | * @mapping - pointer to mapping | ||
| 1156 | * | ||
| 1157 | * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex | ||
| 1158 | * while invalidating the mapping. | ||
| 1159 | */ | ||
| 1160 | int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping) | ||
| 1161 | { | ||
| 1162 | return __nfs_revalidate_mapping(inode, mapping, true); | ||
| 1163 | } | ||
| 1164 | |||
| 1126 | static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) | 1165 | static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) |
| 1127 | { | 1166 | { |
| 1128 | struct nfs_inode *nfsi = NFS_I(inode); | 1167 | struct nfs_inode *nfsi = NFS_I(inode); |
| @@ -1231,13 +1270,6 @@ static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fat | |||
| 1231 | return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0; | 1270 | return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0; |
| 1232 | } | 1271 | } |
| 1233 | 1272 | ||
| 1234 | static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr) | ||
| 1235 | { | ||
| 1236 | if (!(fattr->valid & NFS_ATTR_FATTR_SIZE)) | ||
| 1237 | return 0; | ||
| 1238 | return nfs_size_to_loff_t(fattr->size) > i_size_read(inode); | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | static atomic_long_t nfs_attr_generation_counter; | 1273 | static atomic_long_t nfs_attr_generation_counter; |
| 1242 | 1274 | ||
| 1243 | static unsigned long nfs_read_attr_generation_counter(void) | 1275 | static unsigned long nfs_read_attr_generation_counter(void) |
| @@ -1249,6 +1281,7 @@ unsigned long nfs_inc_attr_generation_counter(void) | |||
| 1249 | { | 1281 | { |
| 1250 | return atomic_long_inc_return(&nfs_attr_generation_counter); | 1282 | return atomic_long_inc_return(&nfs_attr_generation_counter); |
| 1251 | } | 1283 | } |
| 1284 | EXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter); | ||
| 1252 | 1285 | ||
| 1253 | void nfs_fattr_init(struct nfs_fattr *fattr) | 1286 | void nfs_fattr_init(struct nfs_fattr *fattr) |
| 1254 | { | 1287 | { |
| @@ -1260,6 +1293,22 @@ void nfs_fattr_init(struct nfs_fattr *fattr) | |||
| 1260 | } | 1293 | } |
| 1261 | EXPORT_SYMBOL_GPL(nfs_fattr_init); | 1294 | EXPORT_SYMBOL_GPL(nfs_fattr_init); |
| 1262 | 1295 | ||
| 1296 | /** | ||
| 1297 | * nfs_fattr_set_barrier | ||
| 1298 | * @fattr: attributes | ||
| 1299 | * | ||
| 1300 | * Used to set a barrier after an attribute was updated. This | ||
| 1301 | * barrier ensures that older attributes from RPC calls that may | ||
| 1302 | * have raced with our update cannot clobber these new values. | ||
| 1303 | * Note that you are still responsible for ensuring that other | ||
| 1304 | * operations which change the attribute on the server do not | ||
| 1305 | * collide. | ||
| 1306 | */ | ||
| 1307 | void nfs_fattr_set_barrier(struct nfs_fattr *fattr) | ||
| 1308 | { | ||
| 1309 | fattr->gencount = nfs_inc_attr_generation_counter(); | ||
| 1310 | } | ||
| 1311 | |||
| 1263 | struct nfs_fattr *nfs_alloc_fattr(void) | 1312 | struct nfs_fattr *nfs_alloc_fattr(void) |
| 1264 | { | 1313 | { |
| 1265 | struct nfs_fattr *fattr; | 1314 | struct nfs_fattr *fattr; |
| @@ -1370,7 +1419,6 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n | |||
| 1370 | 1419 | ||
| 1371 | return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 || | 1420 | return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 || |
| 1372 | nfs_ctime_need_update(inode, fattr) || | 1421 | nfs_ctime_need_update(inode, fattr) || |
| 1373 | nfs_size_need_update(inode, fattr) || | ||
| 1374 | ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0); | 1422 | ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0); |
| 1375 | } | 1423 | } |
| 1376 | 1424 | ||
| @@ -1460,6 +1508,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1460 | int status; | 1508 | int status; |
| 1461 | 1509 | ||
| 1462 | spin_lock(&inode->i_lock); | 1510 | spin_lock(&inode->i_lock); |
| 1511 | nfs_fattr_set_barrier(fattr); | ||
| 1463 | status = nfs_post_op_update_inode_locked(inode, fattr); | 1512 | status = nfs_post_op_update_inode_locked(inode, fattr); |
| 1464 | spin_unlock(&inode->i_lock); | 1513 | spin_unlock(&inode->i_lock); |
| 1465 | 1514 | ||
| @@ -1468,7 +1517,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1468 | EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); | 1517 | EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); |
| 1469 | 1518 | ||
| 1470 | /** | 1519 | /** |
| 1471 | * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache | 1520 | * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache |
| 1472 | * @inode - pointer to inode | 1521 | * @inode - pointer to inode |
| 1473 | * @fattr - updated attributes | 1522 | * @fattr - updated attributes |
| 1474 | * | 1523 | * |
| @@ -1478,11 +1527,10 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); | |||
| 1478 | * | 1527 | * |
| 1479 | * This function is mainly designed to be used by the ->write_done() functions. | 1528 | * This function is mainly designed to be used by the ->write_done() functions. |
| 1480 | */ | 1529 | */ |
| 1481 | int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr) | 1530 | int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr) |
| 1482 | { | 1531 | { |
| 1483 | int status; | 1532 | int status; |
| 1484 | 1533 | ||
| 1485 | spin_lock(&inode->i_lock); | ||
| 1486 | /* Don't do a WCC update if these attributes are already stale */ | 1534 | /* Don't do a WCC update if these attributes are already stale */ |
| 1487 | if ((fattr->valid & NFS_ATTR_FATTR) == 0 || | 1535 | if ((fattr->valid & NFS_ATTR_FATTR) == 0 || |
| 1488 | !nfs_inode_attrs_need_update(inode, fattr)) { | 1536 | !nfs_inode_attrs_need_update(inode, fattr)) { |
| @@ -1514,6 +1562,27 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa | |||
| 1514 | } | 1562 | } |
| 1515 | out_noforce: | 1563 | out_noforce: |
| 1516 | status = nfs_post_op_update_inode_locked(inode, fattr); | 1564 | status = nfs_post_op_update_inode_locked(inode, fattr); |
| 1565 | return status; | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | /** | ||
| 1569 | * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache | ||
| 1570 | * @inode - pointer to inode | ||
| 1571 | * @fattr - updated attributes | ||
| 1572 | * | ||
| 1573 | * After an operation that has changed the inode metadata, mark the | ||
| 1574 | * attribute cache as being invalid, then try to update it. Fake up | ||
| 1575 | * weak cache consistency data, if none exist. | ||
| 1576 | * | ||
| 1577 | * This function is mainly designed to be used by the ->write_done() functions. | ||
| 1578 | */ | ||
| 1579 | int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr) | ||
| 1580 | { | ||
| 1581 | int status; | ||
| 1582 | |||
| 1583 | spin_lock(&inode->i_lock); | ||
| 1584 | nfs_fattr_set_barrier(fattr); | ||
| 1585 | status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr); | ||
| 1517 | spin_unlock(&inode->i_lock); | 1586 | spin_unlock(&inode->i_lock); |
| 1518 | return status; | 1587 | return status; |
| 1519 | } | 1588 | } |
| @@ -1715,6 +1784,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1715 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); | 1784 | nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); |
| 1716 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 1785 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
| 1717 | nfsi->attrtimeo_timestamp = now; | 1786 | nfsi->attrtimeo_timestamp = now; |
| 1787 | /* Set barrier to be more recent than all outstanding updates */ | ||
| 1718 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); | 1788 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); |
| 1719 | } else { | 1789 | } else { |
| 1720 | if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { | 1790 | if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { |
| @@ -1722,6 +1792,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1722 | nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); | 1792 | nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); |
| 1723 | nfsi->attrtimeo_timestamp = now; | 1793 | nfsi->attrtimeo_timestamp = now; |
| 1724 | } | 1794 | } |
| 1795 | /* Set the barrier to be more recent than this fattr */ | ||
| 1796 | if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0) | ||
| 1797 | nfsi->attr_gencount = fattr->gencount; | ||
| 1725 | } | 1798 | } |
| 1726 | invalid &= ~NFS_INO_INVALID_ATTR; | 1799 | invalid &= ~NFS_INO_INVALID_ATTR; |
| 1727 | /* Don't invalidate the data if we were to blame */ | 1800 | /* Don't invalidate the data if we were to blame */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index b802fb3a2d99..9e6475bc5ba2 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -459,6 +459,7 @@ void nfs_mark_request_commit(struct nfs_page *req, | |||
| 459 | struct nfs_commit_info *cinfo, | 459 | struct nfs_commit_info *cinfo, |
| 460 | u32 ds_commit_idx); | 460 | u32 ds_commit_idx); |
| 461 | int nfs_write_need_commit(struct nfs_pgio_header *); | 461 | int nfs_write_need_commit(struct nfs_pgio_header *); |
| 462 | void nfs_writeback_update_inode(struct nfs_pgio_header *hdr); | ||
| 462 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, | 463 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, |
| 463 | int how, struct nfs_commit_info *cinfo); | 464 | int how, struct nfs_commit_info *cinfo); |
| 464 | void nfs_retry_commit(struct list_head *page_list, | 465 | void nfs_retry_commit(struct list_head *page_list, |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 78e557c3ab87..1f11d2533ee4 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -138,7 +138,7 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
| 138 | nfs_fattr_init(fattr); | 138 | nfs_fattr_init(fattr); |
| 139 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 139 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
| 140 | if (status == 0) | 140 | if (status == 0) |
| 141 | nfs_setattr_update_inode(inode, sattr); | 141 | nfs_setattr_update_inode(inode, sattr, fattr); |
| 142 | dprintk("NFS reply setattr: %d\n", status); | 142 | dprintk("NFS reply setattr: %d\n", status); |
| 143 | return status; | 143 | return status; |
| 144 | } | 144 | } |
| @@ -834,7 +834,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) | |||
| 834 | if (nfs3_async_handle_jukebox(task, inode)) | 834 | if (nfs3_async_handle_jukebox(task, inode)) |
| 835 | return -EAGAIN; | 835 | return -EAGAIN; |
| 836 | if (task->tk_status >= 0) | 836 | if (task->tk_status >= 0) |
| 837 | nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr); | 837 | nfs_writeback_update_inode(hdr); |
| 838 | return 0; | 838 | return 0; |
| 839 | } | 839 | } |
| 840 | 840 | ||
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 2a932fdc57cb..53852a4bd88b 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
| @@ -1987,6 +1987,11 @@ int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
| 1987 | if (entry->fattr->valid & NFS_ATTR_FATTR_V3) | 1987 | if (entry->fattr->valid & NFS_ATTR_FATTR_V3) |
| 1988 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); | 1988 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); |
| 1989 | 1989 | ||
| 1990 | if (entry->fattr->fileid != entry->ino) { | ||
| 1991 | entry->fattr->mounted_on_fileid = entry->ino; | ||
| 1992 | entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID; | ||
| 1993 | } | ||
| 1994 | |||
| 1990 | /* In fact, a post_op_fh3: */ | 1995 | /* In fact, a post_op_fh3: */ |
| 1991 | p = xdr_inline_decode(xdr, 4); | 1996 | p = xdr_inline_decode(xdr, 4); |
| 1992 | if (unlikely(p == NULL)) | 1997 | if (unlikely(p == NULL)) |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 8646af9b11d2..86d6214ea022 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
| @@ -621,6 +621,9 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
| 621 | spin_lock(&nn->nfs_client_lock); | 621 | spin_lock(&nn->nfs_client_lock); |
| 622 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { | 622 | list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { |
| 623 | 623 | ||
| 624 | if (pos == new) | ||
| 625 | goto found; | ||
| 626 | |||
| 624 | if (pos->rpc_ops != new->rpc_ops) | 627 | if (pos->rpc_ops != new->rpc_ops) |
| 625 | continue; | 628 | continue; |
| 626 | 629 | ||
| @@ -639,10 +642,6 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
| 639 | prev = pos; | 642 | prev = pos; |
| 640 | 643 | ||
| 641 | status = nfs_wait_client_init_complete(pos); | 644 | status = nfs_wait_client_init_complete(pos); |
| 642 | if (pos->cl_cons_state == NFS_CS_SESSION_INITING) { | ||
| 643 | nfs4_schedule_lease_recovery(pos); | ||
| 644 | status = nfs4_wait_clnt_recover(pos); | ||
| 645 | } | ||
| 646 | spin_lock(&nn->nfs_client_lock); | 645 | spin_lock(&nn->nfs_client_lock); |
| 647 | if (status < 0) | 646 | if (status < 0) |
| 648 | break; | 647 | break; |
| @@ -668,7 +667,7 @@ int nfs41_walk_client_list(struct nfs_client *new, | |||
| 668 | */ | 667 | */ |
| 669 | if (!nfs4_match_client_owner_id(pos, new)) | 668 | if (!nfs4_match_client_owner_id(pos, new)) |
| 670 | continue; | 669 | continue; |
| 671 | 670 | found: | |
| 672 | atomic_inc(&pos->cl_count); | 671 | atomic_inc(&pos->cl_count); |
| 673 | *result = pos; | 672 | *result = pos; |
| 674 | status = 0; | 673 | status = 0; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 88180ac5ea0e..627f37c44456 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -901,6 +901,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
| 901 | if (!cinfo->atomic || cinfo->before != dir->i_version) | 901 | if (!cinfo->atomic || cinfo->before != dir->i_version) |
| 902 | nfs_force_lookup_revalidate(dir); | 902 | nfs_force_lookup_revalidate(dir); |
| 903 | dir->i_version = cinfo->after; | 903 | dir->i_version = cinfo->after; |
| 904 | nfsi->attr_gencount = nfs_inc_attr_generation_counter(); | ||
| 904 | nfs_fscache_invalidate(dir); | 905 | nfs_fscache_invalidate(dir); |
| 905 | spin_unlock(&dir->i_lock); | 906 | spin_unlock(&dir->i_lock); |
| 906 | } | 907 | } |
| @@ -1552,6 +1553,9 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
| 1552 | 1553 | ||
| 1553 | opendata->o_arg.open_flags = 0; | 1554 | opendata->o_arg.open_flags = 0; |
| 1554 | opendata->o_arg.fmode = fmode; | 1555 | opendata->o_arg.fmode = fmode; |
| 1556 | opendata->o_arg.share_access = nfs4_map_atomic_open_share( | ||
| 1557 | NFS_SB(opendata->dentry->d_sb), | ||
| 1558 | fmode, 0); | ||
| 1555 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 1559 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
| 1556 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 1560 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
| 1557 | nfs4_init_opendata_res(opendata); | 1561 | nfs4_init_opendata_res(opendata); |
| @@ -2413,8 +2417,8 @@ static int _nfs4_do_open(struct inode *dir, | |||
| 2413 | opendata->o_res.f_attr, sattr, | 2417 | opendata->o_res.f_attr, sattr, |
| 2414 | state, label, olabel); | 2418 | state, label, olabel); |
| 2415 | if (status == 0) { | 2419 | if (status == 0) { |
| 2416 | nfs_setattr_update_inode(state->inode, sattr); | 2420 | nfs_setattr_update_inode(state->inode, sattr, |
| 2417 | nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); | 2421 | opendata->o_res.f_attr); |
| 2418 | nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); | 2422 | nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); |
| 2419 | } | 2423 | } |
| 2420 | } | 2424 | } |
| @@ -2651,7 +2655,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 2651 | case -NFS4ERR_BAD_STATEID: | 2655 | case -NFS4ERR_BAD_STATEID: |
| 2652 | case -NFS4ERR_EXPIRED: | 2656 | case -NFS4ERR_EXPIRED: |
| 2653 | if (!nfs4_stateid_match(&calldata->arg.stateid, | 2657 | if (!nfs4_stateid_match(&calldata->arg.stateid, |
| 2654 | &state->stateid)) { | 2658 | &state->open_stateid)) { |
| 2655 | rpc_restart_call_prepare(task); | 2659 | rpc_restart_call_prepare(task); |
| 2656 | goto out_release; | 2660 | goto out_release; |
| 2657 | } | 2661 | } |
| @@ -2687,7 +2691,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 2687 | is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); | 2691 | is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); |
| 2688 | is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); | 2692 | is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); |
| 2689 | is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); | 2693 | is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); |
| 2690 | nfs4_stateid_copy(&calldata->arg.stateid, &state->stateid); | 2694 | nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid); |
| 2691 | /* Calculate the change in open mode */ | 2695 | /* Calculate the change in open mode */ |
| 2692 | calldata->arg.fmode = 0; | 2696 | calldata->arg.fmode = 0; |
| 2693 | if (state->n_rdwr == 0) { | 2697 | if (state->n_rdwr == 0) { |
| @@ -3288,7 +3292,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
| 3288 | 3292 | ||
| 3289 | status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label); | 3293 | status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label); |
| 3290 | if (status == 0) { | 3294 | if (status == 0) { |
| 3291 | nfs_setattr_update_inode(inode, sattr); | 3295 | nfs_setattr_update_inode(inode, sattr, fattr); |
| 3292 | nfs_setsecurity(inode, fattr, label); | 3296 | nfs_setsecurity(inode, fattr, label); |
| 3293 | } | 3297 | } |
| 3294 | nfs4_label_free(label); | 3298 | nfs4_label_free(label); |
| @@ -4234,7 +4238,7 @@ static int nfs4_write_done_cb(struct rpc_task *task, | |||
| 4234 | } | 4238 | } |
| 4235 | if (task->tk_status >= 0) { | 4239 | if (task->tk_status >= 0) { |
| 4236 | renew_lease(NFS_SERVER(inode), hdr->timestamp); | 4240 | renew_lease(NFS_SERVER(inode), hdr->timestamp); |
| 4237 | nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr); | 4241 | nfs_writeback_update_inode(hdr); |
| 4238 | } | 4242 | } |
| 4239 | return 0; | 4243 | return 0; |
| 4240 | } | 4244 | } |
| @@ -6893,9 +6897,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, | |||
| 6893 | 6897 | ||
| 6894 | if (status == 0) { | 6898 | if (status == 0) { |
| 6895 | clp->cl_clientid = res.clientid; | 6899 | clp->cl_clientid = res.clientid; |
| 6896 | clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R); | 6900 | clp->cl_exchange_flags = res.flags; |
| 6897 | if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) | 6901 | /* Client ID is not confirmed */ |
| 6902 | if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) { | ||
| 6903 | clear_bit(NFS4_SESSION_ESTABLISHED, | ||
| 6904 | &clp->cl_session->session_state); | ||
| 6898 | clp->cl_seqid = res.seqid; | 6905 | clp->cl_seqid = res.seqid; |
| 6906 | } | ||
| 6899 | 6907 | ||
| 6900 | kfree(clp->cl_serverowner); | 6908 | kfree(clp->cl_serverowner); |
| 6901 | clp->cl_serverowner = res.server_owner; | 6909 | clp->cl_serverowner = res.server_owner; |
| @@ -7227,6 +7235,9 @@ static void nfs4_update_session(struct nfs4_session *session, | |||
| 7227 | struct nfs41_create_session_res *res) | 7235 | struct nfs41_create_session_res *res) |
| 7228 | { | 7236 | { |
| 7229 | nfs4_copy_sessionid(&session->sess_id, &res->sessionid); | 7237 | nfs4_copy_sessionid(&session->sess_id, &res->sessionid); |
| 7238 | /* Mark client id and session as being confirmed */ | ||
| 7239 | session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; | ||
| 7240 | set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state); | ||
| 7230 | session->flags = res->flags; | 7241 | session->flags = res->flags; |
| 7231 | memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs)); | 7242 | memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs)); |
| 7232 | if (res->flags & SESSION4_BACK_CHAN) | 7243 | if (res->flags & SESSION4_BACK_CHAN) |
| @@ -7322,8 +7333,8 @@ int nfs4_proc_destroy_session(struct nfs4_session *session, | |||
| 7322 | dprintk("--> nfs4_proc_destroy_session\n"); | 7333 | dprintk("--> nfs4_proc_destroy_session\n"); |
| 7323 | 7334 | ||
| 7324 | /* session is still being setup */ | 7335 | /* session is still being setup */ |
| 7325 | if (session->clp->cl_cons_state != NFS_CS_READY) | 7336 | if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state)) |
| 7326 | return status; | 7337 | return 0; |
| 7327 | 7338 | ||
| 7328 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 7339 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
| 7329 | trace_nfs4_destroy_session(session->clp, status); | 7340 | trace_nfs4_destroy_session(session->clp, status); |
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index fc46c7455898..e3ea2c5324d6 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
| @@ -70,6 +70,7 @@ struct nfs4_session { | |||
| 70 | 70 | ||
| 71 | enum nfs4_session_state { | 71 | enum nfs4_session_state { |
| 72 | NFS4_SESSION_INITING, | 72 | NFS4_SESSION_INITING, |
| 73 | NFS4_SESSION_ESTABLISHED, | ||
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, | 76 | extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 5ad908e9ce9c..f95e3b58bbc3 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -346,9 +346,23 @@ int nfs41_discover_server_trunking(struct nfs_client *clp, | |||
| 346 | status = nfs4_proc_exchange_id(clp, cred); | 346 | status = nfs4_proc_exchange_id(clp, cred); |
| 347 | if (status != NFS4_OK) | 347 | if (status != NFS4_OK) |
| 348 | return status; | 348 | return status; |
| 349 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
| 350 | 349 | ||
| 351 | return nfs41_walk_client_list(clp, result, cred); | 350 | status = nfs41_walk_client_list(clp, result, cred); |
| 351 | if (status < 0) | ||
| 352 | return status; | ||
| 353 | if (clp != *result) | ||
| 354 | return 0; | ||
| 355 | |||
| 356 | /* Purge state if the client id was established in a prior instance */ | ||
| 357 | if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) | ||
| 358 | set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); | ||
| 359 | else | ||
| 360 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
| 361 | nfs4_schedule_state_manager(clp); | ||
| 362 | status = nfs_wait_client_init_complete(clp); | ||
| 363 | if (status < 0) | ||
| 364 | nfs_put_client(clp); | ||
| 365 | return status; | ||
| 352 | } | 366 | } |
| 353 | 367 | ||
| 354 | #endif /* CONFIG_NFS_V4_1 */ | 368 | #endif /* CONFIG_NFS_V4_1 */ |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index b09cc23d6f43..c63189acd052 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
| @@ -139,7 +139,7 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
| 139 | nfs_fattr_init(fattr); | 139 | nfs_fattr_init(fattr); |
| 140 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 140 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
| 141 | if (status == 0) | 141 | if (status == 0) |
| 142 | nfs_setattr_update_inode(inode, sattr); | 142 | nfs_setattr_update_inode(inode, sattr, fattr); |
| 143 | dprintk("NFS reply setattr: %d\n", status); | 143 | dprintk("NFS reply setattr: %d\n", status); |
| 144 | return status; | 144 | return status; |
| 145 | } | 145 | } |
| @@ -609,10 +609,8 @@ static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task, | |||
| 609 | 609 | ||
| 610 | static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) | 610 | static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 611 | { | 611 | { |
| 612 | struct inode *inode = hdr->inode; | ||
| 613 | |||
| 614 | if (task->tk_status >= 0) | 612 | if (task->tk_status >= 0) |
| 615 | nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr); | 613 | nfs_writeback_update_inode(hdr); |
| 616 | return 0; | 614 | return 0; |
| 617 | } | 615 | } |
| 618 | 616 | ||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 595d81e354d1..849ed784d6ac 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -1377,6 +1377,36 @@ static int nfs_should_remove_suid(const struct inode *inode) | |||
| 1377 | return 0; | 1377 | return 0; |
| 1378 | } | 1378 | } |
| 1379 | 1379 | ||
| 1380 | static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr, | ||
| 1381 | struct nfs_fattr *fattr) | ||
| 1382 | { | ||
| 1383 | struct nfs_pgio_args *argp = &hdr->args; | ||
| 1384 | struct nfs_pgio_res *resp = &hdr->res; | ||
| 1385 | |||
| 1386 | if (!(fattr->valid & NFS_ATTR_FATTR_SIZE)) | ||
| 1387 | return; | ||
| 1388 | if (argp->offset + resp->count != fattr->size) | ||
| 1389 | return; | ||
| 1390 | if (nfs_size_to_loff_t(fattr->size) < i_size_read(hdr->inode)) | ||
| 1391 | return; | ||
| 1392 | /* Set attribute barrier */ | ||
| 1393 | nfs_fattr_set_barrier(fattr); | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | void nfs_writeback_update_inode(struct nfs_pgio_header *hdr) | ||
| 1397 | { | ||
| 1398 | struct nfs_fattr *fattr = hdr->res.fattr; | ||
| 1399 | struct inode *inode = hdr->inode; | ||
| 1400 | |||
| 1401 | if (fattr == NULL) | ||
| 1402 | return; | ||
| 1403 | spin_lock(&inode->i_lock); | ||
| 1404 | nfs_writeback_check_extend(hdr, fattr); | ||
| 1405 | nfs_post_op_update_inode_force_wcc_locked(inode, fattr); | ||
| 1406 | spin_unlock(&inode->i_lock); | ||
| 1407 | } | ||
| 1408 | EXPORT_SYMBOL_GPL(nfs_writeback_update_inode); | ||
| 1409 | |||
| 1380 | /* | 1410 | /* |
| 1381 | * This function is called when the WRITE call is complete. | 1411 | * This function is called when the WRITE call is complete. |
| 1382 | */ | 1412 | */ |
