linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: NeilBrown <neilb@suse.com>
To: Chuck Lever <chuck.lever@oracle.com>
Cc: Bruce Fields <bfields@fieldses.org>,
	Jeff Layton <jlayton@kernel.org>,
	Trond Myklebust <trond.myklebust@hammerspace.com>,
	Anna Schumaker <anna.schumaker@netapp.com>,
	Linux NFS Mailing List <linux-nfs@vger.kernel.org>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 22/23] SUNRPC: simplify auth_unix.
Date: Thu, 08 Nov 2018 12:41:16 +1100	[thread overview]
Message-ID: <87va58wdkz.fsf@notabene.neil.brown.name> (raw)
In-Reply-To: <4A3FA05E-EF4E-4857-A541-E863C5C6198D@oracle.com>

[-- Attachment #1: Type: text/plain, Size: 10772 bytes --]

On Wed, Nov 07 2018, Chuck Lever wrote:

> Hi Neil-
>
>
>> On Nov 6, 2018, at 11:12 PM, NeilBrown <neilb@suse.com> wrote:
>> 
>> 1/ discard 'struct unx_cred'.  We don't need any data that
>>   is not already in 'struct rpc_cred'.
>> 2/ Don't keep these creds in a hash table.  When a credential
>>   is needed, simply allocate it.  When not needed, discard it.
>>   This can easily be faster than performing a lookup on
>>   a shared hash table.

Thanks for the review Chuck!

>
> What's the basis for this claim? A memory allocation disables and
> enables IRQs. That definitely hits a resource that is globally
> shared.

My basis is not rock solid, but I was convinced :-)

kmem_cache_alloc() does disable local irqs when slab.c is used.
slub.c doesn't disable them in the fast path which I *think* should be
reasonably common.
slob always takes a spinlock as well as disabling interrupts.

I think slob is only recommended for tiny machines, and slub is
generally preferred, so I think that when performance matters, it will
still be delivered.

It isn't clear to me why you consider a local irq to be "globally
shared" - assuming that is what you mean.
Disabling local interrupts is not without cost, but I don't think the
cost increases with the number of CPUs, while the cost of accessing
shared memory (even without a spinlock) does.

>
> In addition, the comment near unx_marshal suggests we should
> cache the marshaled on-the-wire version of the credential instead
> of building it in the RPC Call buffer every time. That would
> require keeping the creds around.

That comment has been there since 2.1.32 and has not be acted on.  There
seems little reason to expect that to change.  Caching doesn't seem to
have been found to be necessary in practice.

>
> Have you measured a significant difference in throughput with
> this patch? Have you considered improving the lookup speed of
> the hash table by making the buckets into rb-trees, for example?

No, I haven't measured.
I might have briefly considered changing to an rb-tree, but as the
current hashtable doesn't actually contain anything of value, I would
have quickly discarded the idea.

If I wanted to further improve performance, I would look at ways to
bypass the "lookup_cred" step completely.
unx_marshal only needs the generic "struct cred", so there should be no
need to have a 'struct rpc_cred' at all.

If this series is accepted, I'll (hopefully) look into seeing how
practical that is.

Thanks again,
NeilBrown


>
>
>>   As the lookup can happen during write-out, use a mempool
>>   to ensure forward progress.
>>   This means that we cannot compare two credentials for
>>   equality by comparing the pointers, but we never do that anyway.
>> 
>> Signed-off-by: NeilBrown <neilb@suse.com>
>> ---
>> net/sunrpc/auth.c      |    1 
>> net/sunrpc/auth_unix.c |  101 +++++++++++++++---------------------------------
>> 2 files changed, 32 insertions(+), 70 deletions(-)
>> 
>> diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
>> index 867ea9834bde..a07a7c59d3a4 100644
>> --- a/net/sunrpc/auth.c
>> +++ b/net/sunrpc/auth.c
>> @@ -651,6 +651,7 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
>> 	INIT_LIST_HEAD(&cred->cr_lru);
>> 	refcount_set(&cred->cr_count, 1);
>> 	cred->cr_auth = auth;
>> +	cred->cr_flags = 0;
>> 	cred->cr_ops = ops;
>> 	cred->cr_expire = jiffies;
>> 	cred->cr_cred = get_cred(acred->cred);
>> diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
>> index bff113a411e0..387f6b3ffbea 100644
>> --- a/net/sunrpc/auth_unix.c
>> +++ b/net/sunrpc/auth_unix.c
>> @@ -11,16 +11,11 @@
>> #include <linux/types.h>
>> #include <linux/sched.h>
>> #include <linux/module.h>
>> +#include <linux/mempool.h>
>> #include <linux/sunrpc/clnt.h>
>> #include <linux/sunrpc/auth.h>
>> #include <linux/user_namespace.h>
>> 
>> -struct unx_cred {
>> -	struct rpc_cred		uc_base;
>> -	kgid_t			uc_gid;
>> -	kgid_t			uc_gids[UNX_NGROUPS];
>> -};
>> -#define uc_uid			uc_base.cr_uid
>> 
>> #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
>> # define RPCDBG_FACILITY	RPCDBG_AUTH
>> @@ -28,6 +23,7 @@ struct unx_cred {
>> 
>> static struct rpc_auth		unix_auth;
>> static const struct rpc_credops	unix_credops;
>> +static mempool_t		*unix_pool;
>> 
>> static struct rpc_auth *
>> unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
>> @@ -42,15 +38,6 @@ static void
>> unx_destroy(struct rpc_auth *auth)
>> {
>> 	dprintk("RPC:       destroying UNIX authenticator %p\n", auth);
>> -	rpcauth_clear_credcache(auth->au_credcache);
>> -}
>> -
>> -static int
>> -unx_hash_cred(struct auth_cred *acred, unsigned int hashbits)
>> -{
>> -	return hash_64(from_kgid(&init_user_ns, acred->cred->fsgid) |
>> -		((u64)from_kuid(&init_user_ns, acred->cred->fsuid) <<
>> -			(sizeof(gid_t) * 8)), hashbits);
>> }
>> 
>> /*
>> @@ -59,53 +46,24 @@ unx_hash_cred(struct auth_cred *acred, unsigned int hashbits)
>> static struct rpc_cred *
>> unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
>> {
>> -	return rpcauth_lookup_credcache(auth, acred, flags, GFP_NOFS);
>> -}
>> -
>> -static struct rpc_cred *
>> -unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t gfp)
>> -{
>> -	struct unx_cred	*cred;
>> -	unsigned int groups = 0;
>> -	unsigned int i;
>> +	struct rpc_cred *ret = mempool_alloc(unix_pool, GFP_NOFS);
>> 
>> 	dprintk("RPC:       allocating UNIX cred for uid %d gid %d\n",
>> 			from_kuid(&init_user_ns, acred->cred->fsuid),
>> 			from_kgid(&init_user_ns, acred->cred->fsgid));
>> 
>> -	if (!(cred = kmalloc(sizeof(*cred), gfp)))
>> -		return ERR_PTR(-ENOMEM);
>> -
>> -	rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
>> -	cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
>> -
>> -	if (acred->cred && acred->cred->group_info != NULL)
>> -		groups = acred->cred->group_info->ngroups;
>> -	if (groups > UNX_NGROUPS)
>> -		groups = UNX_NGROUPS;
>> -
>> -	cred->uc_gid = acred->cred->fsgid;
>> -	for (i = 0; i < groups; i++)
>> -		cred->uc_gids[i] = acred->cred->group_info->gid[i];
>> -	if (i < UNX_NGROUPS)
>> -		cred->uc_gids[i] = INVALID_GID;
>> -
>> -	return &cred->uc_base;
>> -}
>> -
>> -static void
>> -unx_free_cred(struct unx_cred *unx_cred)
>> -{
>> -	dprintk("RPC:       unx_free_cred %p\n", unx_cred);
>> -	put_cred(unx_cred->uc_base.cr_cred);
>> -	kfree(unx_cred);
>> +	rpcauth_init_cred(ret, acred, auth, &unix_credops);
>> +	ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
>> +	return ret;
>> }
>> 
>> static void
>> unx_free_cred_callback(struct rcu_head *head)
>> {
>> -	struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu);
>> -	unx_free_cred(unx_cred);
>> +	struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu);
>> +	dprintk("RPC:       unx_free_cred %p\n", rpc_cred);
>> +	put_cred(rpc_cred->cr_cred);
>> +	mempool_free(rpc_cred, unix_pool);
>> }
>> 
>> static void
>> @@ -115,30 +73,32 @@ unx_destroy_cred(struct rpc_cred *cred)
>> }
>> 
>> /*
>> - * Match credentials against current process creds.
>> - * The root_override argument takes care of cases where the caller may
>> - * request root creds (e.g. for NFS swapping).
>> + * Match credentials against current the auth_cred.
>>  */
>> static int
>> -unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
>> +unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
>> {
>> -	struct unx_cred	*cred = container_of(rcred, struct unx_cred, uc_base);
>> 	unsigned int groups = 0;
>> 	unsigned int i;
>> 
>> +	if (cred->cr_cred == acred->cred)
>> +		return 1;
>> 
>> -	if (!uid_eq(cred->uc_uid, acred->cred->fsuid) || !gid_eq(cred->uc_gid, acred->cred->fsgid))
>> +	if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid))
>> 		return 0;
>> 
>> 	if (acred->cred && acred->cred->group_info != NULL)
>> 		groups = acred->cred->group_info->ngroups;
>> 	if (groups > UNX_NGROUPS)
>> 		groups = UNX_NGROUPS;
>> +	if (cred->cr_cred->group_info == NULL)
>> +		return groups == 0;
>> +	if (groups != cred->cr_cred->group_info->ngroups)
>> +		return 0;
>> +
>> 	for (i = 0; i < groups ; i++)
>> -		if (!gid_eq(cred->uc_gids[i], acred->cred->group_info->gid[i]))
>> +		if (!gid_eq(cred->cr_cred->group_info->gid[i], acred->cred->group_info->gid[i]))
>> 			return 0;
>> -	if (groups < UNX_NGROUPS && gid_valid(cred->uc_gids[groups]))
>> -		return 0;
>> 	return 1;
>> }
>> 
>> @@ -150,9 +110,10 @@ static __be32 *
>> unx_marshal(struct rpc_task *task, __be32 *p)
>> {
>> 	struct rpc_clnt	*clnt = task->tk_client;
>> -	struct unx_cred	*cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base);
>> +	struct rpc_cred	*cred = task->tk_rqstp->rq_cred;
>> 	__be32		*base, *hold;
>> 	int		i;
>> +	struct group_info *gi = cred->cr_cred->group_info;
>> 
>> 	*p++ = htonl(RPC_AUTH_UNIX);
>> 	base = p++;
>> @@ -163,11 +124,12 @@ unx_marshal(struct rpc_task *task, __be32 *p)
>> 	 */
>> 	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
>> 
>> -	*p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid));
>> -	*p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid));
>> +	*p++ = htonl((u32) from_kuid(&init_user_ns, cred->cr_cred->fsuid));
>> +	*p++ = htonl((u32) from_kgid(&init_user_ns, cred->cr_cred->fsgid));
>> 	hold = p++;
>> -	for (i = 0; i < UNX_NGROUPS && gid_valid(cred->uc_gids[i]); i++)
>> -		*p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i]));
>> +	if (gi)
>> +		for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++)
>> +			*p++ = htonl((u32) from_kgid(&init_user_ns, gi->gid[i]));
>> 	*hold = htonl(p - hold - 1);		/* gid array length */
>> 	*base = htonl((p - base - 1) << 2);	/* cred length */
>> 
>> @@ -214,12 +176,13 @@ unx_validate(struct rpc_task *task, __be32 *p)
>> 
>> int __init rpc_init_authunix(void)
>> {
>> -	return rpcauth_init_credcache(&unix_auth);
>> +	unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred));
>> +	return unix_pool ? 0 : -ENOMEM;
>> }
>> 
>> void rpc_destroy_authunix(void)
>> {
>> -	rpcauth_destroy_credcache(&unix_auth);
>> +	mempool_destroy(unix_pool);
>> }
>> 
>> const struct rpc_authops authunix_ops = {
>> @@ -228,9 +191,7 @@ const struct rpc_authops authunix_ops = {
>> 	.au_name	= "UNIX",
>> 	.create		= unx_create,
>> 	.destroy	= unx_destroy,
>> -	.hash_cred	= unx_hash_cred,
>> 	.lookup_cred	= unx_lookup_cred,
>> -	.crcreate	= unx_create_cred,
>> };
>> 
>> static
>> 
>> 
>
> --
> Chuck Lever

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

  reply	other threads:[~2018-11-08  1:41 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-07  4:12 [PATCH 00/23 - V4] NFS: Remove generic RPC credentials NeilBrown
2018-11-07  4:12 ` [PATCH 06/23] SUNRPC: remove groupinfo from struct auth_cred NeilBrown
2018-11-07  4:12 ` [PATCH 03/23] cred: export get_task_cred() NeilBrown
2018-11-07  4:12 ` [PATCH 04/23] cred: allow get_cred() and put_cred() to be given NULL NeilBrown
2018-11-07  4:12 ` [PATCH 05/23] SUNRPC: add 'struct cred *' to auth_cred and rpc_cred NeilBrown
2018-11-07  4:12 ` [PATCH 01/23] cred: add cred_fscmp() for comparing creds NeilBrown
2018-11-07  4:12 ` [PATCH 02/23] cred: add get_cred_rcu() NeilBrown
2018-11-07  4:12 ` [PATCH 21/23] SUNRPC: remove crbind rpc_cred operation NeilBrown
2018-11-07  4:12 ` [PATCH 11/23] SUNRPC: discard RPC_DO_ROOTOVERRIDE() NeilBrown
2018-11-07  4:12 ` [PATCH 22/23] SUNRPC: simplify auth_unix NeilBrown
2018-11-07 15:19   ` Chuck Lever
2018-11-08  1:41     ` NeilBrown [this message]
2018-11-08 15:54       ` Chuck Lever
2018-11-09  0:45         ` NeilBrown
2018-11-07  4:12 ` [PATCH 18/23] NFS: struct nfs_open_dir_context: convert rpc_cred pointer to cred NeilBrown
2018-11-07  4:12 ` [PATCH 20/23] SUNRPC: remove generic cred code NeilBrown
2018-11-07  4:12 ` [PATCH 23/23] SUNRPC discard cr_uid from struct rpc_cred NeilBrown
2018-11-07  4:12 ` [PATCH 10/23] NFSv4: don't require lock for get_renew_cred or get_machine_cred NeilBrown
2018-11-07  4:12 ` [PATCH 19/23] NFS/NFSD/SUNRPC: replace generic creds with 'struct cred' NeilBrown
2018-11-07  4:12 ` [PATCH 12/23] NFS/SUNRPC: don't lookup machine credential until rpcauth_bindcred() NeilBrown
2018-11-07  4:12 ` [PATCH 17/23] NFS: change access cache to use 'struct cred' NeilBrown
2018-11-07  4:12 ` [PATCH 07/23] SUNRPC: remove uid and gid from struct auth_cred NeilBrown
2018-11-07  4:12 ` [PATCH 16/23] SUNRPC: remove RPCAUTH_AUTH_NO_CRKEY_TIMEOUT NeilBrown
2018-11-07  4:12 ` [PATCH 09/23] NFSv4: add cl_root_cred for use when machine cred is not available NeilBrown
2018-11-07  4:12 ` [PATCH 14/23] SUNRPC: add side channel to use non-generic cred for rpc call NeilBrown
2018-11-07  4:12 ` [PATCH 13/23] SUNRPC: introduce RPC_TASK_NULLCREDS to request auth_none NeilBrown
2018-11-07  4:12 ` [PATCH 08/23] SUNRPC: remove machine_cred field from struct auth_cred NeilBrown
2018-11-07  4:12 ` [PATCH 15/23] NFS: move credential expiry tracking out of SUNRPC into NFS NeilBrown
2018-11-29 23:19 ` [PATCH 00/23 - V4] NFS: Remove generic RPC credentials NeilBrown
2018-11-30 19:39   ` Schumaker, Anna
  -- strict thread matches above, loose matches on Subject: below --
2018-12-03  0:30 [PATCH 00/23 - V5] " NeilBrown
2018-12-03  0:30 ` [PATCH 22/23] SUNRPC: simplify auth_unix NeilBrown
2018-02-19  5:02 [PATCH 00/23] Remove generic rpc credentials, and associated changed - V3 NeilBrown
2018-02-19  5:02 ` [PATCH 22/23] SUNRPC: simplify auth_unix NeilBrown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87va58wdkz.fsf@notabene.neil.brown.name \
    --to=neilb@suse.com \
    --cc=anna.schumaker@netapp.com \
    --cc=bfields@fieldses.org \
    --cc=chuck.lever@oracle.com \
    --cc=jlayton@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=trond.myklebust@hammerspace.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).