diff options
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 89fc160fd5b..1f063bacd28 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 e1c261ddd65..c4a69833dd0 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 9bf41eab3e4..69c0f3c5ee7 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 a6804f704d9..036f5adc9e1 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 dddfb5795d7..c3ccd2c4683 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 d9ab97269ce..ff681ab65d3 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 2b8e9a5e366..e288f06d3fa 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 e4cbc11a74a..3bd5d7e80f6 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) |
