diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-15 17:15:16 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-15 17:15:16 -0500 |
| commit | 1afcb6ed0d34c5794a51fe325076f006c8babaf4 (patch) | |
| tree | a39a9b36d96dca051c0506cfde57269a1cd1a31c | |
| parent | 56c381f93d57b88a3e667a2f55137947315c17e2 (diff) | |
| parent | b3ecba096729f521312d1863ad22530695527aed (diff) | |
Merge tag 'nfs-for-3.18-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include:
- stable patches to fix NFSv4.x delegation reclaim error paths
- fix a bug whereby we were advertising NFSv4.1 but using NFSv4.2
features
- fix a use-after-free problem with pNFS block layouts
- fix a memory leak in the pNFS files O_DIRECT code
- replace an intrusive and Oops-prone performance fix in the NFSv4
atomic open code with a safer one-line version and revert the two
original patches"
* tag 'nfs-for-3.18-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
sunrpc: fix sleeping under rcu_read_lock in gss_stringify_acceptor
NFS: Don't try to reclaim delegation open state if recovery failed
NFSv4: Ensure that we call FREE_STATEID when NFSv4.x stateids are revoked
NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return
NFSv4.1: nfs41_clear_delegation_stateid shouldn't trust NFS_DELEGATED_STATE
NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired
NFS: SEEK is an NFS v4.2 feature
nfs: Fix use of uninitialized variable in nfs_getattr()
nfs: Remove bogus assignment
nfs: remove spurious WARN_ON_ONCE in write path
pnfs/blocklayout: serialize GETDEVICEINFO calls
nfs: fix pnfs direct write memory leak
Revert "NFS: nfs4_do_open should add negative results to the dcache."
Revert "NFS: remove BUG possibility in nfs4_open_and_get_state"
NFSv4: Ensure nfs_atomic_open set the dentry verifier on ENOENT
| -rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 2 | ||||
| -rw-r--r-- | fs/nfs/blocklayout/rpc_pipefs.c | 14 | ||||
| -rw-r--r-- | fs/nfs/delegation.c | 25 | ||||
| -rw-r--r-- | fs/nfs/delegation.h | 1 | ||||
| -rw-r--r-- | fs/nfs/dir.c | 1 | ||||
| -rw-r--r-- | fs/nfs/direct.c | 1 | ||||
| -rw-r--r-- | fs/nfs/filelayout/filelayout.c | 3 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 2 | ||||
| -rw-r--r-- | fs/nfs/netns.h | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 95 | ||||
| -rw-r--r-- | fs/nfs/write.c | 2 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 11 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 35 |
13 files changed, 124 insertions, 69 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 5228f201d3d5..4f46f7a05289 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
| @@ -378,7 +378,7 @@ bl_write_pagelist(struct nfs_pgio_header *header, int sync) | |||
| 378 | loff_t offset = header->args.offset; | 378 | loff_t offset = header->args.offset; |
| 379 | size_t count = header->args.count; | 379 | size_t count = header->args.count; |
| 380 | struct page **pages = header->args.pages; | 380 | struct page **pages = header->args.pages; |
| 381 | int pg_index = pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; | 381 | int pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; |
| 382 | unsigned int pg_len; | 382 | unsigned int pg_len; |
| 383 | struct blk_plug plug; | 383 | struct blk_plug plug; |
| 384 | int i; | 384 | int i; |
diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c index e966c023b1b7..acbf9ca4018c 100644 --- a/fs/nfs/blocklayout/rpc_pipefs.c +++ b/fs/nfs/blocklayout/rpc_pipefs.c | |||
| @@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
| 65 | 65 | ||
| 66 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); | 66 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); |
| 67 | 67 | ||
| 68 | mutex_lock(&nn->bl_mutex); | ||
| 68 | bl_pipe_msg.bl_wq = &nn->bl_wq; | 69 | bl_pipe_msg.bl_wq = &nn->bl_wq; |
| 69 | 70 | ||
| 70 | b->simple.len += 4; /* single volume */ | 71 | b->simple.len += 4; /* single volume */ |
| 71 | if (b->simple.len > PAGE_SIZE) | 72 | if (b->simple.len > PAGE_SIZE) |
| 72 | return -EIO; | 73 | goto out_unlock; |
| 73 | 74 | ||
| 74 | memset(msg, 0, sizeof(*msg)); | 75 | memset(msg, 0, sizeof(*msg)); |
| 75 | msg->len = sizeof(*bl_msg) + b->simple.len; | 76 | msg->len = sizeof(*bl_msg) + b->simple.len; |
| 76 | msg->data = kzalloc(msg->len, gfp_mask); | 77 | msg->data = kzalloc(msg->len, gfp_mask); |
| 77 | if (!msg->data) | 78 | if (!msg->data) |
| 78 | goto out; | 79 | goto out_free_data; |
| 79 | 80 | ||
| 80 | bl_msg = msg->data; | 81 | bl_msg = msg->data; |
| 81 | bl_msg->type = BL_DEVICE_MOUNT, | 82 | bl_msg->type = BL_DEVICE_MOUNT, |
| @@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
| 87 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); | 88 | rc = rpc_queue_upcall(nn->bl_device_pipe, msg); |
| 88 | if (rc < 0) { | 89 | if (rc < 0) { |
| 89 | remove_wait_queue(&nn->bl_wq, &wq); | 90 | remove_wait_queue(&nn->bl_wq, &wq); |
| 90 | goto out; | 91 | goto out_free_data; |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | set_current_state(TASK_UNINTERRUPTIBLE); | 94 | set_current_state(TASK_UNINTERRUPTIBLE); |
| @@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, | |||
| 97 | if (reply->status != BL_DEVICE_REQUEST_PROC) { | 98 | if (reply->status != BL_DEVICE_REQUEST_PROC) { |
| 98 | printk(KERN_WARNING "%s failed to decode device: %d\n", | 99 | printk(KERN_WARNING "%s failed to decode device: %d\n", |
| 99 | __func__, reply->status); | 100 | __func__, reply->status); |
| 100 | goto out; | 101 | goto out_free_data; |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | dev = MKDEV(reply->major, reply->minor); | 104 | dev = MKDEV(reply->major, reply->minor); |
| 104 | out: | 105 | out_free_data: |
| 105 | kfree(msg->data); | 106 | kfree(msg->data); |
| 107 | out_unlock: | ||
| 108 | mutex_unlock(&nn->bl_mutex); | ||
| 106 | return dev; | 109 | return dev; |
| 107 | } | 110 | } |
| 108 | 111 | ||
| @@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net) | |||
| 232 | struct nfs_net *nn = net_generic(net, nfs_net_id); | 235 | struct nfs_net *nn = net_generic(net, nfs_net_id); |
| 233 | struct dentry *dentry; | 236 | struct dentry *dentry; |
| 234 | 237 | ||
| 238 | mutex_init(&nn->bl_mutex); | ||
| 235 | init_waitqueue_head(&nn->bl_wq); | 239 | init_waitqueue_head(&nn->bl_wq); |
| 236 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); | 240 | nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); |
| 237 | if (IS_ERR(nn->bl_device_pipe)) | 241 | if (IS_ERR(nn->bl_device_pipe)) |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5853f53db732..7f3f60641344 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -125,6 +125,8 @@ again: | |||
| 125 | continue; | 125 | continue; |
| 126 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | 126 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) |
| 127 | continue; | 127 | continue; |
| 128 | if (!nfs4_valid_open_stateid(state)) | ||
| 129 | continue; | ||
| 128 | if (!nfs4_stateid_match(&state->stateid, stateid)) | 130 | if (!nfs4_stateid_match(&state->stateid, stateid)) |
| 129 | continue; | 131 | continue; |
| 130 | get_nfs_open_context(ctx); | 132 | get_nfs_open_context(ctx); |
| @@ -193,7 +195,11 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |||
| 193 | { | 195 | { |
| 194 | int res = 0; | 196 | int res = 0; |
| 195 | 197 | ||
| 196 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync); | 198 | if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) |
| 199 | res = nfs4_proc_delegreturn(inode, | ||
| 200 | delegation->cred, | ||
| 201 | &delegation->stateid, | ||
| 202 | issync); | ||
| 197 | nfs_free_delegation(delegation); | 203 | nfs_free_delegation(delegation); |
| 198 | return res; | 204 | return res; |
| 199 | } | 205 | } |
| @@ -380,11 +386,13 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation | |||
| 380 | { | 386 | { |
| 381 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 387 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 382 | struct nfs_inode *nfsi = NFS_I(inode); | 388 | struct nfs_inode *nfsi = NFS_I(inode); |
| 383 | int err; | 389 | int err = 0; |
| 384 | 390 | ||
| 385 | if (delegation == NULL) | 391 | if (delegation == NULL) |
| 386 | return 0; | 392 | return 0; |
| 387 | do { | 393 | do { |
| 394 | if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) | ||
| 395 | break; | ||
| 388 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); | 396 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); |
| 389 | if (!issync || err != -EAGAIN) | 397 | if (!issync || err != -EAGAIN) |
| 390 | break; | 398 | break; |
| @@ -605,10 +613,23 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl | |||
| 605 | rcu_read_unlock(); | 613 | rcu_read_unlock(); |
| 606 | } | 614 | } |
| 607 | 615 | ||
| 616 | static void nfs_revoke_delegation(struct inode *inode) | ||
| 617 | { | ||
| 618 | struct nfs_delegation *delegation; | ||
| 619 | rcu_read_lock(); | ||
| 620 | delegation = rcu_dereference(NFS_I(inode)->delegation); | ||
| 621 | if (delegation != NULL) { | ||
| 622 | set_bit(NFS_DELEGATION_REVOKED, &delegation->flags); | ||
| 623 | nfs_mark_return_delegation(NFS_SERVER(inode), delegation); | ||
| 624 | } | ||
| 625 | rcu_read_unlock(); | ||
| 626 | } | ||
| 627 | |||
| 608 | void nfs_remove_bad_delegation(struct inode *inode) | 628 | void nfs_remove_bad_delegation(struct inode *inode) |
| 609 | { | 629 | { |
| 610 | struct nfs_delegation *delegation; | 630 | struct nfs_delegation *delegation; |
| 611 | 631 | ||
| 632 | nfs_revoke_delegation(inode); | ||
| 612 | delegation = nfs_inode_detach_delegation(inode); | 633 | delegation = nfs_inode_detach_delegation(inode); |
| 613 | if (delegation) { | 634 | if (delegation) { |
| 614 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); | 635 | nfs_inode_find_state_and_recover(inode, &delegation->stateid); |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 5c1cce39297f..e3c20a3ccc93 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
| @@ -31,6 +31,7 @@ enum { | |||
| 31 | NFS_DELEGATION_RETURN_IF_CLOSED, | 31 | NFS_DELEGATION_RETURN_IF_CLOSED, |
| 32 | NFS_DELEGATION_REFERENCED, | 32 | NFS_DELEGATION_REFERENCED, |
| 33 | NFS_DELEGATION_RETURNING, | 33 | NFS_DELEGATION_RETURNING, |
| 34 | NFS_DELEGATION_REVOKED, | ||
| 34 | }; | 35 | }; |
| 35 | 36 | ||
| 36 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 37 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 06e8cfcbb670..6e62155abf26 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -1527,6 +1527,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, | |||
| 1527 | case -ENOENT: | 1527 | case -ENOENT: |
| 1528 | d_drop(dentry); | 1528 | d_drop(dentry); |
| 1529 | d_add(dentry, NULL); | 1529 | d_add(dentry, NULL); |
| 1530 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | ||
| 1530 | break; | 1531 | |
