Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efc36aa5 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

[PATCH] knfsd: Change the store of auth_domains to not be a 'cache'



The 'auth_domain's are simply handles on internal data structures.  They do
not cache information from user-space, and forcing them into the mold of a
'cache' misrepresents their true nature and causes confusion.

Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3e7b1919
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -242,7 +242,7 @@ static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)

static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
{
	cache_get(&item->ek_client->h);
	kref_get(&item->ek_client->ref);
	new->ek_client = item->ek_client;
	new->ek_fsidtype = item->ek_fsidtype;
	new->ek_fsid[0] = item->ek_fsid[0];
@@ -474,7 +474,7 @@ static inline int svc_export_match(struct svc_export *a, struct svc_export *b)
}
static inline void svc_export_init(struct svc_export *new, struct svc_export *item)
{
	cache_get(&item->ex_client->h);
	kref_get(&item->ex_client->ref);
	new->ex_client = item->ex_client;
	new->ex_dentry = dget(item->ex_dentry);
	new->ex_mnt = mntget(item->ex_mnt);
@@ -1129,7 +1129,6 @@ exp_delclient(struct nfsctl_client *ncp)
	 */
	if (dom) {
		err = auth_unix_forget_old(dom);
		dom->h.expiry_time = get_seconds();
		auth_domain_put(dom);
	}

+7 −5
Original line number Diff line number Diff line
@@ -45,9 +45,10 @@ struct svc_rqst; /* forward decl */
 * of ip addresses to the given client.
 */
struct auth_domain {
	struct	cache_head	h;
	struct kref		ref;
	struct hlist_node	hash;
	char			*name;
	int			flavour;
	struct auth_ops		*flavour;
};

/*
@@ -86,6 +87,9 @@ struct auth_domain {
 *
 * domain_release()
 *   This call releases a domain.
 * set_client()
 *   Givens a pending request (struct svc_rqst), finds and assigns
 *   an appropriate 'auth_domain' as the client.
 */
struct auth_ops {
	char *	name;
@@ -117,7 +121,7 @@ extern void svc_auth_unregister(rpc_authflavor_t flavor);
extern struct auth_domain *unix_domain_find(char *name);
extern void auth_domain_put(struct auth_domain *item);
extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
extern struct auth_domain *auth_domain_lookup(struct auth_domain *item, int set);
extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
extern struct auth_domain *auth_domain_find(char *name);
extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
@@ -160,8 +164,6 @@ static inline unsigned long hash_mem(char *buf, int length, int bits)
	return hash >> (BITS_PER_LONG - bits);
}

extern struct cache_detail auth_domain_cache, ip_map_cache;

#endif /* __KERNEL__ */

#endif /* _LINUX_SUNRPC_SVCAUTH_H_ */
+7 −7
Original line number Diff line number Diff line
@@ -645,6 +645,8 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
	return auth_domain_find(name);
}

static struct auth_ops svcauthops_gss;

int
svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
{
@@ -655,20 +657,18 @@ svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
	new = kmalloc(sizeof(*new), GFP_KERNEL);
	if (!new)
		goto out;
	cache_init(&new->h.h);
	kref_init(&new->h.ref);
	new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL);
	if (!new->h.name)
		goto out_free_dom;
	strcpy(new->h.name, name);
	new->h.flavour = RPC_AUTH_GSS;
	new->h.flavour = &svcauthops_gss;
	new->pseudoflavor = pseudoflavor;
	new->h.h.expiry_time = NEVER;

	test = auth_domain_lookup(&new->h, 1);
	if (test == &new->h) {
		BUG_ON(atomic_dec_and_test(&new->h.h.refcnt));
	} else { /* XXX Duplicate registration? */
	test = auth_domain_lookup(name, &new->h);
	if (test != &new->h) { /* XXX Duplicate registration? */
		auth_domain_put(&new->h);
		/* dangling ref-count... */
		goto out;
	}
	return 0;
+1 −3
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ EXPORT_SYMBOL(nlm_debug);

extern int register_rpc_pipefs(void);
extern void unregister_rpc_pipefs(void);
extern struct cache_detail ip_map_cache;

static int __init
init_sunrpc(void)
@@ -158,7 +159,6 @@ init_sunrpc(void)
#ifdef CONFIG_PROC_FS
	rpc_proc_init();
#endif
	cache_register(&auth_domain_cache);
	cache_register(&ip_map_cache);
out:
	return err;
@@ -169,8 +169,6 @@ cleanup_sunrpc(void)
{
	unregister_rpc_pipefs();
	rpc_destroy_mempool();
	if (cache_unregister(&auth_domain_cache))
		printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n");
	if (cache_unregister(&ip_map_cache))
		printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
#ifdef RPC_DEBUG
+33 −89
Original line number Diff line number Diff line
@@ -106,112 +106,56 @@ svc_auth_unregister(rpc_authflavor_t flavor)
EXPORT_SYMBOL(svc_auth_unregister);

/**************************************************
 * cache for domain name to auth_domain
 * Entries are only added by flavours which will normally
 * have a structure that 'inherits' from auth_domain.
 * e.g. when an IP -> domainname is given to  auth_unix,
 * and the domain name doesn't exist, it will create a
 * auth_unix_domain and add it to this hash table.
 * If it finds the name does exist, but isn't AUTH_UNIX,
 * it will complain.
 * 'auth_domains' are stored in a hash table indexed by name.
 * When the last reference to an 'auth_domain' is dropped,
 * the object is unhashed and freed.
 * If auth_domain_lookup fails to find an entry, it will return
 * it's second argument 'new'.  If this is non-null, it will
 * have been atomically linked into the table.
 */

/*
 * Auth auth_domain cache is somewhat different to other caches,
 * largely because the entries are possibly of different types:
 * each auth flavour has it's own type.
 * One consequence of this that DefineCacheLookup cannot
 * allocate a new structure as it cannot know the size.
 * Notice that the "INIT" code fragment is quite different
 * from other caches.  When auth_domain_lookup might be
 * creating a new domain, the new domain is passed in
 * complete and it is used as-is rather than being copied into
 * another structure.
 */
#define	DN_HASHBITS	6
#define	DN_HASHMAX	(1<<DN_HASHBITS)
#define	DN_HASHMASK	(DN_HASHMAX-1)

static struct cache_head	*auth_domain_table[DN_HASHMAX];

static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd)
{
	struct auth_domain *dom = container_of(item, struct auth_domain, h);
	if (cache_put(item,cd))
		authtab[dom->flavour]->domain_release(dom);
}


struct cache_detail auth_domain_cache = {
	.owner		= THIS_MODULE,
	.hash_size	= DN_HASHMAX,
	.hash_table	= auth_domain_table,
	.name		= "auth.domain",
	.cache_put	= auth_domain_drop,
};
static struct hlist_head	auth_domain_table[DN_HASHMAX];
static spinlock_t	auth_domain_lock = SPIN_LOCK_UNLOCKED;

void auth_domain_put(struct auth_domain *dom)
{
	auth_domain_drop(&dom->h, &auth_domain_cache);
}

static inline int auth_domain_hash(struct auth_domain *item)
{
	return hash_str(item->name, DN_HASHBITS);
	if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
		hlist_del(&dom->hash);
		dom->flavour->domain_release(dom);
	}
static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item)
{
	return strcmp(tmp->name, item->name) == 0;
}

struct auth_domain *
auth_domain_lookup(struct auth_domain *item, int set)
auth_domain_lookup(char *name, struct auth_domain *new)
{
	struct auth_domain *tmp = NULL;
	struct cache_head **hp, **head;
	head = &auth_domain_cache.hash_table[auth_domain_hash(item)];

	if (set)
		write_lock(&auth_domain_cache.hash_lock);
	else
		read_lock(&auth_domain_cache.hash_lock);
	for (hp=head; *hp != NULL; hp = &tmp->h.next) {
		tmp = container_of(*hp, struct auth_domain, h);
		if (!auth_domain_match(tmp, item))
			continue;
		if (!set) {
			cache_get(&tmp->h);
			goto out_noset;
	struct auth_domain *hp;
	struct hlist_head *head;
	struct hlist_node *np;

	head = &auth_domain_table[hash_str(name, DN_HASHBITS)];

	spin_lock(&auth_domain_lock);

	hlist_for_each_entry(hp, np, head, hash) {
		if (strcmp(hp->name, name)==0) {
			kref_get(&hp->ref);
			spin_unlock(&auth_domain_lock);
			return hp;
		}
	}
		*hp = tmp->h.next;
		tmp->h.next = NULL;
		auth_domain_drop(&tmp->h, &auth_domain_cache);
		goto out_set;
	if (new) {
		hlist_add_head(&new->hash, head);
		kref_get(&new->ref);
	}
	/* Didn't find anything */
	if (!set)
		goto out_nada;
	auth_domain_cache.entries++;
out_set:
	item->h.next = *head;
	*head = &item->h;
	cache_get(&item->h);
	write_unlock(&auth_domain_cache.hash_lock);
	cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time);
	cache_get(&item->h);
	return item;
out_nada:
	tmp = NULL;
out_noset:
	read_unlock(&auth_domain_cache.hash_lock);
	return tmp;
	spin_unlock(&auth_domain_lock);
	return new;
}

struct auth_domain *auth_domain_find(char *name)
{
	struct auth_domain *rv, ad;

	ad.name = name;
	rv = auth_domain_lookup(&ad, 0);
	return rv;
	return auth_domain_lookup(name, NULL);
}
Loading