diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-28 16:13:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-28 16:13:07 -0400 |
commit | 9cab1ba421fbc4c4503ccf4ff61e000c771e8942 (patch) | |
tree | afd2124cfee46383d017676f9652ecd6b4cb86e9 /fs | |
parent | cc03638df20acbec5d0d0d9e07234aadde9e698d (diff) | |
parent | 26c4c170731f00008f4317a2888a0a07ac99d90d (diff) |
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
nfs: don't lose MS_SYNCHRONOUS on remount of noac mount
NFS: Return meaningful status from decode_secinfo()
NFSv4: Ensure we request the ordinary fileid when doing readdirplus
NFSv4: Ensure that clientid and session establishment can time out
SUNRPC: Allow RPC calls to return ETIMEDOUT instead of EIO
NFSv4.1: Don't loop forever in nfs4_proc_create_session
NFSv4: Handle NFS4ERR_WRONGSEC outside of nfs4_handle_exception()
NFSv4.1: Don't update sequence number if rpc_task is not sent
NFSv4.1: Ensure state manager thread dies on last umount
SUNRPC: Fix the SUNRPC Kerberos V RPCSEC_GSS module dependencies
NFS: Use correct variable for page bounds checking
NFS: don't negotiate when user specifies sec flavor
NFS: Attempt mount with default sec flavor first
NFS: flav_array honors NFS_MAX_SECFLAVORS
NFS: Fix infinite loop in gss_create_upcall()
Don't mark_inode_dirty_sync() while holding lock
NFS: Get rid of pointless test in nfs_commit_done
NFS: Remove unused argument from nfs_find_best_sec()
NFS: Eliminate duplicate call to nfs_mark_request_dirty
NFS: Remove dead code from nfs_fs_mount()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/namespace.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 118 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 51 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 53 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 8 | ||||
-rw-r--r-- | fs/nfs/super.c | 13 | ||||
-rw-r--r-- | fs/nfs/write.c | 4 |
8 files changed, 142 insertions, 110 deletions
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 89fc160fd5b0..1f063bacd285 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -119,7 +119,7 @@ Elong: | |||
119 | } | 119 | } |
120 | 120 | ||
121 | #ifdef CONFIG_NFS_V4 | 121 | #ifdef CONFIG_NFS_V4 |
122 | static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode) | 122 | static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) |
123 | { | 123 | { |
124 | struct gss_api_mech *mech; | 124 | struct gss_api_mech *mech; |
125 | struct xdr_netobj oid; | 125 | struct xdr_netobj oid; |
@@ -166,7 +166,7 @@ static int nfs_negotiate_security(const struct dentry *parent, | |||
166 | } | 166 | } |
167 | flavors = page_address(page); | 167 | flavors = page_address(page); |
168 | ret = secinfo(parent->d_inode, &dentry->d_name, flavors); | 168 | ret = secinfo(parent->d_inode, &dentry->d_name, flavors); |
169 | *flavor = nfs_find_best_sec(flavors, dentry->d_inode); | 169 | *flavor = nfs_find_best_sec(flavors); |
170 | put_page(page); | 170 | put_page(page); |
171 | } | 171 | } |
172 | 172 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index e1c261ddd65d..c4a69833dd0d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -47,6 +47,7 @@ enum nfs4_client_state { | |||
47 | NFS4CLNT_LAYOUTRECALL, | 47 | NFS4CLNT_LAYOUTRECALL, |
48 | NFS4CLNT_SESSION_RESET, | 48 | NFS4CLNT_SESSION_RESET, |
49 | NFS4CLNT_RECALL_SLOT, | 49 | NFS4CLNT_RECALL_SLOT, |
50 | NFS4CLNT_LEASE_CONFIRM, | ||
50 | }; | 51 | }; |
51 | 52 | ||
52 | enum nfs4_session_state { | 53 | enum nfs4_session_state { |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 9bf41eab3e46..69c0f3c5ee7a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/nfs4.h> | 46 | #include <linux/nfs4.h> |
47 | #include <linux/nfs_fs.h> | 47 | #include <linux/nfs_fs.h> |
48 | #include <linux/nfs_page.h> | 48 | #include <linux/nfs_page.h> |
49 | #include <linux/nfs_mount.h> | ||
49 | #include <linux/namei.h> | 50 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 51 | #include <linux/mount.h> |
51 | #include <linux/module.h> | 52 | #include <linux/module.h> |
@@ -443,8 +444,8 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res * | |||
443 | if (res->sr_status == 1) | 444 | if (res->sr_status == 1) |
444 | res->sr_status = NFS_OK; | 445 | res->sr_status = NFS_OK; |
445 | 446 | ||
446 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | 447 | /* don't increment the sequence number if the task wasn't sent */ |
447 | if (!res->sr_slot) | 448 | if (!RPC_WAS_SENT(task)) |
448 | goto out; | 449 | goto out; |
449 | 450 | ||
450 | /* Check the SEQUENCE operation status */ | 451 | /* Check the SEQUENCE operation status */ |
@@ -2185,9 +2186,14 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2185 | struct nfs4_exception exception = { }; | 2186 | struct nfs4_exception exception = { }; |
2186 | int err; | 2187 | int err; |
2187 | do { | 2188 | do { |
2188 | err = nfs4_handle_exception(server, | 2189 | err = _nfs4_lookup_root(server, fhandle, info); |
2189 | _nfs4_lookup_root(server, fhandle, info), | 2190 | switch (err) { |
2190 | &exception); | 2191 | case 0: |
2192 | case -NFS4ERR_WRONGSEC: | ||
2193 | break; | ||
2194 | default: | ||
2195 | err = nfs4_handle_exception(server, err, &exception); | ||
2196 | } | ||
2191 | } while (exception.retry); | 2197 | } while (exception.retry); |
2192 | return err; | 2198 | return err; |
2193 | } | 2199 | } |
@@ -2208,25 +2214,47 @@ out: | |||
2208 | return ret; | 2214 | return ret; |
2209 | } | 2215 | } |
2210 | 2216 | ||
2211 | /* | 2217 | static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, |
2212 | * get the file handle for the "/" directory on the server | ||
2213 | */ | ||
2214 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | ||
2215 | struct nfs_fsinfo *info) | 2218 | struct nfs_fsinfo *info) |
2216 | { | 2219 | { |
2217 | int i, len, status = 0; | 2220 | int i, len, status = 0; |
2218 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2]; | 2221 | rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS]; |
2219 | 2222 | ||
2220 | flav_array[0] = RPC_AUTH_UNIX; | 2223 | len = gss_mech_list_pseudoflavors(&flav_array[0]); |
2221 | len = gss_mech_list_pseudoflavors(&flav_array[1]); | 2224 | flav_array[len] = RPC_AUTH_NULL; |
2222 | flav_array[1+len] = RPC_AUTH_NULL; | 2225 | len += 1; |
2223 | len += 2; | ||
2224 | 2226 | ||
2225 | for (i = 0; i < len; i++) { | 2227 | for (i = 0; i < len; i++) { |
2226 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); | 2228 | status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); |
2227 | if (status != -EPERM) | 2229 | if (status == -NFS4ERR_WRONGSEC || status == -EACCES) |
2228 | break; | 2230 | continue; |
2231 | break; | ||
2229 | } | 2232 | } |
2233 | /* | ||
2234 | * -EACCESS could mean that the user doesn't have correct permissions | ||
2235 | * to access the mount. It could also mean that we tried to mount | ||
2236 | * with a gss auth flavor, but rpc.gssd isn't running. Either way, | ||
2237 | * existing mount programs don't handle -EACCES very well so it should | ||
2238 | * be mapped to -EPERM instead. | ||
2239 | */ | ||
2240 | if (status == -EACCES) | ||
2241 | status = -EPERM; | ||
2242 | return status; | ||
2243 | } | ||
2244 | |||
2245 | /* | ||
2246 | * get the file handle for the "/" directory on the server | ||
2247 | */ | ||
2248 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | ||
2249 | struct nfs_fsinfo *info) | ||
2250 | { | ||
2251 | int status = nfs4_lookup_root(server, fhandle, info); | ||
2252 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) | ||
2253 | /* | ||
2254 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM | ||
2255 | * by nfs4_map_errors() as this function exits. | ||
2256 | */ | ||
2257 | status = nfs4_find_root_sec(server, fhandle, info); | ||
2230 | if (status == 0) | 2258 | if (status == 0) |
2231 | status = nfs4_server_capabilities(server, fhandle); | 2259 | status = nfs4_server_capabilities(server, fhandle); |
2232 | if (status == 0) | 2260 | if (status == 0) |
@@ -3723,21 +3751,20 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3723 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", | 3751 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
3724 | clp->cl_ipaddr, port >> 8, port & 255); | 3752 | clp->cl_ipaddr, port >> 8, port & 255); |
3725 | 3753 | ||
3726 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3754 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
3727 | if (status != -NFS4ERR_CLID_INUSE) | 3755 | if (status != -NFS4ERR_CLID_INUSE) |
3728 | break; | 3756 | break; |
3729 | if (signalled()) | 3757 | if (loop != 0) { |
3758 | ++clp->cl_id_uniquifier; | ||
3730 | break; | 3759 | break; |
3731 | if (loop++ & 1) | 3760 | } |
3732 | ssleep(clp->cl_lease_time / HZ + 1); | 3761 | ++loop; |
3733 | else | 3762 | ssleep(clp->cl_lease_time / HZ + 1); |
3734 | if (++clp->cl_id_uniquifier == 0) | ||
3735 | break; | ||
3736 | } | 3763 | } |
3737 | return status; | 3764 | return status; |
3738 | } | 3765 | } |
3739 | 3766 | ||
3740 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | 3767 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
3741 | struct nfs4_setclientid_res *arg, | 3768 | struct nfs4_setclientid_res *arg, |
3742 | struct rpc_cred *cred) | 3769 | struct rpc_cred *cred) |
3743 | { | 3770 | { |
@@ -3752,7 +3779,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
3752 | int status; | 3779 | int status; |
3753 | 3780 | ||
3754 | now = jiffies; | 3781 | now = jiffies; |
3755 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3782 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
3756 | if (status == 0) { | 3783 | if (status == 0) { |
3757 | spin_lock(&clp->cl_lock); | 3784 | spin_lock(&clp->cl_lock); |
3758 | clp->cl_lease_time = fsinfo.lease_time * HZ; | 3785 | clp->cl_lease_time = fsinfo.lease_time * HZ; |
@@ -3762,26 +3789,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, | |||
3762 | return status; | 3789 | return status; |
3763 | } | 3790 | } |
3764 | 3791 | ||
3765 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, | ||
3766 | struct nfs4_setclientid_res *arg, | ||
3767 | struct rpc_cred *cred) | ||
3768 | { | ||
3769 | long timeout = 0; | ||
3770 | int err; | ||
3771 | do { | ||
3772 | err = _nfs4_proc_setclientid_confirm(clp, arg, cred); | ||
3773 | switch (err) { | ||
3774 | case 0: | ||
3775 | return err; | ||
3776 | case -NFS4ERR_RESOURCE: | ||
3777 | /* The IBM lawyers misread another document! */ | ||
3778 | case -NFS4ERR_DELAY: | ||
3779 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | ||
3780 | } | ||
3781 | } while (err == 0); | ||
3782 | return err; | ||
3783 | } | ||
3784 | |||
3785 | struct nfs4_delegreturndata { | 3792 | struct nfs4_delegreturndata { |
3786 | struct nfs4_delegreturnargs args; | 3793 | struct nfs4_delegreturnargs args; |
3787 | struct nfs4_delegreturnres res; | 3794 | struct nfs4_delegreturnres res; |
@@ -4786,7 +4793,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4786 | init_utsname()->domainname, | 4793 | init_utsname()->domainname, |
4787 | clp->cl_rpcclient->cl_auth->au_flavor); | 4794 | clp->cl_rpcclient->cl_auth->au_flavor); |
4788 | 4795 | ||
4789 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 4796 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
4790 | if (!status) | 4797 | if (!status) |
4791 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); | 4798 | status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); |
4792 | dprintk("<-- %s status= %d\n", __func__, status); | 4799 | dprintk("<-- %s status= %d\n", __func__, status); |
@@ -4869,7 +4876,8 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4869 | .rpc_client = clp->cl_rpcclient, | 4876 | .rpc_client = clp->cl_rpcclient, |
4870 | .rpc_message = &msg, | 4877 | .rpc_message = &msg, |
4871 | .callback_ops = &nfs4_get_lease_time_ops, | 4878 | .callback_ops = &nfs4_get_lease_time_ops, |
4872 | .callback_data = &data | 4879 | .callback_data = &data, |
4880 | .flags = RPC_TASK_TIMEOUT, | ||
4873 | }; | 4881 | }; |
4874 | int status; | 4882 | int status; |
4875 | 4883 | ||
@@ -5171,7 +5179,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp) | |||
5171 | nfs4_init_channel_attrs(&args); | 5179 | nfs4_init_channel_attrs(&args); |
5172 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | 5180 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); |
5173 | 5181 | ||
5174 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | 5182 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
5175 | 5183 | ||
5176 | if (!status) | 5184 | if (!status) |
5177 | /* Verify the session's negotiated channel_attrs values */ | 5185 | /* Verify the session's negotiated channel_attrs values */ |
@@ -5194,20 +5202,10 @@ int nfs4_proc_create_session(struct nfs_client *clp) | |||
5194 | int status; | 5202 | int status; |
5195 | unsigned *ptr; | 5203 | unsigned *ptr; |
5196 | struct nfs4_session *session = clp->cl_session; | 5204 | struct nfs4_session *session = clp->cl_session; |
5197 | long timeout = 0; | ||
5198 | int err; | ||
5199 | 5205 | ||
5200 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | 5206 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); |
5201 | 5207 | ||
5202 | do { | 5208 | status = _nfs4_proc_create_session(clp); |
5203 | status = _nfs4_proc_create_session(clp); | ||
5204 | if (status == -NFS4ERR_DELAY) { | ||
5205 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | ||
5206 | if (err) | ||
5207 | status = err; | ||
5208 | } | ||
5209 | } while (status == -NFS4ERR_DELAY); | ||
5210 | |||
5211 | if (status) | 5209 | if (status) |
5212 | goto out; | 5210 | goto out; |
5213 | 5211 | ||
@@ -5248,7 +5246,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
5248 | msg.rpc_argp = session; | 5246 | msg.rpc_argp = session; |
5249 | msg.rpc_resp = NULL; | 5247 | msg.rpc_resp = NULL; |
5250 | msg.rpc_cred = NULL; | 5248 | msg.rpc_cred = NULL; |
5251 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | 5249 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
5252 | 5250 | ||
5253 | if (status) | 5251 | if (status) |
5254 | printk(KERN_WARNING | 5252 | printk(KERN_WARNING |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a6804f704d9d..036f5adc9e1f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list); | |||
64 | 64 | ||
65 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 65 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
66 | { | 66 | { |
67 | struct nfs4_setclientid_res clid; | 67 | struct nfs4_setclientid_res clid = { |
68 | .clientid = clp->cl_clientid, | ||
69 | .confirm = clp->cl_confirm, | ||
70 | }; | ||
68 | unsigned short port; | 71 | unsigned short port; |
69 | int status; | 72 | int status; |
70 | 73 | ||
74 | if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) | ||
75 | goto do_confirm; | ||
71 | port = nfs_callback_tcpport; | 76 | port = nfs_callback_tcpport; |
72 | if (clp->cl_addr.ss_family == AF_INET6) | 77 | if (clp->cl_addr.ss_family == AF_INET6) |
73 | port = nfs_callback_tcpport6; | 78 | port = nfs_callback_tcpport6; |
@@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
75 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); | 80 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); |
76 | if (status != 0) | 81 | if (status != 0) |
77 | goto out; | 82 | goto out; |
83 | clp->cl_clientid = clid.clientid; | ||
84 | clp->cl_confirm = clid.confirm; | ||
85 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
86 | do_confirm: | ||
78 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); | 87 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); |
79 | if (status != 0) | 88 | if (status != 0) |
80 | goto out; | 89 | goto out; |
81 | clp->cl_clientid = clid.clientid; | 90 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
82 | nfs4_schedule_state_renewal(clp); | 91 | nfs4_schedule_state_renewal(clp); |
83 | out: | 92 | out: |
84 | return status; | 93 | return status; |
@@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
230 | { | 239 | { |
231 | int status; | 240 | int status; |
232 | 241 | ||
242 | if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) | ||
243 | goto do_confirm; | ||
233 | nfs4_begin_drain_session(clp); | 244 | nfs4_begin_drain_session(clp); |
234 | status = nfs4_proc_exchange_id(clp, cred); | 245 | status = nfs4_proc_exchange_id(clp, cred); |
235 | if (status != 0) | 246 | if (status != 0) |
236 | goto out; | 247 | goto out; |
248 | set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
249 | do_confirm: | ||
237 | status = nfs4_proc_create_session(clp); | 250 | status = nfs4_proc_create_session(clp); |
238 | if (status != 0) | 251 | if (status != 0) |
239 | goto out; | 252 | goto out; |
253 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | ||
240 | nfs41_setup_state_renewal(clp); | 254 | nfs41_setup_state_renewal(clp); |
241 | nfs_mark_client_ready(clp, NFS_CS_READY); | 255 | nfs_mark_client_ready(clp, NFS_CS_READY); |
242 | out: | 256 | out: |
@@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } | |||
1584 | */ | 1598 | */ |
1585 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | 1599 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) |
1586 | { | 1600 | { |
1587 | if (nfs4_has_session(clp)) { | 1601 | switch (status) { |
1588 | switch (status) { | 1602 | case -NFS4ERR_CLID_INUSE: |
1589 | case -NFS4ERR_DELAY: | 1603 | case -NFS4ERR_STALE_CLIENTID: |
1590 | case -NFS4ERR_CLID_INUSE: | 1604 | clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); |
1591 | case -EAGAIN: | 1605 | break; |
1592 | break; | 1606 | case -NFS4ERR_DELAY: |
1607 | case -ETIMEDOUT: | ||
1608 | case -EAGAIN: | ||
1609 | ssleep(1); | ||
1610 | break; | ||
1593 | 1611 | ||
1594 | case -EKEYEXPIRED: | 1612 | case -EKEYEXPIRED: |
1595 | nfs4_warn_keyexpired(clp->cl_hostname); | 1613 | nfs4_warn_keyexpired(clp->cl_hostname); |
1596 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | 1614 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery |
1597 | * in nfs4_exchange_id */ | 1615 | * in nfs4_exchange_id */ |
1598 | default: | 1616 | default: |
1599 | return; | 1617 | return; |
1600 | } | ||
1601 | } | 1618 | } |
1602 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1619 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1603 | } | 1620 | } |
@@ -1607,7 +1624,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1607 | int status = 0; | 1624 | int status = 0; |
1608 | 1625 | ||
1609 | /* Ensure exclusive access to NFSv4 state */ | 1626 | /* Ensure exclusive access to NFSv4 state */ |
1610 | for(;;) { | 1627 | do { |
1611 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { | 1628 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) { |
1612 | /* We're going to have to re-establish a clientid */ | 1629 | /* We're going to have to re-establish a clientid */ |
1613 | status = nfs4_reclaim_lease(clp); | 1630 | status = nfs4_reclaim_lease(clp); |
@@ -1691,7 +1708,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1691 | break; | 1708 | break; |
1692 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | 1709 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
1693 | break; | 1710 | break; |
1694 | } | 1711 | } while (atomic_read(&clp->cl_count) > 1); |
1695 | return; | 1712 | return; |
1696 | out_error: | 1713 | out_error: |
1697 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" | 1714 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index dddfb5795d7b..c3ccd2c46834 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1452,26 +1452,25 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1452 | 1452 | ||
1453 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1453 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
1454 | { | 1454 | { |
1455 | uint32_t attrs[2] = {0, 0}; | 1455 | uint32_t attrs[2] = { |
1456 | FATTR4_WORD0_RDATTR_ERROR, | ||
1457 | FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
1458 | }; | ||
1456 | uint32_t dircount = readdir->count >> 1; | 1459 | uint32_t dircount = readdir->count >> 1; |
1457 | __be32 *p; | 1460 | __be32 *p; |
1458 | 1461 | ||
1459 | if (readdir->plus) { | 1462 | if (readdir->plus) { |
1460 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| | 1463 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| |
1461 | FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE; | 1464 | FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID; |
1462 | attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| | 1465 | attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| |
1463 | FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| | 1466 | FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| |
1464 | FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| | 1467 | FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| |
1465 | FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 1468 | FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1466 | dircount >>= 1; | 1469 | dircount >>= 1; |
1467 | } | 1470 | } |
1468 | attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID; | 1471 | /* Use mounted_on_fileid only if the server supports it */ |
1469 | attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; | 1472 | if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) |
1470 | /* Switch to mounted_on_fileid if the server supports it */ | 1473 | attrs[0] |= FATTR4_WORD0_FILEID; |
1471 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
1472 | attrs[0] &= ~FATTR4_WORD0_FILEID; | ||
1473 | else | ||
1474 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
1475 | 1474 | ||
1476 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); | 1475 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); |
1477 | *p++ = cpu_to_be32(OP_READDIR); | 1476 | *p++ = cpu_to_be32(OP_READDIR); |
@@ -3140,7 +3139,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma | |||
3140 | goto out_overflow; | 3139 | goto out_overflow; |
3141 | xdr_decode_hyper(p, fileid); | 3140 | xdr_decode_hyper(p, fileid); |
3142 | bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 3141 | bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
3143 | ret = NFS_ATTR_FATTR_FILEID; | 3142 | ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID; |
3144 | } | 3143 | } |
3145 | dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); | 3144 | dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid); |
3146 | return ret; | 3145 | return ret; |
@@ -4002,7 +4001,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4002 | { | 4001 | { |
4003 | int status; | 4002 | int status; |
4004 | umode_t fmode = 0; | 4003 | umode_t fmode = 0; |
4005 | uint64_t fileid; | ||
4006 | uint32_t type; | 4004 | uint32_t type; |
4007 | 4005 | ||
4008 | status = decode_attr_type(xdr, bitmap, &type); | 4006 | status = decode_attr_type(xdr, bitmap, &type); |
@@ -4101,13 +4099,10 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4101 | goto xdr_error; | 4099 | goto xdr_error; |
4102 | fattr->valid |= status; | 4100 | fattr->valid |= status; |
4103 | 4101 | ||
4104 | status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid); | 4102 | status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid); |
4105 | if (status < 0) | 4103 | if (status < 0) |
4106 | goto xdr_error; | 4104 | goto xdr_error; |
4107 | if (status != 0 && !(fattr->valid & status)) { | 4105 | fattr->valid |= status; |
4108 | fattr->fileid = fileid; | ||
4109 | fattr->valid |= status; | ||
4110 | } | ||
4111 | 4106 | ||
4112 | xdr_error: | 4107 | xdr_error: |
4113 | dprintk("%s: xdr returned %d\n", __func__, -status); | 4108 | dprintk("%s: xdr returned %d\n", __func__, -status); |
@@ -4838,17 +4833,21 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | |||
4838 | struct nfs4_secinfo_flavor *sec_flavor; | 4833 | struct nfs4_secinfo_flavor *sec_flavor; |
4839 | int status; | 4834 | int status; |
4840 | __be32 *p; | 4835 | __be32 *p; |
4841 | int i; | 4836 | int i, num_flavors; |
4842 | 4837 | ||
4843 | status = decode_op_hdr(xdr, OP_SECINFO); | 4838 | status = decode_op_hdr(xdr, OP_SECINFO); |
4839 | if (status) | ||
4840 | goto out; | ||
4844 | p = xdr_inline_decode(xdr, 4); | 4841 | p = xdr_inline_decode(xdr, 4); |
4845 | if (unlikely(!p)) | 4842 | if (unlikely(!p)) |
4846 | goto out_overflow; | 4843 | goto out_overflow; |
4847 | res->flavors->num_flavors = be32_to_cpup(p); | ||
4848 | 4844 | ||
4849 | for (i = 0; i < res->flavors->num_flavors; i++) { | 4845 | res->flavors->num_flavors = 0; |
4846 | num_flavors = be32_to_cpup(p); | ||
4847 | |||
4848 | for (i = 0; i < num_flavors; i++) { | ||
4850 | sec_flavor = &res->flavors->flavors[i]; | 4849 | sec_flavor = &res->flavors->flavors[i]; |
4851 | if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE) | 4850 | if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE) |
4852 | break; | 4851 | break; |
4853 | 4852 | ||
4854 | p = xdr_inline_decode(xdr, 4); | 4853 | p = xdr_inline_decode(xdr, 4); |
@@ -4857,13 +4856,15 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | |||
4857 | sec_flavor->flavor = be32_to_cpup(p); | 4856 | sec_flavor->flavor = be32_to_cpup(p); |
4858 | 4857 | ||
4859 | if (sec_flavor->flavor == RPC_AUTH_GSS) { | 4858 | if (sec_flavor->flavor == RPC_AUTH_GSS) { |
4860 | if (decode_secinfo_gss(xdr, sec_flavor)) | 4859 | status = decode_secinfo_gss(xdr, sec_flavor); |
4861 | break; | 4860 | if (status) |
4861 | goto out; | ||
4862 | } | 4862 | } |
4863 | res->flavors->num_flavors++; | ||
4863 | } | 4864 | } |
4864 | 4865 | ||
4865 | return 0; | 4866 | out: |
4866 | 4867 | return status; | |
4867 | out_overflow: | 4868 | out_overflow: |
4868 | print_overflow_msg(__func__, xdr); | 4869 | print_overflow_msg(__func__, xdr); |
4869 | return -EIO; | 4870 | return -EIO; |
@@ -6408,7 +6409,9 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
6408 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, | 6409 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, |
6409 | entry->server, 1) < 0) | 6410 | entry->server, 1) < 0) |
6410 | goto out_overflow; | 6411 | goto out_overflow; |
6411 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) | 6412 | if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) |
6413 | entry->ino = entry->fattr->mounted_on_fileid; | ||
6414 | else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) | ||
6412 | entry->ino = entry->fattr->fileid; | 6415 | entry->ino = entry->fattr->fileid; |
6413 | 6416 | ||
6414 | entry->d_type = DT_UNKNOWN; | 6417 | entry->d_type = DT_UNKNOWN; |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index d9ab97269ce6..ff681ab65d31 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1004,6 +1004,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) | |||
1004 | { | 1004 | { |
1005 | struct nfs_inode *nfsi = NFS_I(wdata->inode); | 1005 | struct nfs_inode *nfsi = NFS_I(wdata->inode); |
1006 | loff_t end_pos = wdata->args.offset + wdata->res.count; | 1006 | loff_t end_pos = wdata->args.offset + wdata->res.count; |
1007 | bool mark_as_dirty = false; | ||
1007 | 1008 | ||
1008 | spin_lock(&nfsi->vfs_inode.i_lock); | 1009 | spin_lock(&nfsi->vfs_inode.i_lock); |
1009 | if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | 1010 | if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { |
@@ -1011,13 +1012,18 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) | |||
1011 | get_lseg(wdata->lseg); | 1012 | get_lseg(wdata->lseg); |
1012 | wdata->lseg->pls_lc_cred = | 1013 | wdata->lseg->pls_lc_cred = |
1013 | get_rpccred(wdata->args.context->state->owner->so_cred); | 1014 | get_rpccred(wdata->args.context->state->owner->so_cred); |
1014 | mark_inode_dirty_sync(wdata->inode); | 1015 | mark_as_dirty = true; |
1015 | dprintk("%s: Set layoutcommit for inode %lu ", | 1016 | dprintk("%s: Set layoutcommit for inode %lu ", |
1016 | __func__, wdata->inode->i_ino); | 1017 | __func__, wdata->inode->i_ino); |
1017 | } | 1018 | } |
1018 | if (end_pos > wdata->lseg->pls_end_pos) | 1019 | if (end_pos > wdata->lseg->pls_end_pos) |
1019 | wdata->lseg->pls_end_pos = end_pos; | 1020 | wdata->lseg->pls_end_pos = end_pos; |
1020 | spin_unlock(&nfsi->vfs_inode.i_lock); | 1021 | spin_unlock(&nfsi->vfs_inode.i_lock); |
1022 | |||
1023 | /* if pnfs_layoutcommit_inode() runs between inode locks, the next one | ||
1024 | * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */ | ||
1025 | if (mark_as_dirty) | ||
1026 | mark_inode_dirty_sync(wdata->inode); | ||
1021 | } | 1027 | } |
1022 | EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); | 1028 | EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); |
1023 | 1029 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2b8e9a5e366a..e288f06d3fa7 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -1004,6 +1004,7 @@ static int nfs_parse_security_flavors(char *value, | |||
1004 | return 0; | 1004 | return 0; |
1005 | } | 1005 | } |
1006 | 1006 | ||
1007 | mnt->flags |= NFS_MOUNT_SECFLAVOUR; | ||
1007 | mnt->auth_flavor_len = 1; | 1008 | mnt->auth_flavor_len = 1; |
1008 | return 1; | 1009 | return 1; |
1009 | } | 1010 | } |
@@ -1976,6 +1977,15 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
1976 | if (error < 0) | 1977 | if (error < 0) |
1977 | goto out; | 1978 | goto out; |
1978 | 1979 | ||
1980 | /* | ||
1981 | * noac is a special case. It implies -o sync, but that's not | ||
1982 | * necessarily reflected in the mtab options. do_remount_sb | ||
1983 | * will clear MS_SYNCHRONOUS if -o sync wasn't specified in the | ||
1984 | * remount options, so we have to explicitly reset it. | ||
1985 | */ | ||
1986 | if (data->flags & NFS_MOUNT_NOAC) | ||
1987 | *flags |= MS_SYNCHRONOUS; | ||
1988 | |||
1979 | /* compare new mount options with old ones */ | 1989 | /* compare new mount options with old ones */ |
1980 | error = nfs_compare_remount_data(nfss, data); | 1990 | error = nfs_compare_remount_data(nfss, data); |
1981 | out: | 1991 | out: |
@@ -2235,8 +2245,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | |||
2235 | if (!s->s_root) { | 2245 | if (!s->s_root) { |
2236 | /* initial superblock/root creation */ | 2246 | /* initial superblock/root creation */ |
2237 | nfs_fill_super(s, data); | 2247 | nfs_fill_super(s, data); |
2238 | nfs_fscache_get_super_cookie( | 2248 | nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL); |
2239 | s, data ? data->fscache_uniq : NULL, NULL); | ||
2240 | } | 2249 | } |
2241 | 2250 | ||
2242 | mntroot = nfs_get_root(s, mntfh, dev_name); | 2251 | mntroot = nfs_get_root(s, mntfh, dev_name); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e4cbc11a74ab..3bd5d7e80f6c 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -680,7 +680,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
680 | req = nfs_setup_write_request(ctx, page, offset, count); | 680 | req = nfs_setup_write_request(ctx, page, offset, count); |
681 | if (IS_ERR(req)) | 681 | if (IS_ERR(req)) |
682 | return PTR_ERR(req); | 682 | return PTR_ERR(req); |
683 | nfs_mark_request_dirty(req); | ||
684 | /* Update file length */ | 683 | /* Update file length */ |
685 | nfs_grow_file(page, offset, count); | 684 | nfs_grow_file(page, offset, count); |
686 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 685 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
@@ -1418,8 +1417,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1418 | task->tk_pid, task->tk_status); | 1417 | task->tk_pid, task->tk_status); |
1419 | 1418 | ||
1420 | /* Call the NFS version-specific code */ | 1419 | /* Call the NFS version-specific code */ |
1421 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 1420 | NFS_PROTO(data->inode)->commit_done(task, data); |
1422 | return; | ||
1423 | } | 1421 | } |
1424 | 1422 | ||
1425 | void nfs_commit_release_pages(struct nfs_write_data *data) | 1423 | void nfs_commit_release_pages(struct nfs_write_data *data) |