From d89b22d46a40da3a1630ecea111beaf3ef10bc21 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: cred: add cred_fscmp() for comparing creds. NFS needs to compare to credentials, to see if they can be treated the same w.r.t. filesystem access. Sometimes an ordering is needed when credentials are used as a key to an rbtree. NFS currently has its own private credential management from before 'struct cred' existed. To move it over to more consistent use of 'struct cred' we need a comparison function. This patch adds that function. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/cred.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/cred.h b/include/linux/cred.h index 7eed6101c791..f1085767e1b3 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -169,6 +169,7 @@ extern int change_create_files_as(struct cred *, struct inode *); extern int set_security_override(struct cred *, u32); extern int set_security_override_from_ctx(struct cred *, const char *); extern int set_create_files_as(struct cred *, struct inode *); +extern int cred_fscmp(const struct cred *, const struct cred *); extern void __init cred_init(void); /* -- cgit v1.2.3 From 97d0fb239c041f5f99655af74812c3ab75cc4346 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: cred: add get_cred_rcu() Sometimes we want to opportunistically get a ref to a cred in an rcu_read_lock protected section. get_task_cred() does this, and NFS does as similar thing with its own credential structures. To prepare for NFS converting to use 'struct cred' more uniformly, define get_cred_rcu(), and use it in get_task_cred(). Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/cred.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include/linux') diff --git a/include/linux/cred.h b/include/linux/cred.h index f1085767e1b3..48979fcb95cf 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -252,6 +252,17 @@ static inline const struct cred *get_cred(const struct cred *cred) return get_new_cred(nonconst_cred); } +static inline const struct cred *get_cred_rcu(const struct cred *cred) +{ + struct cred *nonconst_cred = (struct cred *) cred; + if (!cred) + return NULL; + if (!atomic_inc_not_zero(&nonconst_cred->usage)) + return NULL; + validate_creds(cred); + return cred; +} + /** * put_cred - Release a reference to a set of credentials * @cred: The credentials to release -- cgit v1.2.3 From f06bc03339ad4c1baa964a5f0606247ac1c3c50b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: cred: allow get_cred() and put_cred() to be given NULL. It is common practice for helpers like this to silently, accept a NULL pointer. get_rpccred() and put_rpccred() used by NFS act this way and using the same interface will ease the conversion for NFS, and simplify the resulting code. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/cred.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cred.h b/include/linux/cred.h index 48979fcb95cf..4907c9df86b3 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -237,7 +237,7 @@ static inline struct cred *get_new_cred(struct cred *cred) * @cred: The credentials to reference * * Get a reference on the specified set of credentials. The caller must - * release the reference. + * release the reference. If %NULL is passed, it is returned with no action. * * This is used to deal with a committed set of credentials. Although the * pointer is const, this will temporarily discard the const and increment the @@ -248,6 +248,8 @@ static inline struct cred *get_new_cred(struct cred *cred) static inline const struct cred *get_cred(const struct cred *cred) { struct cred *nonconst_cred = (struct cred *) cred; + if (!cred) + return cred; validate_creds(cred); return get_new_cred(nonconst_cred); } @@ -268,7 +270,7 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred) * @cred: The credentials to release * * Release a reference to a set of credentials, deleting them when the last ref - * is released. + * is released. If %NULL is passed, nothing is done. * * This takes a const pointer to a set of credentials because the credentials * on task_struct are attached by const pointers to prevent accidental @@ -278,9 +280,11 @@ static inline void put_cred(const struct cred *_cred) { struct cred *cred = (struct cred *) _cred; - validate_creds(cred); - if (atomic_dec_and_test(&(cred)->usage)) - __put_cred(cred); + if (cred) { + validate_creds(cred); + if (atomic_dec_and_test(&(cred)->usage)) + __put_cred(cred); + } } /** -- cgit v1.2.3 From 97f68c6b02e0225b38d327103c59cfe2ab5ecda7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: add 'struct cred *' to auth_cred and rpc_cred The SUNRPC credential framework was put together before Linux has 'struct cred'. Now that we have it, it makes sense to use it. This first step just includes a suitable 'struct cred *' pointer in every 'struct auth_cred' and almost every 'struct rpc_cred'. The rpc_cred used for auth_null has a NULL 'struct cred *' as nothing else really makes sense. For rpc_cred, the pointer is reference counted. For auth_cred it isn't. struct auth_cred are either allocated on the stack, in which case the thread owns a reference to the auth, or are part of 'struct generic_cred' in which case gc_base owns the reference, and "acred" shares it. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index c4db9424b63b..1f95bd612053 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -46,6 +46,7 @@ enum { /* Work around the lack of a VFS credential */ struct auth_cred { + const struct cred *cred; kuid_t uid; kgid_t gid; struct group_info *group_info; @@ -68,6 +69,7 @@ struct rpc_cred { unsigned long cr_expire; /* when to gc */ unsigned long cr_flags; /* various flags */ refcount_t cr_count; /* ref count */ + const struct cred *cr_cred; kuid_t cr_uid; -- cgit v1.2.3 From fc0664fd9bccafb00bd2dfe0d5218147994f81ee Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: remove groupinfo from struct auth_cred. We can use cred->groupinfo (from the 'struct cred') instead. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 1f95bd612053..30eb9b9b9c8c 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -49,7 +49,6 @@ struct auth_cred { const struct cred *cred; kuid_t uid; kgid_t gid; - struct group_info *group_info; const char *principal; unsigned long ac_flags; unsigned char machine_cred : 1; -- cgit v1.2.3 From 8276c902bbe95d628f48a7fdc13c71e265992085 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: remove uid and gid from struct auth_cred Use cred->fsuid and cred->fsgid instead. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 30eb9b9b9c8c..831ea65bd9f4 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -44,11 +44,8 @@ enum { key will expire soon */ }; -/* Work around the lack of a VFS credential */ struct auth_cred { const struct cred *cred; - kuid_t uid; - kgid_t gid; const char *principal; unsigned long ac_flags; unsigned char machine_cred : 1; -- cgit v1.2.3 From 1a80810fbf238e6dbaaaa5262a76d328ace21376 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: remove machine_cred field from struct auth_cred The cred is a machine_cred iff ->principal is set, so there is no need for the extra flag. There is one case which deserves some explanation. nfs4_root_machine_cred() calls rpc_lookup_machine_cred() with a NULL principal name which results in not getting a machine credential, but getting a root credential instead. This appears to be what is expected of the caller, and is clearly the result provided by both auth_unix and auth_gss which already ignore the flag. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 831ea65bd9f4..1c0468f39479 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -46,9 +46,8 @@ enum { struct auth_cred { const struct cred *cred; - const char *principal; + const char *principal; /* If present, this is a machine credential */ unsigned long ac_flags; - unsigned char machine_cred : 1; }; /* -- cgit v1.2.3 From a534ecb013bfc58a7f03653c7f2976bc341da98f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: NFSv4: add cl_root_cred for use when machine cred is not available. NFSv4 state management tries a root credential when no machine credential is available, as can happen with kerberos. It does this by replacing the cl_machine_cred with a root credential. This means that any user of the machine credential needs to take a lock while getting a reference to the machine credential, which is a little cumbersome. So introduce an explicit cl_root_cred, and never free either credential until client shutdown. This means that no locking is needed to reference these credentials. Future patches will make use of this. This is only a temporary addition. both cl_machine_cred and cl_root_cred will disappear later in the series. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/nfs_fs_sb.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 0fc0b9135d46..fea51b44fe50 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -59,6 +59,7 @@ struct nfs_client { u32 cl_minorversion;/* NFSv4 minorversion */ struct rpc_cred *cl_machine_cred; + struct rpc_cred *cl_root_cred; /* Use when machine_cred is ineffective */ #if IS_ENABLED(CONFIG_NFS_V4) struct list_head cl_ds_clients; /* auth flavor data servers */ -- cgit v1.2.3 From ecd5f97e1c7cd6124e3c3053beb5f2239aeacf8e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: discard RPC_DO_ROOTOVERRIDE() it is never used. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/sched.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 7b540c066594..f542dad8d4ab 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -131,7 +131,6 @@ struct rpc_task_setup { #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) -#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) #define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT)) #define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) -- cgit v1.2.3 From 5e16923b432bfe79fdfb7cd95ed8e63f6438b663 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: NFS/SUNRPC: don't lookup machine credential until rpcauth_bindcred(). When NFS creates a machine credential, it is a "generic" credential, not tied to any auth protocol, and is really just a container for the princpal name. This doesn't get linked to a genuine credential until rpcauth_bindcred() is called. The lookup always succeeds, so various places that test if the machine credential is NULL, are pointless. As a step towards getting rid of generic credentials, this patch gets rid of generic machine credentials. The nfs_client and rpc_client just hold a pointer to a constant principal name. When a machine credential is wanted, a special static 'struct rpc_cred' pointer is used. rpcauth_bindcred() recognizes this, finds the principal from the client, and binds the correct credential. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/nfs_fs_sb.h | 3 +-- include/linux/sunrpc/auth.h | 3 ++- include/linux/sunrpc/clnt.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index fea51b44fe50..6aa8cc83c3b6 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -58,8 +58,7 @@ struct nfs_client { struct nfs_subversion * cl_nfs_mod; /* pointer to nfs version module */ u32 cl_minorversion;/* NFSv4 minorversion */ - struct rpc_cred *cl_machine_cred; - struct rpc_cred *cl_root_cred; /* Use when machine_cred is ineffective */ + const char * cl_principal; /* used for machine cred */ #if IS_ENABLED(CONFIG_NFS_V4) struct list_head cl_ds_clients; /* auth flavor data servers */ diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 1c0468f39479..28b34c740c43 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -75,6 +75,8 @@ struct rpc_cred { #define RPCAUTH_CRED_HASHED 2 #define RPCAUTH_CRED_NEGATIVE 3 +struct rpc_cred *rpc_machine_cred(void); + /* rpc_auth au_flags */ #define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT 0x0001 /* underlying cred has no key timeout */ @@ -170,7 +172,6 @@ void rpc_destroy_authunix(void); struct rpc_cred * rpc_lookup_cred(void); struct rpc_cred * rpc_lookup_cred_nonblock(void); struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t); -struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); int rpcauth_register(const struct rpc_authops *); int rpcauth_unregister(const struct rpc_authops *); struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *, diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 73d5c4a870fa..fc6dfbf77a9d 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -66,6 +66,7 @@ struct rpc_clnt { struct rpc_rtt cl_rtt_default; struct rpc_timeout cl_timeout_default; const struct rpc_program *cl_program; + const char * cl_principal; /* use for machine cred */ #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) struct dentry *cl_debugfs; /* debugfs directory */ #endif -- cgit v1.2.3 From a68a72e135ef55bce136a0b604413fd6b0f6d3fc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: introduce RPC_TASK_NULLCREDS to request auth_none In almost all cases the credential stored in rpc_message.rpc_cred is a "generic" credential. One of the two expections is when an AUTH_NULL credential is used such as for RPC ping requests. To improve consistency, don't pass an explicit credential in these cases, but instead pass NULL and set a task flag, similar to RPC_TASK_ROOTCREDS, which requests that NULL credentials be used by default. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/sched.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index f542dad8d4ab..bd722ebc70b7 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -118,6 +118,7 @@ struct rpc_task_setup { */ #define RPC_TASK_ASYNC 0x0001 /* is an async task */ #define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ +#define RPC_TASK_NULLCREDS 0x0010 /* Use AUTH_NULL credential */ #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ -- cgit v1.2.3 From 1de7eea92946d7b581a8cd26084410913c80e594 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: add side channel to use non-generic cred for rpc call. The credential passed in rpc_message.rpc_cred is always a generic credential except in one instance. When gss_destroying_context() calls rpc_call_null(), it passes a specific credential that it needs to destroy. In this case the RPC acts *on* the credential rather than being authorized by it. This special case deserves explicit support and providing that will mean that rpc_message.rpc_cred is *always* generic, allowing some optimizations. So add "tk_op_cred" to rpc_task and "rpc_op_cred" to the setup data. Use this to pass the cred down from rpc_call_null(), and have rpcauth_bindcred() notice it and bind it in place. Credit to kernel test robot for finding a bug in earlier version of this patch. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/sched.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index bd722ebc70b7..4e2b893b83a8 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -71,6 +71,7 @@ struct rpc_task { struct rpc_clnt * tk_client; /* RPC client */ struct rpc_xprt * tk_xprt; /* Transport */ + struct rpc_cred * tk_op_cred; /* cred being operated on */ struct rpc_rqst * tk_rqstp; /* RPC request */ @@ -105,6 +106,7 @@ struct rpc_task_setup { struct rpc_task *task; struct rpc_clnt *rpc_client; struct rpc_xprt *rpc_xprt; + struct rpc_cred *rpc_op_cred; /* credential being operated on */ const struct rpc_message *rpc_message; const struct rpc_call_ops *callback_ops; void *callback_data; -- cgit v1.2.3 From ddf529eeed59184c49dcad1633c11831f822bf6b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: NFS: move credential expiry tracking out of SUNRPC into NFS. NFS needs to know when a credential is about to expire so that it can modify write-back behaviour to finish the write inside the expiry time. It currently uses functions in SUNRPC code which make use of a fairly complex callback scheme and flags in the generic credientials. As I am working to discard the generic credentials, this has to change. This patch moves the logic into NFS, in part by finding and caching the low-level credential in the open_context. We then make direct cred-api calls on that. This makes the code much simpler and removes a dependency on generic rpc credentials. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/nfs_fs.h | 1 + include/linux/sunrpc/auth.h | 12 ------------ 2 files changed, 1 insertion(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 6e0417c02279..ecf22c0034d5 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -71,6 +71,7 @@ struct nfs_open_context { fl_owner_t flock_owner; struct dentry *dentry; struct rpc_cred *cred; + struct rpc_cred *ll_cred; /* low-level cred - use to check for expiry */ struct nfs4_state *state; fmode_t mode; diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 28b34c740c43..0bdc2f4957ff 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -37,17 +37,9 @@ struct rpcsec_gss_info; -/* auth_cred ac_flags bits */ -enum { - RPC_CRED_KEY_EXPIRE_SOON = 1, /* underlying cred key will expire soon */ - RPC_CRED_NOTIFY_TIMEOUT = 2, /* nofity generic cred when underlying - key will expire soon */ -}; - struct auth_cred { const struct cred *cred; const char *principal; /* If present, this is a machine credential */ - unsigned long ac_flags; }; /* @@ -154,7 +146,6 @@ struct rpc_credops { int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t, void *, __be32 *, void *); int (*crkey_timeout)(struct rpc_cred *); - bool (*crkey_to_expire)(struct rpc_cred *); char * (*crstringify_acceptor)(struct rpc_cred *); bool (*crneed_reencode)(struct rpc_task *); }; @@ -198,9 +189,6 @@ int rpcauth_uptodatecred(struct rpc_task *); int rpcauth_init_credcache(struct rpc_auth *); void rpcauth_destroy_credcache(struct rpc_auth *); void rpcauth_clear_credcache(struct rpc_cred_cache *); -int rpcauth_key_timeout_notify(struct rpc_auth *, - struct rpc_cred *); -bool rpcauth_cred_key_to_expire(struct rpc_auth *, struct rpc_cred *); char * rpcauth_stringify_acceptor(struct rpc_cred *); static inline -- cgit v1.2.3 From 354698b7d47165ed2f52d6c2bf682096a4cd71d1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: SUNRPC: remove RPCAUTH_AUTH_NO_CRKEY_TIMEOUT This is no longer used. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 0bdc2f4957ff..d8cf742f8032 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -69,9 +69,6 @@ struct rpc_cred { struct rpc_cred *rpc_machine_cred(void); -/* rpc_auth au_flags */ -#define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT 0x0001 /* underlying cred has no key timeout */ - /* * Client authentication handle */ -- cgit v1.2.3 From b68572e07c58324cb8c274f1d84a20cad479c2d3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: NFS: change access cache to use 'struct cred'. Rather than keying the access cache with 'struct rpc_cred', use 'struct cred'. Then use cred_fscmp() to compare credentials rather than comparing the raw pointer. A benefit of this approach is that in the common case we avoid the rpc_lookup_cred_nonblock() call which can be slow when the cred cache is large. This also keeps many fewer items pinned in the rpc cred cache, so the cred cache is less likely to get large. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/nfs_fs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index ecf22c0034d5..7d2064bd421f 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -51,7 +51,7 @@ struct nfs_access_entry { struct rb_node rb_node; struct list_head lru; - struct rpc_cred * cred; + const struct cred * cred; __u32 mask; struct rcu_head rcu_head; }; @@ -491,7 +491,7 @@ extern const struct dentry_operations nfs_dentry_operations; extern void nfs_force_lookup_revalidate(struct inode *dir); extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label); -extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); +extern int nfs_may_open(struct inode *inode, const struct cred *cred, int openflags); extern void nfs_access_zap_cache(struct inode *inode); /* -- cgit v1.2.3 From 684f39b4cf5186bb0660e686f94296688b24fb32 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:30 +1100 Subject: NFS: struct nfs_open_dir_context: convert rpc_cred pointer to cred. Use the common 'struct cred' to pass credentials for readdir. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/nfs_fs.h | 2 +- include/linux/nfs_xdr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7d2064bd421f..271015e55d0f 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -89,7 +89,7 @@ struct nfs_open_context { struct nfs_open_dir_context { struct list_head list; - struct rpc_cred *cred; + const struct cred *cred; unsigned long attr_gencount; __u64 dir_cookie; __u64 dup_cookie; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 0e016252cfc6..cd489e2e0979 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1634,7 +1634,7 @@ struct nfs_rpc_ops { unsigned int, struct iattr *); int (*mkdir) (struct inode *, struct dentry *, struct iattr *); int (*rmdir) (struct inode *, const struct qstr *); - int (*readdir) (struct dentry *, struct rpc_cred *, + int (*readdir) (struct dentry *, const struct cred *, u64, struct page **, unsigned int, bool); int (*mknod) (struct inode *, struct dentry *, struct iattr *, dev_t); -- cgit v1.2.3 From a52458b48af142bcc2b72fe810c0db20cfae7fdd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:31 +1100 Subject: NFS/NFSD/SUNRPC: replace generic creds with 'struct cred'. SUNRPC has two sorts of credentials, both of which appear as "struct rpc_cred". There are "generic credentials" which are supplied by clients such as NFS and passed in 'struct rpc_message' to indicate which user should be used to authorize the request, and there are low-level credentials such as AUTH_NULL, AUTH_UNIX, AUTH_GSS which describe the credential to be sent over the wires. This patch replaces all the generic credentials by 'struct cred' pointers - the credential structure used throughout Linux. For machine credentials, there is a special 'struct cred *' pointer which is statically allocated and recognized where needed as having a special meaning. A look-up of a low-level cred will map this to a machine credential. Signed-off-by: NeilBrown Acked-by: J. Bruce Fields Signed-off-by: Anna Schumaker --- include/linux/nfs_fs.h | 6 +++--- include/linux/nfs_xdr.h | 14 +++++++------- include/linux/sunrpc/auth.h | 18 +----------------- include/linux/sunrpc/sched.h | 2 +- 4 files changed, 12 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 271015e55d0f..40e30376130b 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -70,7 +70,7 @@ struct nfs_open_context { struct nfs_lock_context lock_context; fl_owner_t flock_owner; struct dentry *dentry; - struct rpc_cred *cred; + const struct cred *cred; struct rpc_cred *ll_cred; /* low-level cred - use to check for expiry */ struct nfs4_state *state; fmode_t mode; @@ -391,7 +391,7 @@ extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx); -extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); +extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct cred *cred, fmode_t mode); extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode, struct file *filp); extern void nfs_inode_attach_open_context(struct nfs_open_context *ctx); extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx); @@ -462,7 +462,7 @@ static inline struct nfs_open_context *nfs_file_open_context(struct file *filp) return filp->private_data; } -static inline struct rpc_cred *nfs_file_cred(struct file *file) +static inline const struct cred *nfs_file_cred(struct file *file) { if (file != NULL) { struct nfs_open_context *ctx = diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index cd489e2e0979..441a93ebcac0 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -270,7 +270,7 @@ struct nfs4_layoutget_res { struct nfs4_layoutget { struct nfs4_layoutget_args args; struct nfs4_layoutget_res res; - struct rpc_cred *cred; + const struct cred *cred; gfp_t gfp_flags; }; @@ -309,7 +309,7 @@ struct nfs4_layoutcommit_data { struct rpc_task task; struct nfs_fattr fattr; struct list_head lseg_list; - struct rpc_cred *cred; + const struct cred *cred; struct inode *inode; struct nfs4_layoutcommit_args args; struct nfs4_layoutcommit_res res; @@ -334,7 +334,7 @@ struct nfs4_layoutreturn_res { struct nfs4_layoutreturn { struct nfs4_layoutreturn_args args; struct nfs4_layoutreturn_res res; - struct rpc_cred *cred; + const struct cred *cred; struct nfs_client *clp; struct inode *inode; int rpc_status; @@ -1469,7 +1469,7 @@ enum { struct nfs_io_completion; struct nfs_pgio_header { struct inode *inode; - struct rpc_cred *cred; + const struct cred *cred; struct list_head pages; struct nfs_page *req; struct nfs_writeverf verf; /* Used for writes */ @@ -1529,7 +1529,7 @@ struct nfs_commit_info { struct nfs_commit_data { struct rpc_task task; struct inode *inode; - struct rpc_cred *cred; + const struct cred *cred; struct nfs_fattr fattr; struct nfs_writeverf verf; struct list_head pages; /* Coalesced requests we wish to flush */ @@ -1560,7 +1560,7 @@ struct nfs_unlinkdata { struct nfs_removeres res; struct dentry *dentry; wait_queue_head_t wq; - struct rpc_cred *cred; + const struct cred *cred; struct nfs_fattr dir_attr; long timeout; }; @@ -1568,7 +1568,7 @@ struct nfs_unlinkdata { struct nfs_renamedata { struct nfs_renameargs args; struct nfs_renameres res; - struct rpc_cred *cred; + const struct cred *cred; struct inode *old_dir; struct dentry *old_dentry; struct nfs_fattr old_fattr; diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index d8cf742f8032..a43e065a0b07 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -67,7 +67,7 @@ struct rpc_cred { #define RPCAUTH_CRED_HASHED 2 #define RPCAUTH_CRED_NEGATIVE 3 -struct rpc_cred *rpc_machine_cred(void); +const struct cred *rpc_machine_cred(void); /* * Client authentication handle @@ -196,21 +196,5 @@ struct rpc_cred *get_rpccred(struct rpc_cred *cred) return NULL; } -/** - * get_rpccred_rcu - get a reference to a cred using rcu-protected pointer - * @cred: cred of which to take a reference - * - * In some cases, we may have a pointer to a credential to which we - * want to take a reference, but don't already have one. Because these - * objects are freed using RCU, we can access the cr_count while its - * on its way to destruction and only take a reference if it's not already - * zero. - */ -static inline struct rpc_cred * -get_rpccred_rcu(struct rpc_cred *cred) -{ - return get_rpccred(cred); -} - #endif /* __KERNEL__ */ #endif /* _LINUX_SUNRPC_AUTH_H */ diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 4e2b893b83a8..219aa3910a0c 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -26,7 +26,7 @@ struct rpc_message { const struct rpc_procinfo *rpc_proc; /* Procedure information */ void * rpc_argp; /* Arguments */ void * rpc_resp; /* Result */ - struct rpc_cred * rpc_cred; /* Credentials */ + const struct cred * rpc_cred; /* Credentials */ }; struct rpc_call_ops; -- cgit v1.2.3 From 89a4f758d9f55f197c2a461f61ffa4a75127b30d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:31 +1100 Subject: SUNRPC: remove generic cred code. This is no longer used. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index a43e065a0b07..b9449aa27fed 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -104,7 +104,6 @@ struct rpc_auth_create_args { /* Flags for rpcauth_lookupcred() */ #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ -#define RPCAUTH_LOOKUP_RCU 0x02 /* lock-less lookup */ /* * Client authentication ops @@ -151,15 +150,10 @@ extern const struct rpc_authops authunix_ops; extern const struct rpc_authops authnull_ops; int __init rpc_init_authunix(void); -int __init rpc_init_generic_auth(void); int __init rpcauth_init_module(void); void rpcauth_remove_module(void); -void rpc_destroy_generic_auth(void); void rpc_destroy_authunix(void); -struct rpc_cred * rpc_lookup_cred(void); -struct rpc_cred * rpc_lookup_cred_nonblock(void); -struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t); int rpcauth_register(const struct rpc_authops *); int rpcauth_unregister(const struct rpc_authops *); struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *, -- cgit v1.2.3 From d6efccd97e6de25e002d658593675ce8e07ceb8c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:31 +1100 Subject: SUNRPC: remove crbind rpc_cred operation This now always just does get_rpccred(), so we don't need an operation pointer to know to do that. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index b9449aa27fed..5486082d3d63 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -133,7 +133,6 @@ struct rpc_credops { void (*crdestroy)(struct rpc_cred *); int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); - struct rpc_cred * (*crbind)(struct rpc_task *, struct rpc_cred *, int); __be32 * (*crmarshal)(struct rpc_task *, __be32 *); int (*crrefresh)(struct rpc_task *); __be32 * (*crvalidate)(struct rpc_task *, __be32 *); @@ -167,7 +166,6 @@ int rpcauth_list_flavors(rpc_authflavor_t *, int); struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int, gfp_t); void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); -struct rpc_cred * rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int); void put_rpccred(struct rpc_cred *); __be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); __be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); -- cgit v1.2.3 From 04d1532bd0b93cc4d0056f27da1591f086d341a6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Dec 2018 11:30:31 +1100 Subject: SUNRPC discard cr_uid from struct rpc_cred. Just use ->cr_cred->fsuid directly. Signed-off-by: NeilBrown Signed-off-by: Anna Schumaker --- include/linux/sunrpc/auth.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 5486082d3d63..eed3cb16ccf1 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -58,8 +58,6 @@ struct rpc_cred { refcount_t cr_count; /* ref count */ const struct cred *cr_cred; - kuid_t cr_uid; - /* per-flavor data */ }; #define RPCAUTH_CRED_NEW 0 -- cgit v1.2.3 From 10e037d1e0d5d93cc057e4fad6911e481a462407 Mon Sep 17 00:00:00 2001 From: Santosh kumar pradhan Date: Wed, 19 Dec 2018 12:29:57 +0530 Subject: sunrpc: Add xprt after nfs4_test_session_trunk() Multipathing: In case of NFSv3, rpc_clnt_test_and_add_xprt() adds the xprt to xprt switch (i.e. xps) if rpc_call_null_helper() returns success. But in case of NFSv4.1, it needs to do EXCHANGEID to verify the path along with check for session trunking. Add the xprt in nfs4_test_session_trunk() only when nfs4_detect_session_trunking() returns success. Also release refcount hold by rpc_clnt_setup_test_and_add_xprt(). Signed-off-by: Santosh kumar pradhan Tested-by: Suresh Jayaraman Reported-by: Aditya Agnihotri Signed-off-by: Anna Schumaker --- include/linux/sunrpc/clnt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index fc6dfbf77a9d..1c441714d569 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -128,8 +128,8 @@ struct rpc_create_args { }; struct rpc_add_xprt_test { - int (*add_xprt_test)(struct rpc_clnt *, - struct rpc_xprt *, + void (*add_xprt_test)(struct rpc_clnt *clnt, + struct rpc_xprt *xprt, void *calldata); void *data; }; -- cgit v1.2.3