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 | |
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
...
-rw-r--r-- | fs/nfsd/Kconfig | 16 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 44 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 225 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 169 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 20 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 28 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 7 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 4 | ||||
-rw-r--r-- | include/linux/sunrpc/cache.h | 49 | ||||
-rw-r--r-- | include/linux/sunrpc/gss_api.h | 2 | ||||
-rw-r--r-- | include/linux/sunrpc/svcauth.h | 11 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_mech_switch.c | 5 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 10 | ||||
-rw-r--r-- | net/sunrpc/cache.c | 83 | ||||
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 6 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 9 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 1 | ||||
-rw-r--r-- | security/capability.c | 2 |
20 files changed, 512 insertions, 182 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 430b6872806f..dc8f1ef665ce 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig | |||
@@ -81,6 +81,22 @@ config NFSD_V4 | |||
81 | 81 | ||
82 | If unsure, say N. | 82 | If unsure, say N. |
83 | 83 | ||
84 | config NFSD_V4_SECURITY_LABEL | ||
85 | bool "Provide Security Label support for NFSv4 server" | ||
86 | depends on NFSD_V4 && SECURITY | ||
87 | help | ||
88 | |||
89 | Say Y here if you want enable fine-grained security label attribute | ||
90 | support for NFS version 4. Security labels allow security modules like | ||
91 | SELinux and Smack to label files to facilitate enforcement of their policies. | ||
92 | Without this an NFSv4 mount will have the same label on each file. | ||
93 | |||
94 | If you do not wish to enable fine-grained security labels SELinux or | ||
95 | Smack policies on NFSv4 files, say N. | ||
96 | |||
97 | WARNING: there is still a chance of backwards-incompatible protocol changes. | ||
98 | For now we recommend "Y" only for developers and testers." | ||
99 | |||
84 | config NFSD_FAULT_INJECTION | 100 | config NFSD_FAULT_INJECTION |
85 | bool "NFS server manual fault injection" | 101 | bool "NFS server manual fault injection" |
86 | depends on NFSD_V4 && DEBUG_KERNEL | 102 | depends on NFSD_V4 && DEBUG_KERNEL |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 27d74a294515..a7cee864e7b2 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -42,6 +42,36 @@ | |||
42 | #include "current_stateid.h" | 42 | #include "current_stateid.h" |
43 | #include "netns.h" | 43 | #include "netns.h" |
44 | 44 | ||
45 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
46 | #include <linux/security.h> | ||
47 | |||
48 | static inline void | ||
49 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | ||
50 | { | ||
51 | struct inode *inode = resfh->fh_dentry->d_inode; | ||
52 | int status; | ||
53 | |||
54 | mutex_lock(&inode->i_mutex); | ||
55 | status = security_inode_setsecctx(resfh->fh_dentry, | ||
56 | label->data, label->len); | ||
57 | mutex_unlock(&inode->i_mutex); | ||
58 | |||
59 | if (status) | ||
60 | /* | ||
61 | * XXX: We should really fail the whole open, but we may | ||
62 | * already have created a new file, so it may be too | ||
63 | * late. For now this seems the least of evils: | ||
64 | */ | ||
65 | bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
66 | |||
67 | return; | ||
68 | } | ||
69 | #else | ||
70 | static inline void | ||
71 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | ||
72 | { } | ||
73 | #endif | ||
74 | |||
45 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 75 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
46 | 76 | ||
47 | static u32 nfsd_attrmask[] = { | 77 | static u32 nfsd_attrmask[] = { |
@@ -239,6 +269,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru | |||
239 | (u32 *)open->op_verf.data, | 269 | (u32 *)open->op_verf.data, |
240 | &open->op_truncate, &open->op_created); | 270 | &open->op_truncate, &open->op_created); |
241 | 271 | ||
272 | if (!status && open->op_label.len) | ||
273 | nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval); | ||
274 | |||
242 | /* | 275 | /* |
243 | * Following rfc 3530 14.2.16, use the returned bitmask | 276 | * Following rfc 3530 14.2.16, use the returned bitmask |
244 | * to indicate which attributes we used to store the | 277 | * to indicate which attributes we used to store the |
@@ -263,7 +296,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru | |||
263 | 296 | ||
264 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); | 297 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); |
265 | accmode = NFSD_MAY_NOP; | 298 | accmode = NFSD_MAY_NOP; |
266 | if (open->op_created) | 299 | if (open->op_created || |
300 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
267 | accmode |= NFSD_MAY_OWNER_OVERRIDE; | 301 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
268 | status = do_open_permission(rqstp, resfh, open, accmode); | 302 | status = do_open_permission(rqstp, resfh, open, accmode); |
269 | set_change_info(&open->op_cinfo, current_fh); | 303 | set_change_info(&open->op_cinfo, current_fh); |
@@ -637,6 +671,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
637 | if (status) | 671 | if (status) |
638 | goto out; | 672 | goto out; |
639 | 673 | ||
674 | if (create->cr_label.len) | ||
675 | nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); | ||
676 | |||
640 | if (create->cr_acl != NULL) | 677 | if (create->cr_acl != NULL) |
641 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, | 678 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, |
642 | create->cr_bmval); | 679 | create->cr_bmval); |
@@ -916,6 +953,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
916 | setattr->sa_acl); | 953 | setattr->sa_acl); |
917 | if (status) | 954 | if (status) |
918 | goto out; | 955 | goto out; |
956 | if (setattr->sa_label.len) | ||
957 | status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, | ||
958 | &setattr->sa_label); | ||
959 | if (status) | ||
960 | goto out; | ||
919 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, | 961 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
920 | 0, (time_t)0); | 962 | 0, (time_t)0); |
921 | out: | 963 | out: |
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) |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6cd86e0fe450..0c0f3ea90de5 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -55,6 +55,11 @@ | |||
55 | #include "cache.h" | 55 | #include "cache.h" |
56 | #include "netns.h" | 56 | #include "netns.h" |
57 | 57 | ||
58 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
59 | #include <linux/security.h> | ||
60 | #endif | ||
61 | |||
62 | |||
58 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 63 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
59 | 64 | ||
60 | /* | 65 | /* |
@@ -134,6 +139,19 @@ xdr_error: \ | |||
134 | } \ | 139 | } \ |
135 | } while (0) | 140 | } while (0) |
136 | 141 | ||
142 | static void next_decode_page(struct nfsd4_compoundargs *argp) | ||
143 | { | ||
144 | argp->pagelist++; | ||
145 | argp->p = page_address(argp->pagelist[0]); | ||
146 | if (argp->pagelen < PAGE_SIZE) { | ||
147 | argp->end = argp->p + (argp->pagelen>>2); | ||
148 | argp->pagelen = 0; | ||
149 | } else { | ||
150 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
151 | argp->pagelen -= PAGE_SIZE; | ||
152 | } | ||
153 | } | ||
154 | |||
137 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | 155 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) |
138 | { | 156 | { |
139 | /* We want more bytes than seem to be available. | 157 | /* We want more bytes than seem to be available. |
@@ -161,16 +179,7 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | |||
161 | * guarantee p points to at least nbytes bytes. | 179 | * guarantee p points to at least nbytes bytes. |
162 | */ | 180 | */ |
163 | memcpy(p, argp->p, avail); | 181 | memcpy(p, argp->p, avail); |
164 | /* step to next page */ | 182 | next_decode_page(argp); |
165 | argp->p = page_address(argp->pagelist[0]); | ||
166 | argp->pagelist++; | ||
167 | if (argp->pagelen < PAGE_SIZE) { | ||
168 | argp->end = argp->p + (argp->pagelen>>2); | ||
169 | argp->pagelen = 0; | ||
170 | } else { | ||
171 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
172 | argp->pagelen -= PAGE_SIZE; | ||
173 | } | ||
174 | memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); | 183 | memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); |
175 | argp->p += XDR_QUADLEN(nbytes - avail); | 184 | argp->p += XDR_QUADLEN(nbytes - avail); |
176 | return p; | 185 | return p; |
@@ -242,7 +251,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
242 | 251 | ||
243 | static __be32 | 252 | static __be32 |
244 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | 253 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
245 | struct iattr *iattr, struct nfs4_acl **acl) | 254 | struct iattr *iattr, struct nfs4_acl **acl, |
255 | struct xdr_netobj *label) | ||
246 | { | 256 | { |
247 | int expected_len, len = 0; | 257 | int expected_len, len = 0; |
248 | u32 dummy32; | 258 | u32 dummy32; |
@@ -380,6 +390,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
380 | goto xdr_error; | 390 | goto xdr_error; |
381 | } | 391 | } |
382 | } | 392 | } |
393 | |||
394 | label->len = 0; | ||
395 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
396 | if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { | ||
397 | READ_BUF(4); | ||
398 | len += 4; | ||
399 | READ32(dummy32); /* lfs: we don't use it */ | ||
400 | READ_BUF(4); | ||
401 | len += 4; | ||
402 | READ32(dummy32); /* pi: we don't use it either */ | ||
403 | READ_BUF(4); | ||
404 | len += 4; | ||
405 | READ32(dummy32); | ||
406 | READ_BUF(dummy32); | ||
407 | if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN) | ||
408 | return nfserr_badlabel; | ||
409 | len += (XDR_QUADLEN(dummy32) << 2); | ||
410 | READMEM(buf, dummy32); | ||
411 | label->data = kzalloc(dummy32 + 1, GFP_KERNEL); | ||
412 | if (!label->data) | ||
413 | return nfserr_jukebox; | ||
414 | defer_free(argp, kfree, label->data); | ||
415 | memcpy(label->data, buf, dummy32); | ||
416 | } | ||
417 | #endif | ||
418 | |||
383 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 | 419 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
384 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 | 420 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
385 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | 421 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) |
@@ -428,7 +464,11 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ | |||
428 | /* callback_sec_params4 */ | 464 | /* callback_sec_params4 */ |
429 | READ_BUF(4); | 465 | READ_BUF(4); |
430 | READ32(nr_secflavs); | 466 | READ32(nr_secflavs); |
431 | cbs->flavor = (u32)(-1); | 467 | if (nr_secflavs) |
468 | cbs->flavor = (u32)(-1); | ||
469 | else | ||
470 | /* Is this legal? Be generous, take it to mean AUTH_NONE: */ | ||
471 | cbs->flavor = 0; | ||
432 | for (i = 0; i < nr_secflavs; ++i) { | 472 | for (i = 0; i < nr_secflavs; ++i) { |
433 | READ_BUF(4); | 473 | READ_BUF(4); |
434 | READ32(dummy); | 474 | READ32(dummy); |
@@ -576,7 +616,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
576 | return status; | 616 | return status; |
577 | 617 | ||
578 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, | 618 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
579 | &create->cr_acl); | 619 | &create->cr_acl, &create->cr_label); |
580 | if (status) | 620 | if (status) |
581 | goto out; | 621 | goto out; |
582 | 622 | ||
@@ -827,7 +867,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
827 | case NFS4_CREATE_UNCHECKED: | 867 | case NFS4_CREATE_UNCHECKED: |
828 | case NFS4_CREATE_GUARDED: | 868 | case NFS4_CREATE_GUARDED: |
829 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 869 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
830 | &open->op_iattr, &open->op_acl); | 870 | &open->op_iattr, &open->op_acl, &open->op_label); |
831 | if (status) | 871 | if (status) |
832 | goto out; | 872 | goto out; |
833 | break; | 873 | break; |
@@ -841,7 +881,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
841 | READ_BUF(NFS4_VERIFIER_SIZE); | 881 | READ_BUF(NFS4_VERIFIER_SIZE); |
842 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); | 882 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); |
843 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 883 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
844 | &open->op_iattr, &open->op_acl); | 884 | &open->op_iattr, &open->op_acl, &open->op_label); |
845 | if (status) | 885 | if (status) |
846 | goto out; | 886 | goto out; |
847 | break; | 887 | break; |
@@ -1063,7 +1103,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
1063 | if (status) | 1103 | if (status) |
1064 | return status; | 1104 | return status; |
1065 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, | 1105 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
1066 | &setattr->sa_acl); | 1106 | &setattr->sa_acl, &setattr->sa_label); |
1067 | } | 1107 | } |
1068 | 1108 | ||
1069 | static __be32 | 1109 | static __be32 |
@@ -1567,6 +1607,7 @@ struct nfsd4_minorversion_ops { | |||
1567 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { | 1607 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { |
1568 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, | 1608 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, |
1569 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | 1609 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, |
1610 | [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | ||
1570 | }; | 1611 | }; |
1571 | 1612 | ||
1572 | static __be32 | 1613 | static __be32 |
@@ -1953,6 +1994,36 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace, | |||
1953 | FATTR4_WORD0_RDATTR_ERROR) | 1994 | FATTR4_WORD0_RDATTR_ERROR) |
1954 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID | 1995 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID |
1955 | 1996 | ||
1997 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
1998 | static inline __be32 | ||
1999 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
2000 | { | ||
2001 | __be32 *p = *pp; | ||
2002 | |||
2003 | if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) | ||
2004 | return nfserr_resource; | ||
2005 | |||
2006 | /* | ||
2007 | * For now we use a 0 here to indicate the null translation; in | ||
2008 | * the future we may place a call to translation code here. | ||
2009 | */ | ||
2010 | if ((*buflen -= 8) < 0) | ||
2011 | return nfserr_resource; | ||
2012 | |||
2013 | WRITE32(0); /* lfs */ | ||
2014 | WRITE32(0); /* pi */ | ||
2015 | p = xdr_encode_opaque(p, context, len); | ||
2016 | *buflen -= (XDR_QUADLEN(len) << 2) + 4; | ||
2017 | |||
2018 | *pp = p; | ||
2019 | return 0; | ||
2020 | } | ||
2021 | #else | ||
2022 | static inline __be32 | ||
2023 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
2024 | { return 0; } | ||
2025 | #endif | ||
2026 | |||
1956 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | 2027 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) |
1957 | { | 2028 | { |
1958 | /* As per referral draft: */ | 2029 | /* As per referral draft: */ |
@@ -2012,6 +2083,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2012 | int err; | 2083 | int err; |
2013 | int aclsupport = 0; | 2084 | int aclsupport = 0; |
2014 | struct nfs4_acl *acl = NULL; | 2085 | struct nfs4_acl *acl = NULL; |
2086 | void *context = NULL; | ||
2087 | int contextlen; | ||
2088 | bool contextsupport = false; | ||
2015 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2089 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
2016 | u32 minorversion = resp->cstate.minorversion; | 2090 | u32 minorversion = resp->cstate.minorversion; |
2017 | struct path path = { | 2091 | struct path path = { |
@@ -2065,6 +2139,21 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2065 | } | 2139 | } |
2066 | } | 2140 | } |
2067 | 2141 | ||
2142 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2143 | if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || | ||
2144 | bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { | ||
2145 | err = security_inode_getsecctx(dentry->d_inode, | ||
2146 | &context, &contextlen); | ||
2147 | contextsupport = (err == 0); | ||
2148 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2149 | if (err == -EOPNOTSUPP) | ||
2150 | bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2151 | else if (err) | ||
2152 | goto out_nfserr; | ||
2153 | } | ||
2154 | } | ||
2155 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2156 | |||
2068 | if (bmval2) { | 2157 | if (bmval2) { |
2069 | if ((buflen -= 16) < 0) | 2158 | if ((buflen -= 16) < 0) |
2070 | goto out_resource; | 2159 | goto out_resource; |
@@ -2093,6 +2182,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2093 | 2182 | ||
2094 | if (!aclsupport) | 2183 | if (!aclsupport) |
2095 | word0 &= ~FATTR4_WORD0_ACL; | 2184 | word0 &= ~FATTR4_WORD0_ACL; |
2185 | if (!contextsupport) | ||
2186 | word2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2096 | if (!word2) { | 2187 | if (!word2) { |
2097 | if ((buflen -= 12) < 0) | 2188 | if ((buflen -= 12) < 0) |
2098 | goto out_resource; | 2189 | goto out_resource; |
@@ -2400,6 +2491,12 @@ out_acl: | |||
2400 | get_parent_attributes(exp, &stat); | 2491 | get_parent_attributes(exp, &stat); |
2401 | WRITE64(stat.ino); | 2492 | WRITE64(stat.ino); |
2402 | } | 2493 | } |
2494 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2495 | status = nfsd4_encode_security_label(rqstp, context, | ||
2496 | contextlen, &p, &buflen); | ||
2497 | if (status) | ||
2498 | goto out; | ||
2499 | } | ||
2403 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2500 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
2404 | WRITE32(3); | 2501 | WRITE32(3); |
2405 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); | 2502 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); |
@@ -2412,6 +2509,10 @@ out_acl: | |||
2412 | status = nfs_ok; | 2509 | status = nfs_ok; |
2413 | 2510 | ||
2414 | out: | 2511 | out: |
2512 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2513 | if (context) | ||
2514 | security_release_secctx(context, contextlen); | ||
2515 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2415 | kfree(acl); | 2516 | kfree(acl); |
2416 | if (fhp == &tempfh) | 2517 | if (fhp == &tempfh) |
2417 | fh_put(&tempfh); | 2518 | fh_put(&tempfh); |
@@ -3176,16 +3277,18 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3176 | { | 3277 | { |
3177 | __be32 *p; | 3278 | __be32 *p; |
3178 | 3279 | ||
3179 | RESERVE_SPACE(12); | 3280 | RESERVE_SPACE(16); |
3180 | if (nfserr) { | 3281 | if (nfserr) { |
3181 | WRITE32(2); | 3282 | WRITE32(3); |
3283 | WRITE32(0); | ||
3182 | WRITE32(0); | 3284 | WRITE32(0); |
3183 | WRITE32(0); | 3285 | WRITE32(0); |
3184 | } | 3286 | } |
3185 | else { | 3287 | else { |
3186 | WRITE32(2); | 3288 | WRITE32(3); |
3187 | WRITE32(setattr->sa_bmval[0]); | 3289 | WRITE32(setattr->sa_bmval[0]); |
3188 | WRITE32(setattr->sa_bmval[1]); | 3290 | WRITE32(setattr->sa_bmval[1]); |
3291 | WRITE32(setattr->sa_bmval[2]); | ||
3189 | } | 3292 | } |
3190 | ADJUST_ARGS(); | 3293 | ADJUST_ARGS(); |
3191 | return nfserr; | 3294 | return nfserr; |
@@ -3226,6 +3329,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3226 | return nfserr; | 3329 | return nfserr; |
3227 | } | 3330 | } |
3228 | 3331 | ||
3332 | static const u32 nfs4_minimal_spo_must_enforce[2] = { | ||
3333 | [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) | | ||
3334 | 1 << (OP_EXCHANGE_ID - 32) | | ||
3335 | 1 << (OP_CREATE_SESSION - 32) | | ||
3336 | 1 << (OP_DESTROY_SESSION - 32) | | ||
3337 | 1 << (OP_DESTROY_CLIENTID - 32) | ||
3338 | }; | ||
3339 | |||
3229 | static __be32 | 3340 | static __be32 |
3230 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | 3341 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3231 | struct nfsd4_exchange_id *exid) | 3342 | struct nfsd4_exchange_id *exid) |
@@ -3264,6 +3375,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
3264 | /* state_protect4_r. Currently only support SP4_NONE */ | 3375 | /* state_protect4_r. Currently only support SP4_NONE */ |
3265 | BUG_ON(exid->spa_how != SP4_NONE); | 3376 | BUG_ON(exid->spa_how != SP4_NONE); |
3266 | WRITE32(exid->spa_how); | 3377 | WRITE32(exid->spa_how); |
3378 | switch (exid->spa_how) { | ||
3379 | case SP4_NONE: | ||
3380 | break; | ||
3381 | case SP4_MACH_CRED: | ||
3382 | /* spo_must_enforce bitmap: */ | ||
3383 | WRITE32(2); | ||
3384 | WRITE32(nfs4_minimal_spo_must_enforce[0]); | ||
3385 | WRITE32(nfs4_minimal_spo_must_enforce[1]); | ||
3386 | /* empty spo_must_allow bitmap: */ | ||
3387 | WRITE32(0); | ||
3388 | break; | ||
3389 | default: | ||
3390 | WARN_ON_ONCE(1); | ||
3391 | } | ||
3267 | 3392 | ||
3268 | /* The server_owner struct */ | 3393 | /* The server_owner struct */ |
3269 | WRITE64(minor_id); /* Minor id */ | 3394 | WRITE64(minor_id); /* Minor id */ |
@@ -3635,13 +3760,17 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3635 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; | 3760 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; |
3636 | BUG_ON(iov->iov_len > PAGE_SIZE); | 3761 | BUG_ON(iov->iov_len > PAGE_SIZE); |
3637 | if (nfsd4_has_session(cs)) { | 3762 | if (nfsd4_has_session(cs)) { |
3763 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3764 | struct nfs4_client *clp = cs->session->se_client; | ||
3638 | if (cs->status != nfserr_replay_cache) { | 3765 | if (cs->status != nfserr_replay_cache) { |
3639 | nfsd4_store_cache_entry(resp); | 3766 | nfsd4_store_cache_entry(resp); |
3640 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; | 3767 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; |
3641 | } | 3768 | } |
3642 | /* Renew the clientid on success and on replay */ | 3769 | /* Renew the clientid on success and on replay */ |
3643 | put_client_renew(cs->session->se_client); | 3770 | spin_lock(&nn->client_lock); |
3644 | nfsd4_put_session(cs->session); | 3771 | nfsd4_put_session(cs->session); |
3772 | spin_unlock(&nn->client_lock); | ||
3773 | put_client_renew(clp); | ||
3645 | } | 3774 | } |
3646 | return 1; | 3775 | return 1; |
3647 | } | 3776 | } |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index c0d93170585d..2bbd94e51efc 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -24,7 +24,7 @@ | |||
24 | /* | 24 | /* |
25 | * nfsd version | 25 | * nfsd version |
26 | */ | 26 | */ |
27 | #define NFSD_SUPPORTED_MINOR_VERSION 1 | 27 | #define NFSD_SUPPORTED_MINOR_VERSION 2 |
28 | /* | 28 | /* |
29 | * Maximum blocksizes supported by daemon under various circumstances. | 29 | * Maximum blocksizes supported by daemon under various circumstances. |
30 | */ | 30 | */ |
@@ -328,6 +328,13 @@ void nfsd_lockd_shutdown(void); | |||
328 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ | 328 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ |
329 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) | 329 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) |
330 | 330 | ||
331 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
332 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ | ||
333 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL) | ||
334 | #else | ||
335 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0 | ||
336 | #endif | ||
337 | |||
331 | static inline u32 nfsd_suppattrs0(u32 minorversion) | 338 | static inline u32 nfsd_suppattrs0(u32 minorversion) |
332 | { | 339 | { |
333 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 | 340 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 |
@@ -342,8 +349,11 @@ static inline u32 nfsd_suppattrs1(u32 minorversion) | |||
342 | 349 | ||
343 | static inline u32 nfsd_suppattrs2(u32 minorversion) | 350 | static inline u32 nfsd_suppattrs2(u32 minorversion) |
344 | { | 351 | { |
345 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2 | 352 | switch (minorversion) { |
346 | : NFSD4_SUPPORTED_ATTRS_WORD2; | 353 | default: return NFSD4_2_SUPPORTED_ATTRS_WORD2; |
354 | case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2; | ||
355 | case 0: return NFSD4_SUPPORTED_ATTRS_WORD2; | ||
356 | } | ||
347 | } | 357 | } |
348 | 358 | ||
349 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ | 359 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ |
@@ -356,7 +366,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) | |||
356 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ | 366 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ |
357 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ | 367 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ |
358 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 368 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
369 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
370 | #define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL | ||
371 | #else | ||
359 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 | 372 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 |
373 | #endif | ||
360 | 374 | ||
361 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ | 375 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ |
362 | NFSD_WRITEABLE_ATTRS_WORD0 | 376 | NFSD_WRITEABLE_ATTRS_WORD0 |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 262df5ccbf59..6b9f48ca4c25 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -116,7 +116,7 @@ struct svc_program nfsd_program = { | |||
116 | 116 | ||
117 | }; | 117 | }; |
118 | 118 | ||
119 | u32 nfsd_supported_minorversion; | 119 | u32 nfsd_supported_minorversion = 1; |
120 | 120 | ||
121 | int nfsd_vers(int vers, enum vers_op change) | 121 | int nfsd_vers(int vers, enum vers_op change) |
122 | { | 122 | { |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 274e2a114e05..424d8f5f2317 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -246,6 +246,7 @@ struct nfs4_client { | |||
246 | nfs4_verifier cl_verifier; /* generated by client */ | 246 | nfs4_verifier cl_verifier; /* generated by client */ |
247 | time_t cl_time; /* time of last lease renewal */ | 247 | time_t cl_time; /* time of last lease renewal */ |
248 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 248 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
249 | bool cl_mach_cred; /* SP4_MACH_CRED in force */ | ||
249 | struct svc_cred cl_cred; /* setclientid principal */ | 250 | struct svc_cred cl_cred; /* setclientid principal */ |
250 | clientid_t cl_clientid; /* generated by server */ | 251 | clientid_t cl_clientid; /* generated by server */ |
251 | nfs4_verifier cl_confirm; /* generated by server */ | 252 | nfs4_verifier cl_confirm; /* generated by server */ |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a6bc8a7423db..8ff6a0019b0b 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <linux/exportfs.h> | 29 | #include <linux/exportfs.h> |
30 | #include <linux/writeback.h> | 30 | #include <linux/writeback.h> |
31 | #include <linux/security.h> | ||
31 | 32 | ||
32 | #ifdef CONFIG_NFSD_V3 | 33 | #ifdef CONFIG_NFSD_V3 |
33 | #include "xdr3.h" | 34 | #include "xdr3.h" |
@@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry) | |||
621 | return 0; | 622 | return 0; |
622 | return 1; | 623 | return 1; |
623 | } | 624 | } |
625 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
626 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
627 | struct xdr_netobj *label) | ||
628 | { | ||
629 | __be32 error; | ||
630 | int host_error; | ||
631 | struct dentry *dentry; | ||
632 | |||
633 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); | ||
634 | if (error) | ||
635 | return error; | ||
636 | |||
637 | dentry = fhp->fh_dentry; | ||
638 | |||
639 | mutex_lock(&dentry->d_inode->i_mutex); | ||
640 | host_error = security_inode_setsecctx(dentry, label->data, label->len); | ||
641 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
642 | return nfserrno(host_error); | ||
643 | } | ||
644 | #else | ||
645 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
646 | struct xdr_netobj *label) | ||
647 | { | ||
648 | return nfserr_notsupp; | ||
649 | } | ||
650 | #endif | ||
651 | |||
624 | #endif /* defined(CONFIG_NFSD_V4) */ | 652 | #endif /* defined(CONFIG_NFSD_V4) */ |
625 | 653 | ||
626 | #ifdef CONFIG_NFSD_V3 | 654 | #ifdef CONFIG_NFSD_V3 |
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 5b5894159f22..a4be2e389670 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -39,7 +39,6 @@ | |||
39 | typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); | 39 | typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); |
40 | 40 | ||
41 | /* nfsd/vfs.c */ | 41 | /* nfsd/vfs.c */ |
42 | int fh_lock_parent(struct svc_fh *, struct dentry *); | ||
43 | int nfsd_racache_init(int); | 42 | int nfsd_racache_init(int); |
44 | void nfsd_racache_shutdown(void); | 43 | void nfsd_racache_shutdown(void); |
45 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | 44 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, |
@@ -56,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *); | |||
56 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, | 55 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, |
57 | struct nfs4_acl *); | 56 | struct nfs4_acl *); |
58 | int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); | 57 | int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); |
58 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, | ||
59 | struct xdr_netobj *); | ||
59 | #endif /* CONFIG_NFSD_V4 */ | 60 | #endif /* CONFIG_NFSD_V4 */ |
60 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, | 61 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, |
61 | char *name, int len, struct iattr *attrs, | 62 | char *name, int len, struct iattr *attrs, |
@@ -92,17 +93,13 @@ __be32 nfsd_remove(struct svc_rqst *, | |||
92 | struct svc_fh *, char *, int); | 93 | struct svc_fh *, char *, int); |
93 | __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, | 94 | __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, |
94 | char *name, int len); | 95 | char *name, int len); |
95 | int nfsd_truncate(struct svc_rqst *, struct svc_fh *, | ||
96 | unsigned long size); | ||
97 | __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, | 96 | __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, |
98 | loff_t *, struct readdir_cd *, filldir_t); | 97 | loff_t *, struct readdir_cd *, filldir_t); |
99 | __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, | 98 | __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, |
100 | struct kstatfs *, int access); | 99 | struct kstatfs *, int access); |
101 | 100 | ||
102 | int nfsd_notify_change(struct inode *, struct iattr *); | ||
103 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, | 101 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, |
104 | struct dentry *, int); | 102 | struct dentry *, int); |
105 | int nfsd_sync_dir(struct dentry *dp); | ||
106 | 103 | ||
107 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 104 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
108 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); | 105 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 3b271d2092b6..b3ed6446ed8e 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "state.h" | 40 | #include "state.h" |
41 | #include "nfsd.h" | 41 | #include "nfsd.h" |
42 | 42 | ||
43 | #define NFSD4_MAX_SEC_LABEL_LEN 2048 | ||
43 | #define NFSD4_MAX_TAGLEN 128 | 44 | #define NFSD4_MAX_TAGLEN 128 |
44 | #define XDR_LEN(n) (((n) + 3) & ~3) | 45 | #define XDR_LEN(n) (((n) + 3) & ~3) |
45 | 46 | ||
@@ -118,6 +119,7 @@ struct nfsd4_create { | |||
118 | struct iattr cr_iattr; /* request */ | 119 | struct iattr cr_iattr; /* request */ |
119 | struct nfsd4_change_info cr_cinfo; /* response */ | 120 | struct nfsd4_change_info cr_cinfo; /* response */ |
120 | struct nfs4_acl *cr_acl; | 121 | struct nfs4_acl *cr_acl; |
122 | struct xdr_netobj cr_label; | ||
121 | }; | 123 | }; |
122 | #define cr_linklen u.link.namelen | 124 | #define cr_linklen u.link.namelen |
123 | #define cr_linkname u.link.name | 125 | #define cr_linkname u.link.name |
@@ -246,6 +248,7 @@ struct nfsd4_open { | |||
246 | struct nfs4_file *op_file; /* used during processing */ | 248 | struct nfs4_file *op_file; /* used during processing */ |
247 | struct nfs4_ol_stateid *op_stp; /* used during processing */ | 249 | struct nfs4_ol_stateid *op_stp; /* used during processing */ |
248 | struct nfs4_acl *op_acl; | 250 | struct nfs4_acl *op_acl; |
251 | struct xdr_netobj op_label; | ||
249 | }; | 252 | }; |
250 | #define op_iattr iattr | 253 | #define op_iattr iattr |
251 | 254 | ||
@@ -330,6 +333,7 @@ struct nfsd4_setattr { | |||
330 | u32 sa_bmval[3]; /* request */ | 333 | u32 sa_bmval[3]; /* request */ |
331 | struct iattr sa_iattr; /* request */ | 334 | struct iattr sa_iattr; /* request */ |
332 | struct nfs4_acl *sa_acl; | 335 | struct nfs4_acl *sa_acl; |
336 | struct xdr_netobj sa_label; | ||
333 | }; | 337 | }; |
334 | 338 | ||
335 | struct nfsd4_setclientid { | 339 | struct nfsd4_setclientid { |
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 303399b1ba59..6ce690de447f 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h | |||
@@ -57,6 +57,7 @@ struct cache_head { | |||
57 | #define CACHE_VALID 0 /* Entry contains valid data */ | 57 | #define CACHE_VALID 0 /* Entry contains valid data */ |
58 | #define CACHE_NEGATIVE 1 /* Negative entry - there is no match for the key */ | 58 | #define CACHE_NEGATIVE 1 /* Negative entry - there is no match for the key */ |
59 | #define CACHE_PENDING 2 /* An upcall has been sent but no reply received yet*/ | 59 | #define CACHE_PENDING 2 /* An upcall has been sent but no reply received yet*/ |
60 | #define CACHE_CLEANED 3 /* Entry has been cleaned from cache */ | ||
60 | 61 | ||
61 | #define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */ | 62 | #define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */ |
62 | 63 | ||
@@ -148,6 +149,24 @@ struct cache_deferred_req { | |||
148 | int too_many); | 149 | int too_many); |
149 | }; | 150 | }; |
150 | 151 | ||
152 | /* | ||
153 | * timestamps kept in the cache are expressed in seconds | ||
154 | * since boot. This is the best for measuring differences in | ||
155 | * real time. | ||
156 | */ | ||
157 | static inline time_t seconds_since_boot(void) | ||
158 | { | ||
159 | struct timespec boot; | ||
160 | getboottime(&boot); | ||
161 | return get_seconds() - boot.tv_sec; | ||
162 | } | ||
163 | |||
164 | static inline time_t convert_to_wallclock(time_t sinceboot) | ||
165 | { | ||
166 | struct timespec boot; | ||
167 | getboottime(&boot); | ||
168 | return boot.tv_sec + sinceboot; | ||
169 | } | ||
151 | 170 | ||
152 | extern const struct file_operations cache_file_operations_pipefs; | 171 | extern const struct file_operations cache_file_operations_pipefs; |
153 | extern const struct file_operations content_file_operations_pipefs; | 172 | extern const struct file_operations content_file_operations_pipefs; |
@@ -181,15 +200,10 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd) | |||
181 | kref_put(&h->ref, cd->cache_put); | 200 | kref_put(&h->ref, cd->cache_put); |
182 | } | 201 | } |
183 | 202 | ||
184 | static inline int cache_valid(struct cache_head *h) | 203 | static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) |
185 | { | 204 | { |
186 | /* If an item has been unhashed pending removal when | 205 | return (h->expiry_time < seconds_since_boot()) || |
187 | * the refcount drops to 0, the expiry_time will be | 206 | (detail->flush_time > h->last_refresh); |
188 | * set to 0. We don't want to consider such items | ||
189 | * valid in this context even though CACHE_VALID is | ||
190 | * set. | ||
191 | */ | ||
192 | return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags)); | ||
193 | } | 207 | } |
194 | 208 | ||
195 | extern int cache_check(struct cache_detail *detail, | 209 | extern int cache_check(struct cache_detail *detail, |
@@ -250,25 +264,6 @@ static inline int get_uint(char **bpp, unsigned int *anint) | |||
250 | return 0; | 264 | return 0; |
251 | } | 265 | } |
252 | 266 | ||
253 | /* | ||
254 | * timestamps kept in the cache are expressed in seconds | ||
255 | * since boot. This is the best for measuring differences in | ||
256 | * real time. | ||
257 | */ | ||
258 | static inline time_t seconds_since_boot(void) | ||
259 | { | ||
260 | struct timespec boot; | ||
261 | getboottime(&boot); | ||
262 | return get_seconds() - boot.tv_sec; | ||
263 | } | ||
264 | |||
265 | static inline time_t convert_to_wallclock(time_t sinceboot) | ||
266 | { | ||
267 | struct timespec boot; | ||
268 | getboottime(&boot); | ||
269 | return boot.tv_sec + sinceboot; | ||
270 | } | ||
271 | |||
272 | static inline time_t get_expiry(char **bpp) | 267 | static inline time_t get_expiry(char **bpp) |
273 | { | 268 | { |
274 | int rv; | 269 | int rv; |
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 161463e59624..1f911ccb2a75 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h | |||
@@ -151,6 +151,8 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); | |||
151 | /* Fill in an array with a list of supported pseudoflavors */ | 151 | /* Fill in an array with a list of supported pseudoflavors */ |
152 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); | 152 | int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); |
153 | 153 | ||
154 | struct gss_api_mech * gss_mech_get(struct gss_api_mech *); | ||
155 | |||
154 | /* For every successful gss_mech_get or gss_mech_get_by_* call there must be a | 156 | /* For every successful gss_mech_get or gss_mech_get_by_* call there must be a |
155 | * corresponding call to gss_mech_put. */ | 157 | * corresponding call to gss_mech_put. */ |
156 | void gss_mech_put(struct gss_api_mech *); | 158 | void gss_mech_put(struct gss_api_mech *); |
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h index ff374ab30839..8d71d6577459 100644 --- a/include/linux/sunrpc/svcauth.h +++ b/include/linux/sunrpc/svcauth.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/string.h> | 14 | #include <linux/string.h> |
15 | #include <linux/sunrpc/msg_prot.h> | 15 | #include <linux/sunrpc/msg_prot.h> |
16 | #include <linux/sunrpc/cache.h> | 16 | #include <linux/sunrpc/cache.h> |
17 | #include <linux/sunrpc/gss_api.h> | ||
17 | #include <linux/hash.h> | 18 | #include <linux/hash.h> |
18 | #include <linux/cred.h> | 19 | #include <linux/cred.h> |
19 | 20 | ||
@@ -23,13 +24,23 @@ struct svc_cred { | |||
23 | struct group_info *cr_group_info; | 24 | struct group_info *cr_group_info; |
24 | u32 cr_flavor; /* pseudoflavor */ | 25 | u32 cr_flavor; /* pseudoflavor */ |
25 | char *cr_principal; /* for gss */ | 26 | char *cr_principal; /* for gss */ |
27 | struct gss_api_mech *cr_gss_mech; | ||
26 | }; | 28 | }; |
27 | 29 | ||
30 | static inline void init_svc_cred(struct svc_cred *cred) | ||
31 | { | ||
32 | cred->cr_group_info = NULL; | ||
33 | cred->cr_principal = NULL; | ||
34 | cred->cr_gss_mech = NULL; | ||
35 | } | ||
36 | |||
28 | static inline void free_svc_cred(struct svc_cred *cred) | 37 | static inline void free_svc_cred(struct svc_cred *cred) |
29 | { | 38 | { |
30 | if (cred->cr_group_info) | 39 | if (cred->cr_group_info) |
31 | put_group_info(cred->cr_group_info); | 40 | put_group_info(cred->cr_group_info); |
32 | kfree(cred->cr_principal); | 41 | kfree(cred->cr_principal); |
42 | gss_mech_put(cred->cr_gss_mech); | ||
43 | init_svc_cred(cred); | ||
33 | } | 44 | } |
34 | 45 | ||
35 | struct svc_rqst; /* forward decl */ | 46 | struct svc_rqst; /* forward decl */ |
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index defa9d33925c..27ce26240932 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
@@ -139,11 +139,12 @@ void gss_mech_unregister(struct gss_api_mech *gm) | |||
139 | } | 139 | } |
140 | EXPORT_SYMBOL_GPL(gss_mech_unregister); | 140 | EXPORT_SYMBOL_GPL(gss_mech_unregister); |
141 | 141 | ||
142 | static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) | 142 | struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) |
143 | { | 143 | { |
144 | __module_get(gm->gm_owner); | 144 | __module_get(gm->gm_owner); |
145 | return gm; | 145 | return gm; |
146 | } | 146 | } |
147 | EXPORT_SYMBOL(gss_mech_get); | ||
147 | 148 | ||
148 | static struct gss_api_mech * | 149 | static struct gss_api_mech * |
149 | _gss_mech_get_by_name(const char *name) | 150 | _gss_mech_get_by_name(const char *name) |
@@ -360,6 +361,7 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | |||
360 | } | 361 | } |
361 | return 0; | 362 | return 0; |
362 | } | 363 | } |
364 | EXPORT_SYMBOL(gss_pseudoflavor_to_service); | ||
363 | 365 | ||
364 | char * | 366 | char * |
365 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | 367 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) |
@@ -379,6 +381,7 @@ gss_mech_put(struct gss_api_mech * gm) | |||
379 | if (gm) | 381 | if (gm) |
380 | module_put(gm->gm_owner); | 382 | module_put(gm->gm_owner); |
381 | } | 383 | } |
384 | EXPORT_SYMBOL(gss_mech_put); | ||
382 | 385 | ||
383 | /* The mech could probably be determined from the token instead, but it's just | 386 | /* The mech could probably be determined from the token instead, but it's just |
384 | * as easy for now to pass it in. */ | 387 | * as easy for now to pass it in. */ |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index b05ace4c5f12..d0347d148b34 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -377,8 +377,7 @@ rsc_init(struct cache_head *cnew, struct cache_head *ctmp) | |||
377 | new->handle.data = tmp->handle.data; | 377 | new->handle.data = tmp->handle.data; |
378 | tmp->handle.data = NULL; | 378 | tmp->handle.data = NULL; |
379 | new->mechctx = NULL; | 379 | new->mechctx = NULL; |
380 | new->cred.cr_group_info = NULL; | 380 | init_svc_cred(&new->cred); |
381 | new->cred.cr_principal = NULL; | ||
382 | } | 381 | } |
383 | 382 | ||
384 | static void | 383 | static void |
@@ -392,9 +391,7 @@ update_rsc(struct cache_head *cnew, struct cache_head *ctmp) | |||
392 | memset(&new->seqdata, 0, sizeof(new->seqdata)); | 391 | memset(&new->seqdata, 0, sizeof(new->seqdata)); |
393 | spin_lock_init(&new->seqdata.sd_lock); | 392 | spin_lock_init(&new->seqdata.sd_lock); |
394 | new->cred = tmp->cred; | 393 | new->cred = tmp->cred; |
395 | tmp->cred.cr_group_info = NULL; | 394 | init_svc_cred(&tmp->cred); |
396 | new->cred.cr_principal = tmp->cred.cr_principal; | ||
397 | tmp->cred.cr_principal = NULL; | ||
398 | } | 395 | } |
399 | 396 | ||
400 | static struct cache_head * | 397 | static struct cache_head * |
@@ -487,7 +484,7 @@ static int rsc_parse(struct cache_detail *cd, | |||
487 | len = qword_get(&mesg, buf, mlen); | 484 | len = qword_get(&mesg, buf, mlen); |
488 | if (len < 0) | 485 | if (len < 0) |
489 | goto out; | 486 | goto out; |
490 | gm = gss_mech_get_by_name(buf); | 487 | gm = rsci.cred.cr_gss_mech = gss_mech_get_by_name(buf); |
491 | status = -EOPNOTSUPP; | 488 | status = -EOPNOTSUPP; |
492 | if (!gm) | 489 | if (!gm) |
493 | goto out; | 490 | goto out; |
@@ -517,7 +514,6 @@ static int rsc_parse(struct cache_detail *cd, | |||
517 | rscp = rsc_update(cd, &rsci, rscp); | 514 | rscp = rsc_update(cd, &rsci, rscp); |
518 | status = 0; | 515 | status = 0; |
519 | out: | 516 | out: |
520 | gss_mech_put(gm); | ||
521 | rsc_free(&rsci); | 517 | rsc_free(&rsci); |
522 | if (rscp) | 518 | if (rscp) |
523 | cache_put(&rscp->h, cd); | 519 | cache_put(&rscp->h, cd); |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 80fe5c86efd1..49eb37010aa3 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -50,12 +50,6 @@ static void cache_init(struct cache_head *h) | |||
50 | h->last_refresh = now; | 50 | h->last_refresh = now; |
51 | } | 51 | } |
52 | 52 | ||
53 | static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) | ||
54 | { | ||
55 | return (h->expiry_time < seconds_since_boot()) || | ||
56 | (detail->flush_time > h->last_refresh); | ||
57 | } | ||
58 | |||
59 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, | 53 | struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, |
60 | struct cache_head *key, int hash) | 54 | struct cache_head *key, int hash) |
61 | { | 55 | { |
@@ -201,7 +195,7 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) | |||
201 | return sunrpc_cache_pipe_upcall(cd, h); | 195 | return sunrpc_cache_pipe_upcall(cd, h); |
202 | } | 196 | } |
203 | 197 | ||
204 | static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) | 198 | static inline int cache_is_valid(struct cache_head *h) |
205 | { | 199 | { |
206 | if (!test_bit(CACHE_VALID, &h->flags)) | 200 | if (!test_bit(CACHE_VALID, &h->flags)) |
207 | return -EAGAIN; | 201 | return -EAGAIN; |
@@ -227,16 +221,15 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h | |||
227 | int rv; | 221 | int rv; |
228 | 222 | ||
229 | write_lock(&detail->hash_lock); | 223 | write_lock(&detail->hash_lock); |
230 | rv = cache_is_valid(detail, h); | 224 | rv = cache_is_valid(h); |
231 | if (rv != -EAGAIN) { | 225 | if (rv == -EAGAIN) { |
232 | write_unlock(&detail->hash_lock); | 226 | set_bit(CACHE_NEGATIVE, &h->flags); |
233 | return rv; | 227 | cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); |
228 | rv = -ENOENT; | ||
234 | } | 229 | } |
235 | set_bit(CACHE_NEGATIVE, &h->flags); | ||
236 | cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); | ||
237 | write_unlock(&detail->hash_lock); | 230 | write_unlock(&detail->hash_lock); |
238 | cache_fresh_unlocked(h, detail); | 231 | cache_fresh_unlocked(h, detail); |
239 | return -ENOENT; | 232 | return rv; |
240 | } | 233 | } |
241 | 234 | ||
242 | /* | 235 | /* |
@@ -260,7 +253,7 @@ int cache_check(struct cache_detail *detail, | |||
260 | long refresh_age, age; | 253 | long refresh_age, age; |
261 | 254 | ||
262 | /* First decide return status as best we can */ | 255 | /* First decide return status as best we can */ |
263 | rv = cache_is_valid(detail, h); | 256 | rv = cache_is_valid(h); |
264 | 257 | ||
265 | /* now see if we want to start an upcall */ | 258 | /* now see if we want to start an upcall */ |
266 | refresh_age = (h->expiry_time - h->last_refresh); | 259 | refresh_age = (h->expiry_time - h->last_refresh); |
@@ -269,19 +262,17 @@ int cache_check(struct cache_detail *detail, | |||
269 | if (rqstp == NULL) { | 262 | if (rqstp == NULL) { |
270 | if (rv == -EAGAIN) | 263 | if (rv == -EAGAIN) |
271 | rv = -ENOENT; | 264 | rv = -ENOENT; |
272 | } else if (rv == -EAGAIN || age > refresh_age/2) { | 265 | } else if (rv == -EAGAIN || |
266 | (h->expiry_time != 0 && age > refresh_age/2)) { | ||
273 | dprintk("RPC: Want update, refage=%ld, age=%ld\n", | 267 | dprintk("RPC: Want update, refage=%ld, age=%ld\n", |
274 | refresh_age, age); | 268 | refresh_age, age); |
275 | if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { | 269 | if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { |
276 | switch (cache_make_upcall(detail, h)) { | 270 | switch (cache_make_upcall(detail, h)) { |
277 | case -EINVAL: | 271 | case -EINVAL: |
278 | clear_bit(CACHE_PENDING, &h->flags); | ||
279 | cache_revisit_request(h); | ||
280 | rv = try_to_negate_entry(detail, h); | 272 | rv = try_to_negate_entry(detail, h); |
281 | break; | 273 | break; |
282 | case -EAGAIN: | 274 | case -EAGAIN: |
283 | clear_bit(CACHE_PENDING, &h->flags); | 275 | cache_fresh_unlocked(h, detail); |
284 | cache_revisit_request(h); | ||
285 | break; | 276 | break; |
286 | } | 277 | } |
287 | } | 278 | } |
@@ -293,7 +284,7 @@ int cache_check(struct cache_detail *detail, | |||
293 | * Request was not deferred; handle it as best | 284 | * Request was not deferred; handle it as best |
294 | * we can ourselves: | 285 | * we can ourselves: |
295 | */ | 286 | */ |
296 | rv = cache_is_valid(detail, h); | 287 | rv = cache_is_valid(h); |
297 | if (rv == -EAGAIN) | 288 | if (rv == -EAGAIN) |
298 | rv = -ETIMEDOUT; | 289 | rv = -ETIMEDOUT; |
299 | } | 290 | } |
@@ -310,7 +301,7 @@ EXPORT_SYMBOL_GPL(cache_check); | |||
310 | * a current pointer into that list and into the table | 301 | * a current pointer into that list and into the table |
311 | * for that entry. | 302 | * for that entry. |
312 | * | 303 | * |
313 | * Each time clean_cache is called it finds the next non-empty entry | 304 | * Each time cache_clean is called it finds the next non-empty entry |
314 | * in the current table and walks the list in that entry | 305 | * in the current table and walks the list in that entry |
315 | * looking for entries that can be removed. | 306 | * looking for entries that can be removed. |
316 | * | 307 | * |
@@ -457,9 +448,8 @@ static int cache_clean(void) | |||
457 | current_index ++; | 448 | current_index ++; |
458 | spin_unlock(&cache_list_lock); | 449 | spin_unlock(&cache_list_lock); |
459 | if (ch) { | 450 | if (ch) { |
460 | if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) | 451 | set_bit(CACHE_CLEANED, &ch->flags); |
461 | cache_dequeue(current_detail, ch); | 452 | cache_fresh_unlocked(ch, d); |
462 | cache_revisit_request(ch); | ||
463 | cache_put(ch, d); | 453 | cache_put(ch, d); |
464 | } | 454 | } |
465 | } else | 455 | } else |
@@ -1036,23 +1026,32 @@ static int cache_release(struct inode *inode, struct file *filp, | |||
1036 | 1026 | ||
1037 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) | 1027 | static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) |
1038 | { | 1028 | { |
1039 | struct cache_queue *cq; | 1029 | struct cache_queue *cq, *tmp; |
1030 | struct cache_request *cr; | ||
1031 | struct list_head dequeued; | ||
1032 | |||
1033 | INIT_LIST_HEAD(&dequeued); | ||
1040 | spin_lock(&queue_lock); | 1034 | spin_lock(&queue_lock); |
1041 | list_for_each_entry(cq, &detail->queue, list) | 1035 | list_for_each_entry_safe(cq, tmp, &detail->queue, list) |
1042 | if (!cq->reader) { | 1036 | if (!cq->reader) { |
1043 | struct cache_request *cr = container_of(cq, struct cache_request, q); | 1037 | cr = container_of(cq, struct cache_request, q); |
1044 | if (cr->item != ch) | 1038 | if (cr->item != ch) |
1045 | continue; | 1039 | continue; |
1040 | if (test_bit(CACHE_PENDING, &ch->flags)) | ||
1041 | /* Lost a race and it is pending again */ | ||
1042 | break; | ||
1046 | if (cr->readers != 0) | 1043 | if (cr->readers != 0) |
1047 | continue; | 1044 | continue; |
1048 | list_del(&cr->q.list); | 1045 | list_move(&cr->q.list, &dequeued); |
1049 | spin_unlock(&queue_lock); | ||
1050 | cache_put(cr->item, detail); | ||
1051 | kfree(cr->buf); | ||
1052 | kfree(cr); | ||
1053 | return; | ||
1054 | } | 1046 | } |
1055 | spin_unlock(&queue_lock); | 1047 | spin_unlock(&queue_lock); |
1048 | while (!list_empty(&dequeued)) { | ||
1049 | cr = list_entry(dequeued.next, struct cache_request, q.list); | ||
1050 | list_del(&cr->q.list); | ||
1051 | cache_put(cr->item, detail); | ||
1052 | kfree(cr->buf); | ||
1053 | kfree(cr); | ||
1054 | } | ||
1056 | } | 1055 | } |
1057 | 1056 | ||
1058 | /* | 1057 | /* |
@@ -1166,6 +1165,7 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) | |||
1166 | 1165 | ||
1167 | char *buf; | 1166 | char *buf; |
1168 | struct cache_request *crq; | 1167 | struct cache_request *crq; |
1168 | int ret = 0; | ||
1169 | 1169 | ||
1170 | if (!detail->cache_request) | 1170 | if (!detail->cache_request) |
1171 | return -EINVAL; | 1171 | return -EINVAL; |
@@ -1174,6 +1174,9 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) | |||
1174 | warn_no_listener(detail); | 1174 | warn_no_listener(detail); |
1175 | return -EINVAL; | 1175 | return -EINVAL; |
1176 | } | 1176 | } |
1177 | if (test_bit(CACHE_CLEANED, &h->flags)) | ||
1178 | /* Too late to make an upcall */ | ||
1179 | return -EAGAIN; | ||
1177 | 1180 | ||
1178 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 1181 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
1179 | if (!buf) | 1182 | if (!buf) |
@@ -1191,10 +1194,18 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) | |||
1191 | crq->len = 0; | 1194 | crq->len = 0; |
1192 | crq->readers = 0; | 1195 | crq->readers = 0; |
1193 | spin_lock(&queue_lock); | 1196 | spin_lock(&queue_lock); |
1194 | list_add_tail(&crq->q.list, &detail->queue); | 1197 | if (test_bit(CACHE_PENDING, &h->flags)) |
1198 | list_add_tail(&crq->q.list, &detail->queue); | ||
1199 | else | ||
1200 | /* Lost a race, no longer PENDING, so don't enqueue */ | ||
1201 | ret = -EAGAIN; | ||
1195 | spin_unlock(&queue_lock); | 1202 | spin_unlock(&queue_lock); |
1196 | wake_up(&queue_wait); | 1203 | wake_up(&queue_wait); |
1197 | return 0; | 1204 | if (ret == -EAGAIN) { |
1205 | kfree(buf); | ||
1206 | kfree(crq); | ||
1207 | } | ||
1208 | return ret; | ||
1198 | } | 1209 | } |
1199 | EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); | 1210 | EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); |
1200 | 1211 | ||
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 06bdf5a1082c..621ca7b4a155 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -347,13 +347,13 @@ ip_map_cached_get(struct svc_xprt *xprt) | |||
347 | spin_lock(&xprt->xpt_lock); | 347 | spin_lock(&xprt->xpt_lock); |
348 | ipm = xprt->xpt_auth_cache; | 348 | ipm = xprt->xpt_auth_cache; |
349 | if (ipm != NULL) { | 349 | if (ipm != NULL) { |
350 | if (!cache_valid(&ipm->h)) { | 350 | sn = net_generic(xprt->xpt_net, sunrpc_net_id); |
351 | if (cache_is_expired(sn->ip_map_cache, &ipm->h)) { | ||
351 | /* | 352 | /* |
352 | * The entry has been invalidated since it was | 353 | * The entry has been invalidated since it was |
353 | * remembered, e.g. by a second mount from the | 354 | * remembered, e.g. by a second mount from the |
354 | * same IP address. | 355 | * same IP address. |
355 | */ | 356 | */ |
356 | sn = net_generic(xprt->xpt_net, sunrpc_net_id); | ||
357 | xprt->xpt_auth_cache = NULL; | 357 | xprt->xpt_auth_cache = NULL; |
358 | spin_unlock(&xprt->xpt_lock); | 358 | spin_unlock(&xprt->xpt_lock); |
359 | cache_put(&ipm->h, sn->ip_map_cache); | 359 | cache_put(&ipm->h, sn->ip_map_cache); |
@@ -493,8 +493,6 @@ static int unix_gid_parse(struct cache_detail *cd, | |||
493 | if (rv) | 493 | if (rv) |
494 | return -EINVAL; | 494 | return -EINVAL; |
495 | uid = make_kuid(&init_user_ns, id); | 495 | uid = make_kuid(&init_user_ns, id); |
496 | if (!uid_valid(uid)) | ||
497 | return -EINVAL; | ||
498 | ug.uid = uid; | 496 | ug.uid = uid; |
499 | 497 | ||
500 | expiry = get_expiry(&mesg); | 498 | expiry = get_expiry(&mesg); |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 0f679df7d072..305374d4fb98 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -917,7 +917,10 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
917 | len = svsk->sk_datalen; | 917 | len = svsk->sk_datalen; |
918 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 918 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
919 | for (i = 0; i < npages; i++) { | 919 | for (i = 0; i < npages; i++) { |
920 | BUG_ON(svsk->sk_pages[i] == NULL); | 920 | if (svsk->sk_pages[i] == NULL) { |
921 | WARN_ON_ONCE(1); | ||
922 | continue; | ||
923 | } | ||
921 | put_page(svsk->sk_pages[i]); | 924 | put_page(svsk->sk_pages[i]); |
922 | svsk->sk_pages[i] = NULL; | 925 | svsk->sk_pages[i] = NULL; |
923 | } | 926 | } |
@@ -1092,8 +1095,10 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1092 | goto err_noclose; | 1095 | goto err_noclose; |
1093 | } | 1096 | } |
1094 | 1097 | ||
1095 | if (svc_sock_reclen(svsk) < 8) | 1098 | if (svsk->sk_datalen < 8) { |
1099 | svsk->sk_datalen = 0; | ||
1096 | goto err_delete; /* client is nuts. */ | 1100 | goto err_delete; /* client is nuts. */ |
1101 | } | ||
1097 | 1102 | ||
1098 | rqstp->rq_arg.len = svsk->sk_datalen; | 1103 | rqstp->rq_arg.len = svsk->sk_datalen; |
1099 | rqstp->rq_arg.page_base = 0; | 1104 | rqstp->rq_arg.page_base = 0; |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 412de7cfcc80..ddf0602603bd 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -2534,7 +2534,6 @@ static struct rpc_xprt_ops bc_tcp_ops = { | |||
2534 | .reserve_xprt = xprt_reserve_xprt, | 2534 | .reserve_xprt = xprt_reserve_xprt, |
2535 | .release_xprt = xprt_release_xprt, | 2535 | .release_xprt = xprt_release_xprt, |
2536 | .alloc_slot = xprt_alloc_slot, | 2536 | .alloc_slot = xprt_alloc_slot, |
2537 | .rpcbind = xs_local_rpcbind, | ||
2538 | .buf_alloc = bc_malloc, | 2537 | .buf_alloc = bc_malloc, |
2539 | .buf_free = bc_free, | 2538 | .buf_free = bc_free, |
2540 | .send_request = bc_send_request, | 2539 | .send_request = bc_send_request, |
diff --git a/security/capability.c b/security/capability.c index d32e16e3c6ae..32b515766df1 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -858,7 +858,7 @@ static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | |||
858 | 858 | ||
859 | static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | 859 | static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) |
860 | { | 860 | { |
861 | return 0; | 861 | return -EOPNOTSUPP; |
862 | } | 862 | } |
863 | #ifdef CONFIG_KEYS | 863 | #ifdef CONFIG_KEYS |
864 | static int cap_key_alloc(struct key *key, const struct cred *cred, | 864 | static int cap_key_alloc(struct key *key, const struct cred *cred, |