diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-11 13:17:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-11 13:17:13 -0400 |
commit | 0ff08ba5d066619f9973bfcdb5a21320d54219d0 (patch) | |
tree | 526e4a5799eb3023e9d5d81e81c0964b1d928a3e /fs/nfsd/nfs4state.c | |
parent | c72bb316916b1a6cf35e1d5238566ef27b0b7f80 (diff) | |
parent | d109148111cdfcdae94f797dc142468bd0ff7557 (diff) |
Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
Pull nfsd changes from Bruce Fields:
"Changes this time include:
- 4.1 enabled on the server by default: the last 4.1-specific issues
I know of are fixed, so we're not going to find the rest of the
bugs without more exposure.
- Experimental support for NFSv4.2 MAC Labeling (to allow running
selinux over NFS), from Dave Quigley.
- Fixes for some delicate cache/upcall races that could cause rare
server hangs; thanks to Neil Brown and Bodo Stroesser for extreme
debugging persistence.
- Fixes for some bugs found at the recent NFS bakeathon, mostly v4
and v4.1-specific, but also a generic bug handling fragmented rpc
calls"
* 'for-3.11' of git://linux-nfs.org/~bfields/linux: (31 commits)
nfsd4: support minorversion 1 by default
nfsd4: allow destroy_session over destroyed session
svcrpc: fix failures to handle -1 uid's
sunrpc: Don't schedule an upcall on a replaced cache entry.
net/sunrpc: xpt_auth_cache should be ignored when expired.
sunrpc/cache: ensure items removed from cache do not have pending upcalls.
sunrpc/cache: use cache_fresh_unlocked consistently and correctly.
sunrpc/cache: remove races with queuing an upcall.
nfsd4: return delegation immediately if lease fails
nfsd4: do not throw away 4.1 lock state on last unlock
nfsd4: delegation-based open reclaims should bypass permissions
svcrpc: don't error out on small tcp fragment
svcrpc: fix handling of too-short rpc's
nfsd4: minor read_buf cleanup
nfsd4: fix decoding of compounds across page boundaries
nfsd4: clean up nfs4_open_delegation
NFSD: Don't give out read delegations on creates
nfsd4: allow client to send no cb_sec flavors
nfsd4: fail attempts to request gss on the backchannel
nfsd4: implement minimal SP4_MACH_CRED
...
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 225 |
1 files changed, 152 insertions, 73 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f17051838b41..280acef6f0dc 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -97,19 +97,20 @@ nfs4_lock_state(void) | |||
97 | 97 | ||
98 | static void free_session(struct nfsd4_session *); | 98 | static void free_session(struct nfsd4_session *); |
99 | 99 | ||
100 | void nfsd4_put_session(struct nfsd4_session *ses) | 100 | static bool is_session_dead(struct nfsd4_session *ses) |
101 | { | 101 | { |
102 | atomic_dec(&ses->se_ref); | 102 | return ses->se_flags & NFS4_SESSION_DEAD; |
103 | } | 103 | } |
104 | 104 | ||
105 | static bool is_session_dead(struct nfsd4_session *ses) | 105 | void nfsd4_put_session(struct nfsd4_session *ses) |
106 | { | 106 | { |
107 | return ses->se_flags & NFS4_SESSION_DEAD; | 107 | if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) |
108 | free_session(ses); | ||
108 | } | 109 | } |
109 | 110 | ||
110 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses) | 111 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) |
111 | { | 112 | { |
112 | if (atomic_read(&ses->se_ref)) | 113 | if (atomic_read(&ses->se_ref) > ref_held_by_me) |
113 | return nfserr_jukebox; | 114 | return nfserr_jukebox; |
114 | ses->se_flags |= NFS4_SESSION_DEAD; | 115 | ses->se_flags |= NFS4_SESSION_DEAD; |
115 | return nfs_ok; | 116 | return nfs_ok; |
@@ -364,19 +365,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) | |||
364 | } | 365 | } |
365 | 366 | ||
366 | static struct nfs4_delegation * | 367 | static struct nfs4_delegation * |
367 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type) | 368 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) |
368 | { | 369 | { |
369 | struct nfs4_delegation *dp; | 370 | struct nfs4_delegation *dp; |
370 | struct nfs4_file *fp = stp->st_file; | 371 | struct nfs4_file *fp = stp->st_file; |
371 | 372 | ||
372 | dprintk("NFSD alloc_init_deleg\n"); | 373 | dprintk("NFSD alloc_init_deleg\n"); |
373 | /* | ||
374 | * Major work on the lease subsystem (for example, to support | ||
375 | * calbacks on stat) will be required before we can support | ||
376 | * write delegations properly. | ||
377 | */ | ||
378 | if (type != NFS4_OPEN_DELEGATE_READ) | ||
379 | return NULL; | ||
380 | if (fp->fi_had_conflict) | 374 | if (fp->fi_had_conflict) |
381 | return NULL; | 375 | return NULL; |
382 | if (num_delegations > max_delegations) | 376 | if (num_delegations > max_delegations) |
@@ -397,7 +391,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
397 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 391 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
398 | get_nfs4_file(fp); | 392 | get_nfs4_file(fp); |
399 | dp->dl_file = fp; | 393 | dp->dl_file = fp; |
400 | dp->dl_type = type; | 394 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; |
401 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 395 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
402 | dp->dl_time = 0; | 396 | dp->dl_time = 0; |
403 | atomic_set(&dp->dl_count, 1); | 397 | atomic_set(&dp->dl_count, 1); |
@@ -1188,6 +1182,9 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) | |||
1188 | target->cr_gid = source->cr_gid; | 1182 | target->cr_gid = source->cr_gid; |
1189 | target->cr_group_info = source->cr_group_info; | 1183 | target->cr_group_info = source->cr_group_info; |
1190 | get_group_info(target->cr_group_info); | 1184 | get_group_info(target->cr_group_info); |
1185 | target->cr_gss_mech = source->cr_gss_mech; | ||
1186 | if (source->cr_gss_mech) | ||
1187 | gss_mech_get(source->cr_gss_mech); | ||
1191 | return 0; | 1188 | return 0; |
1192 | } | 1189 | } |
1193 | 1190 | ||
@@ -1262,6 +1259,31 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
1262 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | 1259 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); |
1263 | } | 1260 | } |
1264 | 1261 | ||
1262 | static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) | ||
1263 | { | ||
1264 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1265 | u32 service; | ||
1266 | |||
1267 | service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); | ||
1268 | return service == RPC_GSS_SVC_INTEGRITY || | ||
1269 | service == RPC_GSS_SVC_PRIVACY; | ||
1270 | } | ||
1271 | |||
1272 | static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) | ||
1273 | { | ||
1274 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1275 | |||
1276 | if (!cl->cl_mach_cred) | ||
1277 | return true; | ||
1278 | if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) | ||
1279 | return false; | ||
1280 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1281 | return false; | ||
1282 | if (!cr->cr_principal) | ||
1283 | return false; | ||
1284 | return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); | ||
1285 | } | ||
1286 | |||
1265 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) | 1287 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) |
1266 | { | 1288 | { |
1267 | static u32 current_clientid = 1; | 1289 | static u32 current_clientid = 1; |
@@ -1639,16 +1661,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1639 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) | 1661 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) |
1640 | return nfserr_inval; | 1662 | return nfserr_inval; |
1641 | 1663 | ||
1642 | /* Currently only support SP4_NONE */ | ||
1643 | switch (exid->spa_how) { | 1664 | switch (exid->spa_how) { |
1665 | case SP4_MACH_CRED: | ||
1666 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1667 | return nfserr_inval; | ||
1644 | case SP4_NONE: | 1668 | case SP4_NONE: |
1645 | break; | 1669 | break; |
1646 | default: /* checked by xdr code */ | 1670 | default: /* checked by xdr code */ |
1647 | WARN_ON_ONCE(1); | 1671 | WARN_ON_ONCE(1); |
1648 | case SP4_SSV: | 1672 | case SP4_SSV: |
1649 | return nfserr_encr_alg_unsupp; | 1673 | return nfserr_encr_alg_unsupp; |
1650 | case SP4_MACH_CRED: | ||
1651 | return nfserr_serverfault; /* no excuse :-/ */ | ||
1652 | } | 1674 | } |
1653 | 1675 | ||
1654 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1676 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
@@ -1663,6 +1685,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1663 | status = nfserr_inval; | 1685 | status = nfserr_inval; |
1664 | goto out; | 1686 | goto out; |
1665 | } | 1687 | } |
1688 | if (!mach_creds_match(conf, rqstp)) { | ||
1689 | status = nfserr_wrong_cred; | ||
1690 | goto out; | ||
1691 | } | ||
1666 | if (!creds_match) { /* case 9 */ | 1692 | if (!creds_match) { /* case 9 */ |
1667 | status = nfserr_perm; | 1693 | status = nfserr_perm; |
1668 | goto out; | 1694 | goto out; |
@@ -1709,7 +1735,8 @@ out_new: | |||
1709 | status = nfserr_jukebox; | 1735 | status = nfserr_jukebox; |
1710 | goto out; | 1736 | goto out; |
1711 | } | 1737 | } |
1712 | new->cl_minorversion = 1; | 1738 | new->cl_minorversion = cstate->minorversion; |
1739 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); | ||
1713 | 1740 | ||
1714 | gen_clid(new, nn); | 1741 | gen_clid(new, nn); |
1715 | add_to_unconfirmed(new); | 1742 | add_to_unconfirmed(new); |
@@ -1839,6 +1866,24 @@ static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) | |||
1839 | return nfs_ok; | 1866 | return nfs_ok; |
1840 | } | 1867 | } |
1841 | 1868 | ||
1869 | static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) | ||
1870 | { | ||
1871 | switch (cbs->flavor) { | ||
1872 | case RPC_AUTH_NULL: | ||
1873 | case RPC_AUTH_UNIX: | ||
1874 | return nfs_ok; | ||
1875 | default: | ||
1876 | /* | ||
1877 | * GSS case: the spec doesn't allow us to return this | ||
1878 | * error. But it also doesn't allow us not to support | ||
1879 | * GSS. | ||
1880 | * I'd rather this fail hard than return some error the | ||
1881 | * client might think it can already handle: | ||
1882 | */ | ||
1883 | return nfserr_encr_alg_unsupp; | ||
1884 | } | ||
1885 | } | ||
1886 | |||
1842 | __be32 | 1887 | __be32 |
1843 | nfsd4_create_session(struct svc_rqst *rqstp, | 1888 | nfsd4_create_session(struct svc_rqst *rqstp, |
1844 | struct nfsd4_compound_state *cstate, | 1889 | struct nfsd4_compound_state *cstate, |
@@ -1854,6 +1899,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1854 | 1899 | ||
1855 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1900 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1856 | return nfserr_inval; | 1901 | return nfserr_inval; |
1902 | status = nfsd4_check_cb_sec(&cr_ses->cb_sec); | ||
1903 | if (status) | ||
1904 | return status; | ||
1857 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); | 1905 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); |
1858 | if (status) | 1906 | if (status) |
1859 | return status; | 1907 | return status; |
@@ -1874,6 +1922,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1874 | WARN_ON_ONCE(conf && unconf); | 1922 | WARN_ON_ONCE(conf && unconf); |
1875 | 1923 | ||
1876 | if (conf) { | 1924 | if (conf) { |
1925 | status = nfserr_wrong_cred; | ||
1926 | if (!mach_creds_match(conf, rqstp)) | ||
1927 | goto out_free_conn; | ||
1877 | cs_slot = &conf->cl_cs_slot; | 1928 | cs_slot = &conf->cl_cs_slot; |
1878 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1929 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1879 | if (status == nfserr_replay_cache) { | 1930 | if (status == nfserr_replay_cache) { |
@@ -1890,6 +1941,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1890 | status = nfserr_clid_inuse; | 1941 | status = nfserr_clid_inuse; |
1891 | goto out_free_conn; | 1942 | goto out_free_conn; |
1892 | } | 1943 | } |
1944 | status = nfserr_wrong_cred; | ||
1945 | if (!mach_creds_match(unconf, rqstp)) | ||
1946 | goto out_free_conn; | ||
1893 | cs_slot = &unconf->cl_cs_slot; | 1947 | cs_slot = &unconf->cl_cs_slot; |
1894 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1948 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1895 | if (status) { | 1949 | if (status) { |
@@ -1957,7 +2011,11 @@ __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state | |||
1957 | { | 2011 | { |
1958 | struct nfsd4_session *session = cstate->session; | 2012 | struct nfsd4_session *session = cstate->session; |
1959 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 2013 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2014 | __be32 status; | ||
1960 | 2015 | ||
2016 | status = nfsd4_check_cb_sec(&bc->bc_cb_sec); | ||
2017 | if (status) | ||
2018 | return status; | ||
1961 | spin_lock(&nn->client_lock); | 2019 | spin_lock(&nn->client_lock); |
1962 | session->se_cb_prog = bc->bc_cb_program; | 2020 | session->se_cb_prog = bc->bc_cb_program; |
1963 | session->se_cb_sec = bc->bc_cb_sec; | 2021 | session->se_cb_sec = bc->bc_cb_sec; |
@@ -1986,6 +2044,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | |||
1986 | status = nfserr_badsession; | 2044 | status = nfserr_badsession; |
1987 | if (!session) | 2045 | if (!session) |
1988 | goto out; | 2046 | goto out; |
2047 | status = nfserr_wrong_cred; | ||
2048 | if (!mach_creds_match(session->se_client, rqstp)) | ||
2049 | goto out; | ||
1989 | status = nfsd4_map_bcts_dir(&bcts->dir); | 2050 | status = nfsd4_map_bcts_dir(&bcts->dir); |
1990 | if (status) | 2051 | if (status) |
1991 | goto out; | 2052 | goto out; |
@@ -2014,6 +2075,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2014 | { | 2075 | { |
2015 | struct nfsd4_session *ses; | 2076 | struct nfsd4_session *ses; |
2016 | __be32 status; | 2077 | __be32 status; |
2078 | int ref_held_by_me = 0; | ||
2017 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); | 2079 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); |
2018 | 2080 | ||
2019 | nfs4_lock_state(); | 2081 | nfs4_lock_state(); |
@@ -2021,6 +2083,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2021 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { | 2083 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { |
2022 | if (!nfsd4_last_compound_op(r)) | 2084 | if (!nfsd4_last_compound_op(r)) |
2023 | goto out; | 2085 | goto out; |
2086 | ref_held_by_me++; | ||
2024 | } | 2087 | } |
2025 | dump_sessionid(__func__, &sessionid->sessionid); | 2088 | dump_sessionid(__func__, &sessionid->sessionid); |
2026 | spin_lock(&nn->client_lock); | 2089 | spin_lock(&nn->client_lock); |
@@ -2028,17 +2091,22 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2028 | status = nfserr_badsession; | 2091 | status = nfserr_badsession; |
2029 | if (!ses) | 2092 | if (!ses) |
2030 | goto out_client_lock; | 2093 | goto out_client_lock; |
2031 | status = mark_session_dead_locked(ses); | 2094 | status = nfserr_wrong_cred; |
2032 | if (status) | 2095 | if (!mach_creds_match(ses->se_client, r)) |
2033 | goto out_client_lock; | 2096 | goto out_client_lock; |
2097 | nfsd4_get_session_locked(ses); | ||
2098 | status = mark_session_dead_locked(ses, 1 + ref_held_by_me); | ||
2099 | if (status) | ||
2100 | goto out_put_session; | ||
2034 | unhash_session(ses); | 2101 | unhash_session(ses); |
2035 | spin_unlock(&nn->client_lock); | 2102 | spin_unlock(&nn->client_lock); |
2036 | 2103 | ||
2037 | nfsd4_probe_callback_sync(ses->se_client); | 2104 | nfsd4_probe_callback_sync(ses->se_client); |
2038 | 2105 | ||
2039 | spin_lock(&nn->client_lock); | 2106 | spin_lock(&nn->client_lock); |
2040 | free_session(ses); | ||
2041 | status = nfs_ok; | 2107 | status = nfs_ok; |
2108 | out_put_session: | ||
2109 | nfsd4_put_session(ses); | ||
2042 | out_client_lock: | 2110 | out_client_lock: |
2043 | spin_unlock(&nn->client_lock); | 2111 | spin_unlock(&nn->client_lock); |
2044 | out: | 2112 | out: |
@@ -2058,26 +2126,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s | |||
2058 | return NULL; | 2126 | return NULL; |
2059 | } | 2127 | } |
2060 | 2128 | ||
2061 | static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) | 2129 | static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) |
2062 | { | 2130 | { |
2063 | struct nfs4_client *clp = ses->se_client; | 2131 | struct nfs4_client *clp = ses->se_client; |
2064 | struct nfsd4_conn *c; | 2132 | struct nfsd4_conn *c; |
2133 | __be32 status = nfs_ok; | ||
2065 | int ret; | 2134 | int ret; |
2066 | 2135 | ||
2067 | spin_lock(&clp->cl_lock); | 2136 | spin_lock(&clp->cl_lock); |
2068 | c = __nfsd4_find_conn(new->cn_xprt, ses); | 2137 | c = __nfsd4_find_conn(new->cn_xprt, ses); |
2069 | if (c) { | 2138 | if (c) |
2070 | spin_unlock(&clp->cl_lock); | 2139 | goto out_free; |
2071 | free_conn(new); | 2140 | status = nfserr_conn_not_bound_to_session; |
2072 | return; | 2141 | if (clp->cl_mach_cred) |
2073 | } | 2142 | goto out_free; |
2074 | __nfsd4_hash_conn(new, ses); | 2143 | __nfsd4_hash_conn(new, ses); |
2075 | spin_unlock(&clp->cl_lock); | 2144 | spin_unlock(&clp->cl_lock); |
2076 | ret = nfsd4_register_conn(new); | 2145 | ret = nfsd4_register_conn(new); |
2077 | if (ret) | 2146 | if (ret) |
2078 | /* oops; xprt is already down: */ | 2147 | /* oops; xprt is already down: */ |
2079 | nfsd4_conn_lost(&new->cn_xpt_user); | 2148 | nfsd4_conn_lost(&new->cn_xpt_user); |
2080 | return; | 2149 | return nfs_ok; |
2150 | out_free: | ||
2151 | spin_unlock(&clp->cl_lock); | ||
2152 | free_conn(new); | ||
2153 | return status; | ||
2081 | } | 2154 | } |
2082 | 2155 | ||
2083 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) | 2156 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) |
@@ -2169,8 +2242,10 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2169 | if (status) | 2242 | if (status) |
2170 | goto out_put_session; | 2243 | goto out_put_session; |
2171 | 2244 | ||
2172 | nfsd4_sequence_check_conn(conn, session); | 2245 | status = nfsd4_sequence_check_conn(conn, session); |
2173 | conn = NULL; | 2246 | conn = NULL; |
2247 | if (status) | ||
2248 | goto out_put_session; | ||
2174 | 2249 | ||
2175 | /* Success! bump slot seqid */ | 2250 | /* Success! bump slot seqid */ |
2176 | slot->sl_seqid = seq->seqid; | 2251 | slot->sl_seqid = seq->seqid; |
@@ -2232,7 +2307,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2232 | status = nfserr_stale_clientid; | 2307 | status = nfserr_stale_clientid; |
2233 | goto out; | 2308 | goto out; |
2234 | } | 2309 | } |
2235 | 2310 | if (!mach_creds_match(clp, rqstp)) { | |
2311 | status = nfserr_wrong_cred; | ||
2312 | goto out; | ||
2313 | } | ||
2236 | expire_client(clp); | 2314 | expire_client(clp); |
2237 | out: | 2315 | out: |
2238 | nfs4_unlock_state(); | 2316 | nfs4_unlock_state(); |
@@ -2940,13 +3018,13 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f | |||
2940 | return fl; | 3018 | return fl; |
2941 | } | 3019 | } |
2942 | 3020 | ||
2943 | static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | 3021 | static int nfs4_setlease(struct nfs4_delegation *dp) |
2944 | { | 3022 | { |
2945 | struct nfs4_file *fp = dp->dl_file; | 3023 | struct nfs4_file *fp = dp->dl_file; |
2946 | struct file_lock *fl; | 3024 | struct file_lock *fl; |
2947 | int status; | 3025 | int status; |
2948 | 3026 | ||
2949 | fl = nfs4_alloc_init_lease(dp, flag); | 3027 | fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); |
2950 | if (!fl) | 3028 | if (!fl) |
2951 | return -ENOMEM; | 3029 | return -ENOMEM; |
2952 | fl->fl_file = find_readable_file(fp); | 3030 | fl->fl_file = find_readable_file(fp); |
@@ -2964,12 +3042,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | |||
2964 | return 0; | 3042 | return 0; |
2965 | } | 3043 | } |
2966 | 3044 | ||
2967 | static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | 3045 | static int nfs4_set_delegation(struct nfs4_delegation *dp) |
2968 | { | 3046 | { |
2969 | struct nfs4_file *fp = dp->dl_file; | 3047 | struct nfs4_file *fp = dp->dl_file; |
2970 | 3048 | ||
2971 | if (!fp->fi_lease) | 3049 | if (!fp->fi_lease) |
2972 | return nfs4_setlease(dp, flag); | 3050 | return nfs4_setlease(dp); |
2973 | spin_lock(&recall_lock); | 3051 | spin_lock(&recall_lock); |
2974 | if (fp->fi_had_conflict) { | 3052 | if (fp->fi_had_conflict) { |
2975 | spin_unlock(&recall_lock); | 3053 | spin_unlock(&recall_lock); |
@@ -3005,6 +3083,9 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | |||
3005 | 3083 | ||
3006 | /* | 3084 | /* |
3007 | * Attempt to hand out a delegation. | 3085 | * Attempt to hand out a delegation. |
3086 | * | ||
3087 | * Note we don't support write delegations, and won't until the vfs has | ||
3088 | * proper support for them. | ||
3008 | */ | 3089 | */ |
3009 | static void | 3090 | static void |
3010 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, | 3091 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, |
@@ -3013,39 +3094,45 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3013 | struct nfs4_delegation *dp; | 3094 | struct nfs4_delegation *dp; |
3014 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); | 3095 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); |
3015 | int cb_up; | 3096 | int cb_up; |
3016 | int status = 0, flag = 0; | 3097 | int status = 0; |
3017 | 3098 | ||
3018 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); | 3099 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); |
3019 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
3020 | open->op_recall = 0; | 3100 | open->op_recall = 0; |
3021 | switch (open->op_claim_type) { | 3101 | switch (open->op_claim_type) { |
3022 | case NFS4_OPEN_CLAIM_PREVIOUS: | 3102 | case NFS4_OPEN_CLAIM_PREVIOUS: |
3023 | if (!cb_up) | 3103 | if (!cb_up) |
3024 | open->op_recall = 1; | 3104 | open->op_recall = 1; |
3025 | flag = open->op_delegate_type; | 3105 | if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) |
3026 | if (flag == NFS4_OPEN_DELEGATE_NONE) | 3106 | goto out_no_deleg; |
3027 | goto out; | ||
3028 | break; | 3107 | break; |
3029 | case NFS4_OPEN_CLAIM_NULL: | 3108 | case NFS4_OPEN_CLAIM_NULL: |
3030 | /* Let's not give out any delegations till everyone's | 3109 | /* |
3031 | * had the chance to reclaim theirs.... */ | 3110 | * Let's not give out any delegations till everyone's |
3111 | * had the chance to reclaim theirs.... | ||
3112 | */ | ||
3032 | if (locks_in_grace(net)) | 3113 | if (locks_in_grace(net)) |
3033 | goto out; | 3114 | goto out_no_deleg; |
3034 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) | 3115 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) |
3035 | goto out; | 3116 | goto out_no_deleg; |
3117 | /* | ||
3118 | * Also, if the file was opened for write or | ||
3119 | * create, there's a good chance the client's | ||
3120 | * about to write to it, resulting in an | ||
3121 | * immediate recall (since we don't support | ||
3122 | * write delegations): | ||
3123 | */ | ||
3036 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 3124 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
3037 | flag = NFS4_OPEN_DELEGATE_WRITE; | 3125 | goto out_no_deleg; |
3038 | else | 3126 | if (open->op_create == NFS4_OPEN_CREATE) |
3039 | flag = NFS4_OPEN_DELEGATE_READ; | 3127 | goto out_no_deleg; |
3040 | break; | 3128 | break; |
3041 | default: | 3129 | default: |
3042 | goto out; | 3130 | goto out_no_deleg; |
3043 | } | 3131 | } |
3044 | 3132 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); | |
3045 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); | ||
3046 | if (dp == NULL) | 3133 | if (dp == NULL) |
3047 | goto out_no_deleg; | 3134 | goto out_no_deleg; |
3048 | status = nfs4_set_delegation(dp, flag); | 3135 | status = nfs4_set_delegation(dp); |
3049 | if (status) | 3136 | if (status) |
3050 | goto out_free; | 3137 | goto out_free; |
3051 | 3138 | ||
@@ -3053,24 +3140,23 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3053 | 3140 | ||
3054 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", | 3141 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", |
3055 | STATEID_VAL(&dp->dl_stid.sc_stateid)); | 3142 | STATEID_VAL(&dp->dl_stid.sc_stateid)); |
3056 | out: | 3143 | open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; |
3057 | open->op_delegate_type = flag; | ||
3058 | if (flag == NFS4_OPEN_DELEGATE_NONE) { | ||
3059 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && | ||
3060 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
3061 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
3062 | |||
3063 | /* 4.1 client asking for a delegation? */ | ||
3064 | if (open->op_deleg_want) | ||
3065 | nfsd4_open_deleg_none_ext(open, status); | ||
3066 | } | ||
3067 | return; | 3144 | return; |
3068 | out_free: | 3145 | out_free: |
3069 | unhash_stid(&dp->dl_stid); | 3146 | unhash_stid(&dp->dl_stid); |
3070 | nfs4_put_delegation(dp); | 3147 | nfs4_put_delegation(dp); |
3071 | out_no_deleg: | 3148 | out_no_deleg: |
3072 | flag = NFS4_OPEN_DELEGATE_NONE; | 3149 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; |
3073 | goto out; | 3150 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && |
3151 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { | ||
3152 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
3153 | open->op_recall = 1; | ||
3154 | } | ||
3155 | |||
3156 | /* 4.1 client asking for a delegation? */ | ||
3157 | if (open->op_deleg_want) | ||
3158 | nfsd4_open_deleg_none_ext(open, status); | ||
3159 | return; | ||
3074 | } | 3160 | } |
3075 | 3161 | ||
3076 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, | 3162 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, |
@@ -3427,7 +3513,7 @@ grace_disallows_io(struct net *net, struct inode *inode) | |||
3427 | /* Returns true iff a is later than b: */ | 3513 | /* Returns true iff a is later than b: */ |
3428 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) | 3514 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) |
3429 | { | 3515 | { |
3430 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3516 | return (s32)(a->si_generation - b->si_generation) > 0; |
3431 | } | 3517 | } |
3432 | 3518 | ||
3433 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3519 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
@@ -4435,7 +4521,6 @@ __be32 | |||
4435 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 4521 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
4436 | struct nfsd4_locku *locku) | 4522 | struct nfsd4_locku *locku) |
4437 | { | 4523 | { |
4438 | struct nfs4_lockowner *lo; | ||
4439 | struct nfs4_ol_stateid *stp; | 4524 | struct nfs4_ol_stateid *stp; |
4440 | struct file *filp = NULL; | 4525 | struct file *filp = NULL; |
4441 | struct file_lock *file_lock = NULL; | 4526 | struct file_lock *file_lock = NULL; |
@@ -4468,10 +4553,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4468 | status = nfserr_jukebox; | 4553 | status = nfserr_jukebox; |
4469 | goto out; | 4554 | goto out; |
4470 | } | 4555 | } |
4471 | lo = lockowner(stp->st_stateowner); | ||
4472 | locks_init_lock(file_lock); | 4556 | locks_init_lock(file_lock); |
4473 | file_lock->fl_type = F_UNLCK; | 4557 | file_lock->fl_type = F_UNLCK; |
4474 | file_lock->fl_owner = (fl_owner_t)lo; | 4558 | file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); |
4475 | file_lock->fl_pid = current->tgid; | 4559 | file_lock->fl_pid = current->tgid; |
4476 | file_lock->fl_file = filp; | 4560 | file_lock->fl_file = filp; |
4477 | file_lock->fl_flags = FL_POSIX; | 4561 | file_lock->fl_flags = FL_POSIX; |
@@ -4490,11 +4574,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4490 | update_stateid(&stp->st_stid.sc_stateid); | 4574 | update_stateid(&stp->st_stid.sc_stateid); |
4491 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4575 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
4492 | 4576 | ||
4493 | if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) { | ||
4494 | WARN_ON_ONCE(cstate->replay_owner); | ||
4495 | release_lockowner(lo); | ||
4496 | } | ||
4497 | |||
4498 | out: | 4577 | out: |
4499 | nfsd4_bump_seqid(cstate, status); | 4578 | nfsd4_bump_seqid(cstate, status); |
4500 | if (!cstate->replay_owner) | 4579 | if (!cstate->replay_owner) |