diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/Kconfig | 1 | ||||
| -rw-r--r-- | net/Makefile | 1 | ||||
| -rw-r--r-- | net/dns_resolver/Kconfig | 27 | ||||
| -rw-r--r-- | net/dns_resolver/Makefile | 7 | ||||
| -rw-r--r-- | net/dns_resolver/dns_key.c | 211 | ||||
| -rw-r--r-- | net/dns_resolver/dns_query.c | 160 | ||||
| -rw-r--r-- | net/dns_resolver/internal.h | 44 | ||||
| -rw-r--r-- | net/sunrpc/auth.c | 157 | ||||
| -rw-r--r-- | net/sunrpc/auth_generic.c | 23 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 29 | ||||
| -rw-r--r-- | net/sunrpc/auth_null.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/auth_unix.c | 21 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 8 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 182 | ||||
| -rw-r--r-- | net/sunrpc/sched.c | 104 | ||||
| -rw-r--r-- | net/sunrpc/sunrpc_syms.c | 16 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 3 |
17 files changed, 759 insertions, 237 deletions
diff --git a/net/Kconfig b/net/Kconfig index e24fa0873f32..e330594d3709 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
| @@ -213,6 +213,7 @@ source "net/phonet/Kconfig" | |||
| 213 | source "net/ieee802154/Kconfig" | 213 | source "net/ieee802154/Kconfig" |
| 214 | source "net/sched/Kconfig" | 214 | source "net/sched/Kconfig" |
| 215 | source "net/dcb/Kconfig" | 215 | source "net/dcb/Kconfig" |
| 216 | source "net/dns_resolver/Kconfig" | ||
| 216 | 217 | ||
| 217 | config RPS | 218 | config RPS |
| 218 | boolean | 219 | boolean |
diff --git a/net/Makefile b/net/Makefile index 41d420070a38..ea60fbce9b1b 100644 --- a/net/Makefile +++ b/net/Makefile | |||
| @@ -67,3 +67,4 @@ ifeq ($(CONFIG_NET),y) | |||
| 67 | obj-$(CONFIG_SYSCTL) += sysctl_net.o | 67 | obj-$(CONFIG_SYSCTL) += sysctl_net.o |
| 68 | endif | 68 | endif |
| 69 | obj-$(CONFIG_WIMAX) += wimax/ | 69 | obj-$(CONFIG_WIMAX) += wimax/ |
| 70 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ | ||
diff --git a/net/dns_resolver/Kconfig b/net/dns_resolver/Kconfig new file mode 100644 index 000000000000..50d49f7e0472 --- /dev/null +++ b/net/dns_resolver/Kconfig | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # | ||
| 2 | # Configuration for DNS Resolver | ||
| 3 | # | ||
| 4 | config DNS_RESOLVER | ||
| 5 | tristate "DNS Resolver support" | ||
| 6 | depends on NET && KEYS | ||
| 7 | help | ||
| 8 | Saying Y here will include support for the DNS Resolver key type | ||
| 9 | which can be used to make upcalls to perform DNS lookups in | ||
| 10 | userspace. | ||
| 11 | |||
| 12 | DNS Resolver is used to query DNS server for information. Examples | ||
| 13 | being resolving a UNC hostname element to an IP address for CIFS or | ||
| 14 | performing a DNS query for AFSDB records so that AFS can locate a | ||
| 15 | cell's volume location database servers. | ||
| 16 | |||
| 17 | DNS Resolver is used by the CIFS and AFS modules, and would support | ||
| 18 | SMB2 later. DNS Resolver is supported by the userspace upcall | ||
| 19 | helper "/sbin/dns.resolver" via /etc/request-key.conf. | ||
| 20 | |||
| 21 | See <file:Documentation/networking/dns_resolver.txt> for further | ||
| 22 | information. | ||
| 23 | |||
| 24 | To compile this as a module, choose M here: the module will be called | ||
| 25 | dnsresolver. | ||
| 26 | |||
| 27 | If unsure, say N. | ||
diff --git a/net/dns_resolver/Makefile b/net/dns_resolver/Makefile new file mode 100644 index 000000000000..c0ef4e71dc49 --- /dev/null +++ b/net/dns_resolver/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Linux DNS Resolver. | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_DNS_RESOLVER) += dns_resolver.o | ||
| 6 | |||
| 7 | dns_resolver-objs := dns_key.o dns_query.o | ||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c new file mode 100644 index 000000000000..400a04d5c9a1 --- /dev/null +++ b/net/dns_resolver/dns_key.c | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | /* Key type used to cache DNS lookups made by the kernel | ||
| 2 | * | ||
| 3 | * See Documentation/networking/dns_resolver.txt | ||
| 4 | * | ||
| 5 | * Copyright (c) 2007 Igor Mammedov | ||
| 6 | * Author(s): Igor Mammedov (niallain@gmail.com) | ||
| 7 | * Steve French (sfrench@us.ibm.com) | ||
| 8 | * Wang Lei (wang840925@gmail.com) | ||
| 9 | * David Howells (dhowells@redhat.com) | ||
| 10 | * | ||
| 11 | * This library is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU Lesser General Public License as published | ||
| 13 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This library is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 19 | * the GNU Lesser General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU Lesser General Public License | ||
| 22 | * along with this library; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 24 | */ | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/moduleparam.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/string.h> | ||
| 29 | #include <linux/kernel.h> | ||
| 30 | #include <linux/keyctl.h> | ||
| 31 | #include <linux/err.h> | ||
| 32 | #include <keys/dns_resolver-type.h> | ||
| 33 | #include <keys/user-type.h> | ||
| 34 | #include "internal.h" | ||
| 35 | |||
| 36 | MODULE_DESCRIPTION("DNS Resolver"); | ||
| 37 | MODULE_AUTHOR("Wang Lei"); | ||
| 38 | MODULE_LICENSE("GPL"); | ||
| 39 | |||
| 40 | unsigned dns_resolver_debug; | ||
| 41 | module_param_named(debug, dns_resolver_debug, uint, S_IWUSR | S_IRUGO); | ||
| 42 | MODULE_PARM_DESC(debug, "DNS Resolver debugging mask"); | ||
| 43 | |||
| 44 | const struct cred *dns_resolver_cache; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Instantiate a user defined key for dns_resolver. | ||
| 48 | * | ||
| 49 | * The data must be a NUL-terminated string, with the NUL char accounted in | ||
| 50 | * datalen. | ||
| 51 | * | ||
| 52 | * If the data contains a '#' characters, then we take the clause after each | ||
| 53 | * one to be an option of the form 'key=value'. The actual data of interest is | ||
| 54 | * the string leading up to the first '#'. For instance: | ||
| 55 | * | ||
| 56 | * "ip1,ip2,...#foo=bar" | ||
| 57 | */ | ||
| 58 | static int | ||
| 59 | dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) | ||
| 60 | { | ||
| 61 | struct user_key_payload *upayload; | ||
| 62 | int ret; | ||
| 63 | size_t result_len = 0; | ||
| 64 | const char *data = _data, *opt; | ||
| 65 | |||
| 66 | kenter("%%%d,%s,'%s',%zu", | ||
| 67 | key->serial, key->description, data, datalen); | ||
| 68 | |||
| 69 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') | ||
| 70 | return -EINVAL; | ||
| 71 | datalen--; | ||
| 72 | |||
| 73 | /* deal with any options embedded in the data */ | ||
| 74 | opt = memchr(data, '#', datalen); | ||
| 75 | if (!opt) { | ||
| 76 | kdebug("no options currently supported"); | ||
| 77 | return -EINVAL; | ||
| 78 | } | ||
| 79 | |||
| 80 | result_len = datalen; | ||
| 81 | ret = key_payload_reserve(key, result_len); | ||
| 82 | if (ret < 0) | ||
| 83 | return -EINVAL; | ||
| 84 | |||
| 85 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); | ||
| 86 | if (!upayload) { | ||
| 87 | kleave(" = -ENOMEM"); | ||
| 88 | return -ENOMEM; | ||
| 89 | } | ||
| 90 | |||
| 91 | upayload->datalen = result_len; | ||
| 92 | memcpy(upayload->data, data, result_len); | ||
| 93 | upayload->data[result_len] = '\0'; | ||
| 94 | rcu_assign_pointer(key->payload.data, upayload); | ||
| 95 | |||
| 96 | kleave(" = 0"); | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | /* | ||
| 101 | * The description is of the form "[<type>:]<domain_name>" | ||
| 102 | * | ||
| 103 | * The domain name may be a simple name or an absolute domain name (which | ||
| 104 | * should end with a period). The domain name is case-independent. | ||
| 105 | */ | ||
| 106 | static int | ||
| 107 | dns_resolver_match(const struct key *key, const void *description) | ||
| 108 | { | ||
| 109 | int slen, dlen, ret = 0; | ||
| 110 | const char *src = key->description, *dsp = description; | ||
| 111 | |||
| 112 | kenter("%s,%s", src, dsp); | ||
| 113 | |||
| 114 | if (!src || !dsp) | ||
| 115 | goto no_match; | ||
| 116 | |||
| 117 | if (strcasecmp(src, dsp) == 0) | ||
| 118 | goto matched; | ||
| 119 | |||
| 120 | slen = strlen(src); | ||
| 121 | dlen = strlen(dsp); | ||
| 122 | if (slen <= 0 || dlen <= 0) | ||
| 123 | goto no_match; | ||
| 124 | if (src[slen - 1] == '.') | ||
| 125 | slen--; | ||
| 126 | if (dsp[dlen - 1] == '.') | ||
| 127 | dlen--; | ||
| 128 | if (slen != dlen || strncasecmp(src, dsp, slen) != 0) | ||
| 129 | goto no_match; | ||
| 130 | |||
| 131 | matched: | ||
| 132 | ret = 1; | ||
| 133 | no_match: | ||
| 134 | kleave(" = %d", ret); | ||
| 135 | return ret; | ||
| 136 | } | ||
| 137 | |||
| 138 | struct key_type key_type_dns_resolver = { | ||
| 139 | .name = "dns_resolver", | ||
| 140 | .instantiate = dns_resolver_instantiate, | ||
| 141 | .match = dns_resolver_match, | ||
| 142 | .revoke = user_revoke, | ||
| 143 | .destroy = user_destroy, | ||
| 144 | .describe = user_describe, | ||
| 145 | .read = user_read, | ||
| 146 | }; | ||
| 147 | |||
| 148 | static int __init init_dns_resolver(void) | ||
| 149 | { | ||
| 150 | struct cred *cred; | ||
| 151 | struct key *keyring; | ||
| 152 | int ret; | ||
| 153 | |||
| 154 | printk(KERN_NOTICE "Registering the %s key type\n", | ||
| 155 | key_type_dns_resolver.name); | ||
| 156 | |||
| 157 | /* create an override credential set with a special thread keyring in | ||
| 158 | * which DNS requests are cached | ||
| 159 | * | ||
| 160 | * this is used to prevent malicious redirections from being installed | ||
| 161 | * with add_key(). | ||
| 162 | */ | ||
| 163 | cred = prepare_kernel_cred(NULL); | ||
| 164 | if (!cred) | ||
| 165 | return -ENOMEM; | ||
| 166 | |||
| 167 | keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred, | ||
| 168 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
| 169 | KEY_USR_VIEW | KEY_USR_READ, | ||
| 170 | KEY_ALLOC_NOT_IN_QUOTA); | ||
| 171 | if (IS_ERR(keyring)) { | ||
| 172 | ret = PTR_ERR(keyring); | ||
| 173 | goto failed_put_cred; | ||
| 174 | } | ||
| 175 | |||
| 176 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
| 177 | if (ret < 0) | ||
| 178 | goto failed_put_key; | ||
| 179 | |||
| 180 | ret = register_key_type(&key_type_dns_resolver); | ||
| 181 | if (ret < 0) | ||
| 182 | goto failed_put_key; | ||
| 183 | |||
| 184 | /* instruct request_key() to use this special keyring as a cache for | ||
| 185 | * the results it looks up */ | ||
| 186 | cred->thread_keyring = keyring; | ||
| 187 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | ||
| 188 | dns_resolver_cache = cred; | ||
| 189 | |||
| 190 | kdebug("DNS resolver keyring: %d\n", key_serial(keyring)); | ||
| 191 | return 0; | ||
| 192 | |||
| 193 | failed_put_key: | ||
| 194 | key_put(keyring); | ||
| 195 | failed_put_cred: | ||
| 196 | put_cred(cred); | ||
| 197 | return ret; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void __exit exit_dns_resolver(void) | ||
| 201 | { | ||
| 202 | key_revoke(dns_resolver_cache->thread_keyring); | ||
| 203 | unregister_key_type(&key_type_dns_resolver); | ||
| 204 | put_cred(dns_resolver_cache); | ||
| 205 | printk(KERN_NOTICE "Unregistered %s key type\n", | ||
| 206 | key_type_dns_resolver.name); | ||
| 207 | } | ||
| 208 | |||
| 209 | module_init(init_dns_resolver) | ||
| 210 | module_exit(exit_dns_resolver) | ||
| 211 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c new file mode 100644 index 000000000000..03d5255f5cf2 --- /dev/null +++ b/net/dns_resolver/dns_query.c | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | /* Upcall routine, designed to work as a key type and working through | ||
| 2 | * /sbin/request-key to contact userspace when handling DNS queries. | ||
| 3 | * | ||
| 4 | * See Documentation/networking/dns_resolver.txt | ||
| 5 | * | ||
| 6 | * Copyright (c) 2007 Igor Mammedov | ||
| 7 | * Author(s): Igor Mammedov (niallain@gmail.com) | ||
| 8 | * Steve French (sfrench@us.ibm.com) | ||
| 9 | * Wang Lei (wang840925@gmail.com) | ||
| 10 | * David Howells (dhowells@redhat.com) | ||
| 11 | * | ||
| 12 | * The upcall wrapper used to make an arbitrary DNS query. | ||
| 13 | * | ||
| 14 | * This function requires the appropriate userspace tool dns.upcall to be | ||
| 15 | * installed and something like the following lines should be added to the | ||
| 16 | * /etc/request-key.conf file: | ||
| 17 | * | ||
| 18 | * create dns_resolver * * /sbin/dns.upcall %k | ||
| 19 | * | ||
| 20 | * For example to use this module to query AFSDB RR: | ||
| 21 | * | ||
| 22 | * create dns_resolver afsdb:* * /sbin/dns.afsdb %k | ||
| 23 | * | ||
| 24 | * This library is free software; you can redistribute it and/or modify | ||
| 25 | * it under the terms of the GNU Lesser General Public License as published | ||
| 26 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 27 | * (at your option) any later version. | ||
| 28 | * | ||
| 29 | * This library is distributed in the hope that it will be useful, | ||
| 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 32 | * the GNU Lesser General Public License for more details. | ||
| 33 | * | ||
| 34 | * You should have received a copy of the GNU Lesser General Public License | ||
| 35 | * along with this library; if not, write to the Free Software | ||
| 36 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 37 | */ | ||
| 38 | |||
| 39 | #include <linux/module.h> | ||
| 40 | #include <linux/slab.h> | ||
| 41 | #include <linux/dns_resolver.h> | ||
| 42 | #include <linux/err.h> | ||
| 43 | #include <keys/dns_resolver-type.h> | ||
| 44 | #include <keys/user-type.h> | ||
| 45 | |||
| 46 | #include "internal.h" | ||
| 47 | |||
| 48 | /** | ||
| 49 | * dns_query - Query the DNS | ||
| 50 | * @type: Query type (or NULL for straight host->IP lookup) | ||
| 51 | * @name: Name to look up | ||
| 52 | * @namelen: Length of name | ||
| 53 | * @options: Request options (or NULL if no options) | ||
| 54 | * @_result: Where to place the returned data. | ||
| 55 | * @_expiry: Where to store the result expiry time (or NULL) | ||
| 56 | * | ||
| 57 | * The data will be returned in the pointer at *result, and the caller is | ||
| 58 | * responsible for freeing it. | ||
| 59 | * | ||
| 60 | * The description should be of the form "[<query_type>:]<domain_name>", and | ||
| 61 | * the options need to be appropriate for the query type requested. If no | ||
| 62 | * query_type is given, then the query is a straight hostname to IP address | ||
| 63 | * lookup. | ||
| 64 | * | ||
| 65 | * The DNS resolution lookup is performed by upcalling to userspace by way of | ||
| 66 | * requesting a key of type dns_resolver. | ||
| 67 | * | ||
| 68 | * Returns the size of the result on success, -ve error code otherwise. | ||
| 69 | */ | ||
| 70 | int dns_query(const char *type, const char *name, size_t namelen, | ||
| 71 | const char *options, char **_result, time_t *_expiry) | ||
| 72 | { | ||
| 73 | struct key *rkey; | ||
| 74 | struct user_key_payload *upayload; | ||
| 75 | const struct cred *saved_cred; | ||
| 76 | size_t typelen, desclen; | ||
| 77 | char *desc, *cp; | ||
| 78 | int ret, len; | ||
| 79 | |||
| 80 | kenter("%s,%*.*s,%zu,%s", | ||
| 81 | type, (int)namelen, (int)namelen, name, namelen, options); | ||
| 82 | |||
| 83 | if (!name || namelen == 0 || !_result) | ||
| 84 | return -EINVAL; | ||
| 85 | |||
| 86 | /* construct the query key description as "[<type>:]<name>" */ | ||
| 87 | typelen = 0; | ||
| 88 | desclen = 0; | ||
| 89 | if (type) { | ||
| 90 | typelen = strlen(type); | ||
| 91 | if (typelen < 1) | ||
| 92 | return -EINVAL; | ||
| 93 | desclen += typelen + 1; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (!namelen) | ||
| 97 | namelen = strlen(name); | ||
| 98 | if (namelen < 3) | ||
| 99 | return -EINVAL; | ||
| 100 | desclen += namelen + 1; | ||
| 101 | |||
| 102 | desc = kmalloc(desclen, GFP_KERNEL); | ||
| 103 | if (!desc) | ||
| 104 | return -ENOMEM; | ||
| 105 | |||
| 106 | cp = desc; | ||
| 107 | if (type) { | ||
| 108 | memcpy(cp, type, typelen); | ||
| 109 | cp += typelen; | ||
| 110 | *cp++ = ':'; | ||
| 111 | } | ||
| 112 | memcpy(cp, name, namelen); | ||
| 113 | cp += namelen; | ||
| 114 | *cp = '\0'; | ||
| 115 | |||
| 116 | if (!options) | ||
| 117 | options = ""; | ||
| 118 | kdebug("call request_key(,%s,%s)", desc, options); | ||
| 119 | |||
| 120 | /* make the upcall, using special credentials to prevent the use of | ||
| 121 | * add_key() to preinstall malicious redirections | ||
| 122 | */ | ||
| 123 | saved_cred = override_creds(dns_resolver_cache); | ||
| 124 | rkey = request_key(&key_type_dns_resolver, desc, options); | ||
| 125 | revert_creds(saved_cred); | ||
| 126 | kfree(desc); | ||
| 127 | if (IS_ERR(rkey)) { | ||
| 128 | ret = PTR_ERR(rkey); | ||
| 129 | goto out; | ||
| 130 | } | ||
| 131 | |||
| 132 | down_read(&rkey->sem); | ||
| 133 | rkey->perm |= KEY_USR_VIEW; | ||
| 134 | |||
| 135 | ret = key_validate(rkey); | ||
| 136 | if (ret < 0) | ||
| 137 | goto put; | ||
| 138 | |||
| 139 | upayload = rcu_dereference_protected(rkey->payload.data, | ||
| 140 | lockdep_is_held(&rkey->sem)); | ||
| 141 | len = upayload->datalen; | ||
| 142 | |||
| 143 | ret = -ENOMEM; | ||
| 144 | *_result = kmalloc(len + 1, GFP_KERNEL); | ||
| 145 | if (!*_result) | ||
| 146 | goto put; | ||
| 147 | |||
| 148 | memcpy(*_result, upayload->data, len + 1); | ||
| 149 | if (_expiry) | ||
| 150 | *_expiry = rkey->expiry; | ||
| 151 | |||
| 152 | ret = len; | ||
| 153 | put: | ||
| 154 | up_read(&rkey->sem); | ||
| 155 | key_put(rkey); | ||
| 156 | out: | ||
| 157 | kleave(" = %d", ret); | ||
| 158 | return ret; | ||
| 159 | } | ||
| 160 | EXPORT_SYMBOL(dns_query); | ||
diff --git a/net/dns_resolver/internal.h b/net/dns_resolver/internal.h new file mode 100644 index 000000000000..189ca9e9b785 --- /dev/null +++ b/net/dns_resolver/internal.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 Wang Lei | ||
| 3 | * Author(s): Wang Lei (wang840925@gmail.com). All Rights Reserved. | ||
| 4 | * | ||
| 5 | * Internal DNS Rsolver stuff | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as published | ||
| 9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This library is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 15 | * the GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/compiler.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/sched.h> | ||
| 25 | |||
| 26 | /* | ||
| 27 | * dns_key.c | ||
| 28 | */ | ||
| 29 | extern const struct cred *dns_resolver_cache; | ||
| 30 | |||
| 31 | /* | ||
| 32 | * debug tracing | ||
| 33 | */ | ||
| 34 | extern unsigned dns_resolver_debug; | ||
| 35 | |||
| 36 | #define kdebug(FMT, ...) \ | ||
| 37 | do { \ | ||
| 38 | if (unlikely(dns_resolver_debug)) \ | ||
| 39 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", \ | ||
| 40 | current->comm, ##__VA_ARGS__); \ | ||
| 41 | } while (0) | ||
| 42 | |||
| 43 | #define kenter(FMT, ...) kdebug("==> %s("FMT")", __func__, ##__VA_ARGS__) | ||
| 44 | #define kleave(FMT, ...) kdebug("<== %s()"FMT"", __func__, ##__VA_ARGS__) | ||
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 8dc47f1d0001..880d0de3f50f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -19,6 +19,15 @@ | |||
| 19 | # define RPCDBG_FACILITY RPCDBG_AUTH | 19 | # define RPCDBG_FACILITY RPCDBG_AUTH |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #define RPC_CREDCACHE_DEFAULT_HASHBITS (4) | ||
| 23 | struct rpc_cred_cache { | ||
| 24 | struct hlist_head *hashtable; | ||
| 25 | unsigned int hashbits; | ||
| 26 | spinlock_t lock; | ||
| 27 | }; | ||
| 28 | |||
| 29 | static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS; | ||
| 30 | |||
| 22 | static DEFINE_SPINLOCK(rpc_authflavor_lock); | 31 | static DEFINE_SPINLOCK(rpc_authflavor_lock); |
| 23 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | 32 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { |
| 24 | &authnull_ops, /* AUTH_NULL */ | 33 | &authnull_ops, /* AUTH_NULL */ |
| @@ -29,6 +38,42 @@ static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | |||
| 29 | static LIST_HEAD(cred_unused); | 38 | static LIST_HEAD(cred_unused); |
| 30 | static unsigned long number_cred_unused; | 39 | static unsigned long number_cred_unused; |
| 31 | 40 | ||
| 41 | #define MAX_HASHTABLE_BITS (10) | ||
| 42 | static int param_set_hashtbl_sz(const char *val, struct kernel_param *kp) | ||
| 43 | { | ||
| 44 | unsigned long num; | ||
| 45 | unsigned int nbits; | ||
| 46 | int ret; | ||
| 47 | |||
| 48 | if (!val) | ||
| 49 | goto out_inval; | ||
| 50 | ret = strict_strtoul(val, 0, &num); | ||
| 51 | if (ret == -EINVAL) | ||
| 52 | goto out_inval; | ||
| 53 | nbits = fls(num); | ||
| 54 | if (num > (1U << nbits)) | ||
| 55 | nbits++; | ||
| 56 | if (nbits > MAX_HASHTABLE_BITS || nbits < 2) | ||
| 57 | goto out_inval; | ||
| 58 | *(unsigned int *)kp->arg = nbits; | ||
| 59 | return 0; | ||
| 60 | out_inval: | ||
| 61 | return -EINVAL; | ||
| 62 | } | ||
| 63 | |||
| 64 | static int param_get_hashtbl_sz(char *buffer, struct kernel_param *kp) | ||
| 65 | { | ||
| 66 | unsigned int nbits; | ||
| 67 | |||
| 68 | nbits = *(unsigned int *)kp->arg; | ||
| 69 | return sprintf(buffer, "%u", 1U << nbits); | ||
| 70 | } | ||
| 71 | |||
| 72 | #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int); | ||
| 73 | |||
| 74 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); | ||
| 75 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | ||
| 76 | |||
| 32 | static u32 | 77 | static u32 |
| 33 | pseudoflavor_to_flavor(u32 flavor) { | 78 | pseudoflavor_to_flavor(u32 flavor) { |
| 34 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 79 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
| @@ -145,16 +190,23 @@ int | |||
| 145 | rpcauth_init_credcache(struct rpc_auth *auth) | 190 | rpcauth_init_credcache(struct rpc_auth *auth) |
| 146 | { | 191 | { |
| 147 | struct rpc_cred_cache *new; | 192 | struct rpc_cred_cache *new; |
| 148 | int i; | 193 | unsigned int hashsize; |
| 149 | 194 | ||
| 150 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 195 | new = kmalloc(sizeof(*new), GFP_KERNEL); |
| 151 | if (!new) | 196 | if (!new) |
| 152 | return -ENOMEM; | 197 | goto out_nocache; |
| 153 | for (i = 0; i < RPC_CREDCACHE_NR; i++) | 198 | new->hashbits = auth_hashbits; |
| 154 | INIT_HLIST_HEAD(&new->hashtable[i]); | 199 | hashsize = 1U << new->hashbits; |
| 200 | new->hashtable = kcalloc(hashsize, sizeof(new->hashtable[0]), GFP_KERNEL); | ||
| 201 | if (!new->hashtable) | ||
| 202 | goto out_nohashtbl; | ||
| 155 | spin_lock_init(&new->lock); | 203 | spin_lock_init(&new->lock); |
| 156 | auth->au_credcache = new; | 204 | auth->au_credcache = new; |
| 157 | return 0; | 205 | return 0; |
| 206 | out_nohashtbl: | ||
| 207 | kfree(new); | ||
| 208 | out_nocache: | ||
| 209 | return -ENOMEM; | ||
| 158 | } | 210 | } |
| 159 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); | 211 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); |
| 160 | 212 | ||
| @@ -183,11 +235,12 @@ rpcauth_clear_credcache(struct rpc_cred_cache *cache) | |||
| 183 | LIST_HEAD(free); | 235 | LIST_HEAD(free); |
| 184 | struct hlist_head *head; | 236 | struct hlist_head *head; |
| 185 | struct rpc_cred *cred; | 237 | struct rpc_cred *cred; |
| 238 | unsigned int hashsize = 1U << cache->hashbits; | ||
| 186 | int i; | 239 | int i; |
| 187 | 240 | ||
| 188 | spin_lock(&rpc_credcache_lock); | 241 | spin_lock(&rpc_credcache_lock); |
| 189 | spin_lock(&cache->lock); | 242 | spin_lock(&cache->lock); |
| 190 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | 243 | for (i = 0; i < hashsize; i++) { |
| 191 | head = &cache->hashtable[i]; | 244 | head = &cache->hashtable[i]; |
| 192 | while (!hlist_empty(head)) { | 245 | while (!hlist_empty(head)) { |
| 193 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | 246 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); |
| @@ -216,6 +269,7 @@ rpcauth_destroy_credcache(struct rpc_auth *auth) | |||
| 216 | if (cache) { | 269 | if (cache) { |
| 217 | auth->au_credcache = NULL; | 270 | auth->au_credcache = NULL; |
| 218 | rpcauth_clear_credcache(cache); | 271 | rpcauth_clear_credcache(cache); |
| 272 | kfree(cache->hashtable); | ||
| 219 | kfree(cache); | 273 | kfree(cache); |
| 220 | } | 274 | } |
| 221 | } | 275 | } |
| @@ -297,7 +351,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 297 | *entry, *new; | 351 | *entry, *new; |
| 298 | unsigned int nr; | 352 | unsigned int nr; |
| 299 | 353 | ||
| 300 | nr = hash_long(acred->uid, RPC_CREDCACHE_HASHBITS); | 354 | nr = hash_long(acred->uid, cache->hashbits); |
| 301 | 355 | ||
| 302 | rcu_read_lock(); | 356 | rcu_read_lock(); |
| 303 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { | 357 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { |
| @@ -390,16 +444,16 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | |||
| 390 | } | 444 | } |
| 391 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); | 445 | EXPORT_SYMBOL_GPL(rpcauth_init_cred); |
| 392 | 446 | ||
| 393 | void | 447 | struct rpc_cred * |
| 394 | rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) | 448 | rpcauth_generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) |
| 395 | { | 449 | { |
| 396 | task->tk_msg.rpc_cred = get_rpccred(cred); | ||
| 397 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, | 450 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, |
| 398 | cred->cr_auth->au_ops->au_name, cred); | 451 | cred->cr_auth->au_ops->au_name, cred); |
| 452 | return get_rpccred(cred); | ||
| 399 | } | 453 | } |
| 400 | EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred); | 454 | EXPORT_SYMBOL_GPL(rpcauth_generic_bind_cred); |
| 401 | 455 | ||
| 402 | static void | 456 | static struct rpc_cred * |
| 403 | rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) | 457 | rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) |
| 404 | { | 458 | { |
| 405 | struct rpc_auth *auth = task->tk_client->cl_auth; | 459 | struct rpc_auth *auth = task->tk_client->cl_auth; |
| @@ -407,45 +461,43 @@ rpcauth_bind_root_cred(struct rpc_task *task, int lookupflags) | |||
| 407 | .uid = 0, | 461 | .uid = 0, |
| 408 | .gid = 0, | 462 | .gid = 0, |
| 409 | }; | 463 | }; |
| 410 | struct rpc_cred *ret; | ||
| 411 | 464 | ||
| 412 | dprintk("RPC: %5u looking up %s cred\n", | 465 | dprintk("RPC: %5u looking up %s cred\n", |
| 413 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); | 466 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); |
| 414 | ret = auth->au_ops->lookup_cred(auth, &acred, lookupflags); | 467 | return auth->au_ops->lookup_cred(auth, &acred, lookupflags); |
| 415 | if (!IS_ERR(ret)) | ||
| 416 | task->tk_msg.rpc_cred = ret; | ||
| 417 | else | ||
| 418 | task->tk_status = PTR_ERR(ret); | ||
| 419 | } | 468 | } |
| 420 | 469 | ||
| 421 | static void | 470 | static struct rpc_cred * |
| 422 | rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) | 471 | rpcauth_bind_new_cred(struct rpc_task *task, int lookupflags) |
| 423 | { | 472 | { |
| 424 | struct rpc_auth *auth = task->tk_client->cl_auth; | 473 | struct rpc_auth *auth = task->tk_client->cl_auth; |
| 425 | struct rpc_cred *ret; | ||
| 426 | 474 | ||
| 427 | dprintk("RPC: %5u looking up %s cred\n", | 475 | dprintk("RPC: %5u looking up %s cred\n", |
| 428 | task->tk_pid, auth->au_ops->au_name); | 476 | task->tk_pid, auth->au_ops->au_name); |
| 429 | ret = rpcauth_lookupcred(auth, lookupflags); | 477 | return rpcauth_lookupcred(auth, lookupflags); |
| 430 | if (!IS_ERR(ret)) | ||
| 431 | task->tk_msg.rpc_cred = ret; | ||
| 432 | else | ||
| 433 | task->tk_status = PTR_ERR(ret); | ||
| 434 | } | 478 | } |
| 435 | 479 | ||
| 436 | void | 480 | static int |
| 437 | rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags) | 481 | rpcauth_bindcred(struct rpc_task *task, struct rpc_cred *cred, int flags) |
| 438 | { | 482 | { |
| 483 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 484 | struct rpc_cred *new; | ||
| 439 | int lookupflags = 0; | 485 | int lookupflags = 0; |
| 440 | 486 | ||
| 441 | if (flags & RPC_TASK_ASYNC) | 487 | if (flags & RPC_TASK_ASYNC) |
| 442 | lookupflags |= RPCAUTH_LOOKUP_NEW; | 488 | lookupflags |= RPCAUTH_LOOKUP_NEW; |
| 443 | if (cred != NULL) | 489 | if (cred != NULL) |
| 444 | cred->cr_ops->crbind(task, cred, lookupflags); | 490 | new = cred->cr_ops->crbind(task, cred, lookupflags); |
| 445 | else if (flags & RPC_TASK_ROOTCREDS) | 491 | else if (flags & RPC_TASK_ROOTCREDS) |
| 446 | rpcauth_bind_root_cred(task, lookupflags); | 492 | new = rpcauth_bind_root_cred(task, lookupflags); |
| 447 | else | 493 | else |
| 448 | rpcauth_bind_new_cred(task, lookupflags); | 494 | new = rpcauth_bind_new_cred(task, lookupflags); |
| 495 | if (IS_ERR(new)) | ||
| 496 | return PTR_ERR(new); | ||
| 497 | if (req->rq_cred != NULL) | ||
| 498 | put_rpccred(req->rq_cred); | ||
| 499 | req->rq_cred = new; | ||
| 500 | return 0; | ||
| 449 | } | 501 | } |
| 450 | 502 | ||
| 451 | void | 503 | void |
| @@ -484,22 +536,10 @@ out_nodestroy: | |||
| 484 | } | 536 | } |
| 485 | EXPORT_SYMBOL_GPL(put_rpccred); | 537 | EXPORT_SYMBOL_GPL(put_rpccred); |
| 486 | 538 | ||
| 487 | void | ||
| 488 | rpcauth_unbindcred(struct rpc_task *task) | ||
| 489 | { | ||
| 490 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | ||
| 491 | |||
| 492 | dprintk("RPC: %5u releasing %s cred %p\n", | ||
| 493 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | ||
| 494 | |||
| 495 | put_rpccred(cred); | ||
| 496 | task->tk_msg.rpc_cred = NULL; | ||
| 497 | } | ||
| 498 | |||
| 499 | __be32 * | 539 | __be32 * |
| 500 | rpcauth_marshcred(struct rpc_task *task, __be32 *p) | 540 | rpcauth_marshcred(struct rpc_task *task, __be32 *p) |
| 501 | { | 541 | { |
| 502 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 542 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 503 | 543 | ||
| 504 | dprintk("RPC: %5u marshaling %s cred %p\n", | 544 | dprintk("RPC: %5u marshaling %s cred %p\n", |
| 505 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 545 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
| @@ -510,7 +550,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p) | |||
| 510 | __be32 * | 550 | __be32 * |
| 511 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) | 551 | rpcauth_checkverf(struct rpc_task *task, __be32 *p) |
| 512 | { | 552 | { |
| 513 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 553 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 514 | 554 | ||
| 515 | dprintk("RPC: %5u validating %s cred %p\n", | 555 | dprintk("RPC: %5u validating %s cred %p\n", |
| 516 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 556 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
| @@ -522,7 +562,7 @@ int | |||
| 522 | rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, | 562 | rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, |
| 523 | __be32 *data, void *obj) | 563 | __be32 *data, void *obj) |
| 524 | { | 564 | { |
| 525 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 565 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 526 | 566 | ||
| 527 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", | 567 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", |
| 528 | task->tk_pid, cred->cr_ops->cr_name, cred); | 568 | task->tk_pid, cred->cr_ops->cr_name, cred); |
| @@ -536,7 +576,7 @@ int | |||
| 536 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | 576 | rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, |
| 537 | __be32 *data, void *obj) | 577 | __be32 *data, void *obj) |
| 538 | { | 578 | { |
| 539 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 579 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 540 | 580 | ||
| 541 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", | 581 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", |
| 542 | task->tk_pid, cred->cr_ops->cr_name, cred); | 582 | task->tk_pid, cred->cr_ops->cr_name, cred); |
| @@ -550,13 +590,21 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | |||
| 550 | int | 590 | int |
| 551 | rpcauth_refreshcred(struct rpc_task *task) | 591 | rpcauth_refreshcred(struct rpc_task *task) |
| 552 | { | 592 | { |
| 553 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 593 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 554 | int err; | 594 | int err; |
| 555 | 595 | ||
| 596 | cred = task->tk_rqstp->rq_cred; | ||
| 597 | if (cred == NULL) { | ||
| 598 | err = rpcauth_bindcred(task, task->tk_msg.rpc_cred, task->tk_flags); | ||
| 599 | if (err < 0) | ||
| 600 | goto out; | ||
| 601 | cred = task->tk_rqstp->rq_cred; | ||
| 602 | }; | ||
| 556 | dprintk("RPC: %5u refreshing %s cred %p\n", | 603 | dprintk("RPC: %5u refreshing %s cred %p\n", |
| 557 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 604 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
| 558 | 605 | ||
| 559 | err = cred->cr_ops->crrefresh(task); | 606 | err = cred->cr_ops->crrefresh(task); |
| 607 | out: | ||
| 560 | if (err < 0) | 608 | if (err < 0) |
| 561 | task->tk_status = err; | 609 | task->tk_status = err; |
| 562 | return err; | 610 | return err; |
| @@ -565,7 +613,7 @@ rpcauth_refreshcred(struct rpc_task *task) | |||
| 565 | void | 613 | void |
| 566 | rpcauth_invalcred(struct rpc_task *task) | 614 | rpcauth_invalcred(struct rpc_task *task) |
| 567 | { | 615 | { |
| 568 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 616 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 569 | 617 | ||
| 570 | dprintk("RPC: %5u invalidating %s cred %p\n", | 618 | dprintk("RPC: %5u invalidating %s cred %p\n", |
| 571 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | 619 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
| @@ -576,7 +624,7 @@ rpcauth_invalcred(struct rpc_task *task) | |||
| 576 | int | 624 | int |
| 577 | rpcauth_uptodatecred(struct rpc_task *task) | 625 | rpcauth_uptodatecred(struct rpc_task *task) |
| 578 | { | 626 | { |
| 579 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 627 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 580 | 628 | ||
| 581 | return cred == NULL || | 629 | return cred == NULL || |
| 582 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; | 630 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; |
| @@ -587,14 +635,27 @@ static struct shrinker rpc_cred_shrinker = { | |||
| 587 | .seeks = DEFAULT_SEEKS, | 635 | .seeks = DEFAULT_SEEKS, |
| 588 | }; | 636 | }; |
| 589 | 637 | ||
| 590 | void __init rpcauth_init_module(void) | 638 | int __init rpcauth_init_module(void) |
| 591 | { | 639 | { |
| 592 | rpc_init_authunix(); | 640 | int err; |
| 593 | rpc_init_generic_auth(); | 641 | |
| 642 | err = rpc_init_authunix(); | ||
| 643 | if (err < 0) | ||
| 644 | goto out1; | ||
| 645 | err = rpc_init_generic_auth(); | ||
| 646 | if (err < 0) | ||
| 647 | goto out2; | ||
| 594 | register_shrinker(&rpc_cred_shrinker); | 648 | register_shrinker(&rpc_cred_shrinker); |
| 649 | return 0; | ||
| 650 | out2: | ||
| 651 | rpc_destroy_authunix(); | ||
| 652 | out1: | ||
| 653 | return err; | ||
| 595 | } | 654 | } |
| 596 | 655 | ||
| 597 | void __exit rpcauth_remove_module(void) | 656 | void __exit rpcauth_remove_module(void) |
| 598 | { | 657 | { |
| 658 | rpc_destroy_authunix(); | ||
| 659 | rpc_destroy_generic_auth(); | ||
| 599 | unregister_shrinker(&rpc_cred_shrinker); | 660 | unregister_shrinker(&rpc_cred_shrinker); |
| 600 | } | 661 | } |
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index 8f623b0f03dd..43162bb3b78f 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
| @@ -27,7 +27,6 @@ struct generic_cred { | |||
| 27 | }; | 27 | }; |
| 28 | 28 | ||
| 29 | static struct rpc_auth generic_auth; | 29 | static struct rpc_auth generic_auth; |
| 30 | static struct rpc_cred_cache generic_cred_cache; | ||
| 31 | static const struct rpc_credops generic_credops; | 30 | static const struct rpc_credops generic_credops; |
| 32 | 31 | ||
| 33 | /* | 32 | /* |
| @@ -55,18 +54,13 @@ struct rpc_cred *rpc_lookup_machine_cred(void) | |||
| 55 | } | 54 | } |
| 56 | EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); | 55 | EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); |
| 57 | 56 | ||
| 58 | static void | 57 | static struct rpc_cred *generic_bind_cred(struct rpc_task *task, |
| 59 | generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred, int lookupflags) | 58 | struct rpc_cred *cred, int lookupflags) |
| 60 | { | 59 | { |
| 61 | struct rpc_auth *auth = task->tk_client->cl_auth; | 60 | struct rpc_auth *auth = task->tk_client->cl_auth; |
| 62 | struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; | 61 | struct auth_cred *acred = &container_of(cred, struct generic_cred, gc_base)->acred; |
| 63 | struct rpc_cred *ret; | ||
| 64 | 62 | ||
| 65 | ret = auth->au_ops->lookup_cred(auth, acred, lookupflags); | 63 | return auth->au_ops->lookup_cred(auth, acred, lookupflags); |
| 66 | if (!IS_ERR(ret)) | ||
| 67 | task->tk_msg.rpc_cred = ret; | ||
| 68 | else | ||
| 69 | task->tk_status = PTR_ERR(ret); | ||
| 70 | } | 64 | } |
| 71 | 65 | ||
| 72 | /* | 66 | /* |
| @@ -159,20 +153,16 @@ out_nomatch: | |||
| 159 | return 0; | 153 | return 0; |
| 160 | } | 154 | } |
| 161 | 155 | ||
| 162 | void __init rpc_init_generic_auth(void) | 156 | int __init rpc_init_generic_auth(void) |
| 163 | { | 157 | { |
| 164 | spin_lock_init(&generic_cred_cache.lock); | 158 | return rpcauth_init_credcache(&generic_auth); |
| 165 | } | 159 | } |
| 166 | 160 | ||
| 167 | void __exit rpc_destroy_generic_auth(void) | 161 | void __exit rpc_destroy_generic_auth(void) |
| 168 | { | 162 | { |
| 169 | rpcauth_clear_credcache(&generic_cred_cache); | 163 | rpcauth_destroy_credcache(&generic_auth); |
| 170 | } | 164 | } |
| 171 | 165 | ||
| 172 | static struct rpc_cred_cache generic_cred_cache = { | ||
| 173 | {{ NULL, },}, | ||
| 174 | }; | ||
| 175 | |||
| 176 | static const struct rpc_authops generic_auth_ops = { | 166 | static const struct rpc_authops generic_auth_ops = { |
| 177 | .owner = THIS_MODULE, | 167 | .owner = THIS_MODULE, |
| 178 | .au_name = "Generic", | 168 | .au_name = "Generic", |
| @@ -183,7 +173,6 @@ static const struct rpc_authops generic_auth_ops = { | |||
| 183 | static struct rpc_auth generic_auth = { | 173 | static struct rpc_auth generic_auth = { |
| 184 | .au_ops = &generic_auth_ops, | 174 | .au_ops = &generic_auth_ops, |
| 185 | .au_count = ATOMIC_INIT(0), | 175 | .au_count = ATOMIC_INIT(0), |
| 186 | .au_credcache = &generic_cred_cache, | ||
| 187 | }; | 176 | }; |
| 188 | 177 | ||
| 189 | static const struct rpc_credops generic_credops = { | 178 | static const struct rpc_credops generic_credops = { |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 8da2a0e68574..dcfc66bab2bb 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -373,7 +373,7 @@ gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss | |||
| 373 | static void | 373 | static void |
| 374 | gss_upcall_callback(struct rpc_task *task) | 374 | gss_upcall_callback(struct rpc_task *task) |
| 375 | { | 375 | { |
| 376 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, | 376 | struct gss_cred *gss_cred = container_of(task->tk_rqstp->rq_cred, |
| 377 | struct gss_cred, gc_base); | 377 | struct gss_cred, gc_base); |
| 378 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; | 378 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; |
| 379 | struct inode *inode = &gss_msg->inode->vfs_inode; | 379 | struct inode *inode = &gss_msg->inode->vfs_inode; |
| @@ -502,7 +502,7 @@ static void warn_gssd(void) | |||
| 502 | static inline int | 502 | static inline int |
| 503 | gss_refresh_upcall(struct rpc_task *task) | 503 | gss_refresh_upcall(struct rpc_task *task) |
| 504 | { | 504 | { |
| 505 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 505 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 506 | struct gss_auth *gss_auth = container_of(cred->cr_auth, | 506 | struct gss_auth *gss_auth = container_of(cred->cr_auth, |
| 507 | struct gss_auth, rpc_auth); | 507 | struct gss_auth, rpc_auth); |
| 508 | struct gss_cred *gss_cred = container_of(cred, | 508 | struct gss_cred *gss_cred = container_of(cred, |
| @@ -928,6 +928,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx) | |||
| 928 | { | 928 | { |
| 929 | dprintk("RPC: gss_free_ctx\n"); | 929 | dprintk("RPC: gss_free_ctx\n"); |
| 930 | 930 | ||
| 931 | gss_delete_sec_context(&ctx->gc_gss_ctx); | ||
| 931 | kfree(ctx->gc_wire_ctx.data); | 932 | kfree(ctx->gc_wire_ctx.data); |
| 932 | kfree(ctx); | 933 | kfree(ctx); |
| 933 | } | 934 | } |
| @@ -942,13 +943,7 @@ gss_free_ctx_callback(struct rcu_head *head) | |||
| 942 | static void | 943 | static void |
| 943 | gss_free_ctx(struct gss_cl_ctx *ctx) | 944 | gss_free_ctx(struct gss_cl_ctx *ctx) |
| 944 | { | 945 | { |
| 945 | struct gss_ctx *gc_gss_ctx; | ||
| 946 | |||
| 947 | gc_gss_ctx = rcu_dereference(ctx->gc_gss_ctx); | ||
| 948 | rcu_assign_pointer(ctx->gc_gss_ctx, NULL); | ||
| 949 | call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); | 946 | call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); |
| 950 | if (gc_gss_ctx) | ||
| 951 | gss_delete_sec_context(&gc_gss_ctx); | ||
| 952 | } | 947 | } |
| 953 | 948 | ||
| 954 | static void | 949 | static void |
| @@ -1064,12 +1059,12 @@ out: | |||
| 1064 | static __be32 * | 1059 | static __be32 * |
| 1065 | gss_marshal(struct rpc_task *task, __be32 *p) | 1060 | gss_marshal(struct rpc_task *task, __be32 *p) |
| 1066 | { | 1061 | { |
| 1067 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1062 | struct rpc_rqst *req = task->tk_rqstp; |
| 1063 | struct rpc_cred *cred = req->rq_cred; | ||
| 1068 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 1064 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
| 1069 | gc_base); | 1065 | gc_base); |
| 1070 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1066 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
| 1071 | __be32 *cred_len; | 1067 | __be32 *cred_len; |
| 1072 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 1073 | u32 maj_stat = 0; | 1068 | u32 maj_stat = 0; |
| 1074 | struct xdr_netobj mic; | 1069 | struct xdr_netobj mic; |
| 1075 | struct kvec iov; | 1070 | struct kvec iov; |
| @@ -1119,7 +1114,7 @@ out_put_ctx: | |||
| 1119 | 1114 | ||
| 1120 | static int gss_renew_cred(struct rpc_task *task) | 1115 | static int gss_renew_cred(struct rpc_task *task) |
| 1121 | { | 1116 | { |
| 1122 | struct rpc_cred *oldcred = task->tk_msg.rpc_cred; | 1117 | struct rpc_cred *oldcred = task->tk_rqstp->rq_cred; |
| 1123 | struct gss_cred *gss_cred = container_of(oldcred, | 1118 | struct gss_cred *gss_cred = container_of(oldcred, |
| 1124 | struct gss_cred, | 1119 | struct gss_cred, |
| 1125 | gc_base); | 1120 | gc_base); |
| @@ -1133,7 +1128,7 @@ static int gss_renew_cred(struct rpc_task *task) | |||
| 1133 | new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW); | 1128 | new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW); |
| 1134 | if (IS_ERR(new)) | 1129 | if (IS_ERR(new)) |
| 1135 | return PTR_ERR(new); | 1130 | return PTR_ERR(new); |
| 1136 | task->tk_msg.rpc_cred = new; | 1131 | task->tk_rqstp->rq_cred = new; |
| 1137 | put_rpccred(oldcred); | 1132 | put_rpccred(oldcred); |
| 1138 | return 0; | 1133 | return 0; |
| 1139 | } | 1134 | } |
| @@ -1161,7 +1156,7 @@ static int gss_cred_is_negative_entry(struct rpc_cred *cred) | |||
| 1161 | static int | 1156 | static int |
| 1162 | gss_refresh(struct rpc_task *task) | 1157 | gss_refresh(struct rpc_task *task) |
| 1163 | { | 1158 | { |
| 1164 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1159 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 1165 | int ret = 0; | 1160 | int ret = 0; |
| 1166 | 1161 | ||
| 1167 | if (gss_cred_is_negative_entry(cred)) | 1162 | if (gss_cred_is_negative_entry(cred)) |
| @@ -1172,7 +1167,7 @@ gss_refresh(struct rpc_task *task) | |||
| 1172 | ret = gss_renew_cred(task); | 1167 | ret = gss_renew_cred(task); |
| 1173 | if (ret < 0) | 1168 | if (ret < 0) |
| 1174 | goto out; | 1169 | goto out; |
| 1175 | cred = task->tk_msg.rpc_cred; | 1170 | cred = task->tk_rqstp->rq_cred; |
| 1176 | } | 1171 | } |
| 1177 | 1172 | ||
| 1178 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) | 1173 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) |
| @@ -1191,7 +1186,7 @@ gss_refresh_null(struct rpc_task *task) | |||
| 1191 | static __be32 * | 1186 | static __be32 * |
| 1192 | gss_validate(struct rpc_task *task, __be32 *p) | 1187 | gss_validate(struct rpc_task *task, __be32 *p) |
| 1193 | { | 1188 | { |
| 1194 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1189 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 1195 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1190 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
| 1196 | __be32 seq; | 1191 | __be32 seq; |
| 1197 | struct kvec iov; | 1192 | struct kvec iov; |
| @@ -1400,7 +1395,7 @@ static int | |||
| 1400 | gss_wrap_req(struct rpc_task *task, | 1395 | gss_wrap_req(struct rpc_task *task, |
| 1401 | kxdrproc_t encode, void *rqstp, __be32 *p, void *obj) | 1396 | kxdrproc_t encode, void *rqstp, __be32 *p, void *obj) |
| 1402 | { | 1397 | { |
| 1403 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1398 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 1404 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 1399 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
| 1405 | gc_base); | 1400 | gc_base); |
| 1406 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1401 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
| @@ -1503,7 +1498,7 @@ static int | |||
| 1503 | gss_unwrap_resp(struct rpc_task *task, | 1498 | gss_unwrap_resp(struct rpc_task *task, |
| 1504 | kxdrproc_t decode, void *rqstp, __be32 *p, void *obj) | 1499 | kxdrproc_t decode, void *rqstp, __be32 *p, void *obj) |
| 1505 | { | 1500 | { |
| 1506 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1501 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
| 1507 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 1502 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
| 1508 | gc_base); | 1503 | gc_base); |
| 1509 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1504 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index 1db618f56ecb..a5c36c01707b 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
| @@ -75,7 +75,7 @@ nul_marshal(struct rpc_task *task, __be32 *p) | |||
| 75 | static int | 75 | static int |
| 76 | nul_refresh(struct rpc_task *task) | 76 | nul_refresh(struct rpc_task *task) |
| 77 | { | 77 | { |
| 78 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | 78 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); |
| 79 | return 0; | 79 | return 0; |
| 80 | } | 80 | } |
| 81 | 81 | ||
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index aac2f8b4ee21..4cb70dc6e7ad 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
| @@ -29,7 +29,6 @@ struct unx_cred { | |||
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | static struct rpc_auth unix_auth; | 31 | static struct rpc_auth unix_auth; |
| 32 | static struct rpc_cred_cache unix_cred_cache; | ||
| 33 | static const struct rpc_credops unix_credops; | 32 | static const struct rpc_credops unix_credops; |
| 34 | 33 | ||
| 35 | static struct rpc_auth * | 34 | static struct rpc_auth * |
| @@ -141,7 +140,7 @@ static __be32 * | |||
| 141 | unx_marshal(struct rpc_task *task, __be32 *p) | 140 | unx_marshal(struct rpc_task *task, __be32 *p) |
| 142 | { | 141 | { |
| 143 | struct rpc_clnt *clnt = task->tk_client; | 142 | struct rpc_clnt *clnt = task->tk_client; |
| 144 | struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base); | 143 | struct unx_cred *cred = container_of(task->tk_rqstp->rq_cred, struct unx_cred, uc_base); |
| 145 | __be32 *base, *hold; | 144 | __be32 *base, *hold; |
| 146 | int i; | 145 | int i; |
| 147 | 146 | ||
| @@ -174,7 +173,7 @@ unx_marshal(struct rpc_task *task, __be32 *p) | |||
| 174 | static int | 173 | static int |
| 175 | unx_refresh(struct rpc_task *task) | 174 | unx_refresh(struct rpc_task *task) |
| 176 | { | 175 | { |
| 177 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | 176 | set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags); |
| 178 | return 0; | 177 | return 0; |
| 179 | } | 178 | } |
| 180 | 179 | ||
| @@ -197,15 +196,20 @@ unx_validate(struct rpc_task *task, __be32 *p) | |||
| 197 | printk("RPC: giant verf size: %u\n", size); | 196 | printk("RPC: giant verf size: %u\n", size); |
| 198 | return NULL; | 197 | return NULL; |
| 199 | } | 198 | } |
| 200 | task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2; | 199 | task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; |
| 201 | p += (size >> 2); | 200 | p += (size >> 2); |
| 202 | 201 | ||
| 203 | return p; | 202 | return p; |
| 204 | } | 203 | } |
| 205 | 204 | ||
| 206 | void __init rpc_init_authunix(void) | 205 | int __init rpc_init_authunix(void) |
| 207 | { | 206 | { |
| 208 | spin_lock_init(&unix_cred_cache.lock); | 207 | return rpcauth_init_credcache(&unix_auth); |
| 208 | } | ||
| 209 | |||
| 210 | void rpc_destroy_authunix(void) | ||
| 211 | { | ||
| 212 | rpcauth_destroy_credcache(&unix_auth); | ||
| 209 | } | 213 | } |
| 210 | 214 | ||
| 211 | const struct rpc_authops authunix_ops = { | 215 | const struct rpc_authops authunix_ops = { |
| @@ -219,17 +223,12 @@ const struct rpc_authops authunix_ops = { | |||
| 219 | }; | 223 | }; |
| 220 | 224 | ||
| 221 | static | 225 | static |
| 222 | struct rpc_cred_cache unix_cred_cache = { | ||
| 223 | }; | ||
| 224 | |||
| 225 | static | ||
| 226 | struct rpc_auth unix_auth = { | 226 | struct rpc_auth unix_auth = { |
| 227 | .au_cslack = UNX_WRITESLACK, | 227 | .au_cslack = UNX_WRITESLACK, |
| 228 | .au_rslack = 2, /* assume AUTH_NULL verf */ | 228 | .au_rslack = 2, /* assume AUTH_NULL verf */ |
| 229 | .au_ops = &authunix_ops, | 229 | .au_ops = &authunix_ops, |
| 230 | .au_flavor = RPC_AUTH_UNIX, | 230 | .au_flavor = RPC_AUTH_UNIX, |
| 231 | .au_count = ATOMIC_INIT(0), | 231 | .au_count = ATOMIC_INIT(0), |
| 232 | .au_credcache = &unix_cred_cache, | ||
| 233 | }; | 232 | }; |
| 234 | 233 | ||
| 235 | static | 234 | static |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 58de76c8540c..2b06410e584e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -34,7 +34,6 @@ | |||
| 34 | #include <linux/sunrpc/cache.h> | 34 | #include <linux/sunrpc/cache.h> |
| 35 | #include <linux/sunrpc/stats.h> | 35 | #include <linux/sunrpc/stats.h> |
| 36 | #include <linux/sunrpc/rpc_pipe_fs.h> | 36 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 37 | #include <linux/smp_lock.h> | ||
| 38 | 37 | ||
| 39 | #define RPCDBG_FACILITY RPCDBG_CACHE | 38 | #define RPCDBG_FACILITY RPCDBG_CACHE |
| 40 | 39 | ||
| @@ -320,7 +319,7 @@ static struct cache_detail *current_detail; | |||
| 320 | static int current_index; | 319 | static int current_index; |
| 321 | 320 | ||
| 322 | static void do_cache_clean(struct work_struct *work); | 321 | static void do_cache_clean(struct work_struct *work); |
| 323 | static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean); | 322 | static struct delayed_work cache_cleaner; |
| 324 | 323 | ||
| 325 | static void sunrpc_init_cache_detail(struct cache_detail *cd) | 324 | static void sunrpc_init_cache_detail(struct cache_detail *cd) |
| 326 | { | 325 | { |
| @@ -1504,6 +1503,11 @@ static int create_cache_proc_entries(struct cache_detail *cd) | |||
| 1504 | } | 1503 | } |
| 1505 | #endif | 1504 | #endif |
| 1506 | 1505 | ||
| 1506 | void __init cache_initialize(void) | ||
| 1507 | { | ||
| 1508 | INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean); | ||
| 1509 | } | ||
| 1510 | |||
| 1507 | int cache_register(struct cache_detail *cd) | 1511 | int cache_register(struct cache_detail *cd) |
| 1508 | { | 1512 | { |
| 1509 | int ret; | 1513 | int ret; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 756fc324db9e..2388d83b68ff 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -414,6 +414,35 @@ out_no_clnt: | |||
| 414 | EXPORT_SYMBOL_GPL(rpc_clone_client); | 414 | EXPORT_SYMBOL_GPL(rpc_clone_client); |
| 415 | 415 | ||
| 416 | /* | 416 | /* |
| 417 | * Kill all tasks for the given client. | ||
| 418 | * XXX: kill their descendants as well? | ||
| 419 | */ | ||
| 420 | void rpc_killall_tasks(struct rpc_clnt *clnt) | ||
| 421 | { | ||
| 422 | struct rpc_task *rovr; | ||
| 423 | |||
| 424 | |||
| 425 | if (list_empty(&clnt->cl_tasks)) | ||
| 426 | return; | ||
| 427 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
| 428 | /* | ||
| 429 | * Spin lock all_tasks to prevent changes... | ||
| 430 | */ | ||
| 431 | spin_lock(&clnt->cl_lock); | ||
| 432 | list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { | ||
| 433 | if (!RPC_IS_ACTIVATED(rovr)) | ||
| 434 | continue; | ||
| 435 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | ||
| 436 | rovr->tk_flags |= RPC_TASK_KILLED; | ||
| 437 | rpc_exit(rovr, -EIO); | ||
| 438 | rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | spin_unlock(&clnt->cl_lock); | ||
| 442 | } | ||
| 443 | EXPORT_SYMBOL_GPL(rpc_killall_tasks); | ||
| 444 | |||
| 445 | /* | ||
| 417 | * Properly shut down an RPC client, terminating all outstanding | 446 | * Properly shut down an RPC client, terminating all outstanding |
| 418 | * requests. | 447 | * requests. |
| 419 | */ | 448 | */ |
| @@ -538,6 +567,49 @@ out: | |||
| 538 | } | 567 | } |
| 539 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); | 568 | EXPORT_SYMBOL_GPL(rpc_bind_new_program); |
| 540 | 569 | ||
| 570 | void rpc_task_release_client(struct rpc_task *task) | ||
| 571 | { | ||
| 572 | struct rpc_clnt *clnt = task->tk_client; | ||
| 573 | |||
| 574 | if (clnt != NULL) { | ||
| 575 | /* Remove from client task list */ | ||
| 576 | spin_lock(&clnt->cl_lock); | ||
| 577 | list_del(&task->tk_task); | ||
| 578 | spin_unlock(&clnt->cl_lock); | ||
| 579 | task->tk_client = NULL; | ||
| 580 | |||
| 581 | rpc_release_client(clnt); | ||
| 582 | } | ||
| 583 | } | ||
| 584 | |||
| 585 | static | ||
| 586 | void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | ||
| 587 | { | ||
| 588 | if (clnt != NULL) { | ||
| 589 | rpc_task_release_client(task); | ||
| 590 | task->tk_client = clnt; | ||
| 591 | kref_get(&clnt->cl_kref); | ||
| 592 | if (clnt->cl_softrtry) | ||
| 593 | task->tk_flags |= RPC_TASK_SOFT; | ||
| 594 | /* Add to the client's list of all tasks */ | ||
| 595 | spin_lock(&clnt->cl_lock); | ||
| 596 | list_add_tail(&task->tk_task, &clnt->cl_tasks); | ||
| 597 | spin_unlock(&clnt->cl_lock); | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 601 | static void | ||
| 602 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) | ||
| 603 | { | ||
| 604 | if (msg != NULL) { | ||
| 605 | task->tk_msg.rpc_proc = msg->rpc_proc; | ||
| 606 | task->tk_msg.rpc_argp = msg->rpc_argp; | ||
| 607 | task->tk_msg.rpc_resp = msg->rpc_resp; | ||
| 608 | if (msg->rpc_cred != NULL) | ||
| 609 | task->tk_msg.rpc_cred = get_rpccred(msg->rpc_cred); | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 541 | /* | 613 | /* |
| 542 | * Default callback for async RPC calls | 614 | * Default callback for async RPC calls |
| 543 | */ | 615 | */ |
| @@ -562,6 +634,18 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) | |||
| 562 | if (IS_ERR(task)) | 634 | if (IS_ERR(task)) |
| 563 | goto out; | 635 | goto out; |
| 564 | 636 | ||
| 637 | rpc_task_set_client(task, task_setup_data->rpc_client); | ||
| 638 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); | ||
| 639 | |||
| 640 | if (task->tk_status != 0) { | ||
| 641 | int ret = task->tk_status; | ||
| 642 | rpc_put_task(task); | ||
| 643 | return ERR_PTR(ret); | ||
| 644 | } | ||
| 645 | |||
| 646 | if (task->tk_action == NULL) | ||
| 647 | rpc_call_start(task); | ||
| 648 | |||
| 565 | atomic_inc(&task->tk_count); | 649 | atomic_inc(&task->tk_count); |
| 566 | rpc_execute(task); | 650 | rpc_execute(task); |
| 567 | out: | 651 | out: |
| @@ -756,12 +840,13 @@ EXPORT_SYMBOL_GPL(rpc_force_rebind); | |||
| 756 | * Restart an (async) RPC call from the call_prepare state. | 840 | * Restart an (async) RPC call from the call_prepare state. |
| 757 | * Usually called from within the exit handler. | 841 | * Usually called from within the exit handler. |
| 758 | */ | 842 | */ |
| 759 | void | 843 | int |
| 760 | rpc_restart_call_prepare(struct rpc_task *task) | 844 | rpc_restart_call_prepare(struct rpc_task *task) |
| 761 | { | 845 | { |
| 762 | if (RPC_ASSASSINATED(task)) | 846 | if (RPC_ASSASSINATED(task)) |
| 763 | return; | 847 | return 0; |
| 764 | task->tk_action = rpc_prepare_task; | 848 | task->tk_action = rpc_prepare_task; |
| 849 | return 1; | ||
| 765 | } | 850 | } |
| 766 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | 851 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); |
| 767 | 852 | ||
| @@ -769,13 +854,13 @@ EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | |||
| 769 | * Restart an (async) RPC call. Usually called from within the | 854 | * Restart an (async) RPC call. Usually called from within the |
| 770 | * exit handler. | 855 | * exit handler. |
| 771 | */ | 856 | */ |
| 772 | void | 857 | int |
| 773 | rpc_restart_call(struct rpc_task *task) | 858 | rpc_restart_call(struct rpc_task *task) |
| 774 | { | 859 | { |
| 775 | if (RPC_ASSASSINATED(task)) | 860 | if (RPC_ASSASSINATED(task)) |
| 776 | return; | 861 | return 0; |
| 777 | |||
| 778 | task->tk_action = call_start; | 862 | task->tk_action = call_start; |
| 863 | return 1; | ||
| 779 | } | 864 | } |
| 780 | EXPORT_SYMBOL_GPL(rpc_restart_call); | 865 | EXPORT_SYMBOL_GPL(rpc_restart_call); |
| 781 | 866 | ||
| @@ -824,11 +909,6 @@ call_reserve(struct rpc_task *task) | |||
| 824 | { | 909 | { |
| 825 | dprint_status(task); | 910 | dprint_status(task); |
| 826 | 911 | ||
| 827 | if (!rpcauth_uptodatecred(task)) { | ||
| 828 | task->tk_action = call_refresh; | ||
| 829 | return; | ||
| 830 | } | ||
| 831 | |||
| 832 | task->tk_status = 0; | 912 | task->tk_status = 0; |
| 833 | task->tk_action = call_reserveresult; | 913 | task->tk_action = call_reserveresult; |
| 834 | xprt_reserve(task); | 914 | xprt_reserve(task); |
| @@ -892,7 +972,7 @@ call_reserveresult(struct rpc_task *task) | |||
| 892 | static void | 972 | static void |
| 893 | call_allocate(struct rpc_task *task) | 973 | call_allocate(struct rpc_task *task) |
| 894 | { | 974 | { |
| 895 | unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack; | 975 | unsigned int slack = task->tk_client->cl_auth->au_cslack; |
| 896 | struct rpc_rqst *req = task->tk_rqstp; | 976 | struct rpc_rqst *req = task->tk_rqstp; |
| 897 | struct rpc_xprt *xprt = task->tk_xprt; | 977 | struct rpc_xprt *xprt = task->tk_xprt; |
| 898 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; | 978 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; |
| @@ -900,7 +980,7 @@ call_allocate(struct rpc_task *task) | |||
| 900 | dprint_status(task); | 980 | dprint_status(task); |
| 901 | 981 | ||
| 902 | task->tk_status = 0; | 982 | task->tk_status = 0; |
| 903 | task->tk_action = call_bind; | 983 | task->tk_action = call_refresh; |
| 904 | 984 | ||
| 905 | if (req->rq_buffer) | 985 | if (req->rq_buffer) |
| 906 | return; | 986 | return; |
| @@ -937,6 +1017,47 @@ call_allocate(struct rpc_task *task) | |||
| 937 | rpc_exit(task, -ERESTARTSYS); | 1017 | rpc_exit(task, -ERESTARTSYS); |
| 938 | } | 1018 | } |
| 939 | 1019 | ||
| 1020 | /* | ||
| 1021 | * 2a. Bind and/or refresh the credentials | ||
| 1022 | */ | ||
| 1023 | static void | ||
| 1024 | call_refresh(struct rpc_task *task) | ||
| 1025 | { | ||
| 1026 | dprint_status(task); | ||
| 1027 | |||
| 1028 | task->tk_action = call_refreshresult; | ||
| 1029 | task->tk_status = 0; | ||
| 1030 | task->tk_client->cl_stats->rpcauthrefresh++; | ||
| 1031 | rpcauth_refreshcred(task); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | /* | ||
| 1035 | * 2b. Process the results of a credential refresh | ||
| 1036 | */ | ||
| 1037 | static void | ||
| 1038 | call_refreshresult(struct rpc_task *task) | ||
| 1039 | { | ||
| 1040 | int status = task->tk_status; | ||
| 1041 | |||
| 1042 | dprint_status(task); | ||
| 1043 | |||
| 1044 | task->tk_status = 0; | ||
| 1045 | task->tk_action = call_bind; | ||
| 1046 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
| 1047 | return; | ||
| 1048 | switch (status) { | ||
| 1049 | case -EACCES: | ||
| 1050 | rpc_exit(task, -EACCES); | ||
| 1051 | return; | ||
| 1052 | case -ENOMEM: | ||
| 1053 | rpc_exit(task, -ENOMEM); | ||
| 1054 | return; | ||
| 1055 | case -ETIMEDOUT: | ||
| 1056 | rpc_delay(task, 3*HZ); | ||
| 1057 | } | ||
| 1058 | task->tk_action = call_refresh; | ||
| 1059 | } | ||
| 1060 | |||
| 940 | static inline int | 1061 | static inline int |
| 941 | rpc_task_need_encode(struct rpc_task *task) | 1062 | rpc_task_need_encode(struct rpc_task *task) |
| 942 | { | 1063 | { |
| @@ -1472,43 +1593,6 @@ out_retry: | |||
| 1472 | } | 1593 | } |
| 1473 | } | 1594 | } |
| 1474 | 1595 | ||
| 1475 | /* | ||
| 1476 | * 8. Refresh the credentials if rejected by the server | ||
| 1477 | */ | ||
| 1478 | static void | ||
| 1479 | call_refresh(struct rpc_task *task) | ||
| 1480 | { | ||
| 1481 | dprint_status(task); | ||
| 1482 | |||
| 1483 | task->tk_action = call_refreshresult; | ||
| 1484 | task->tk_status = 0; | ||
| 1485 | task->tk_client->cl_stats->rpcauthrefresh++; | ||
| 1486 | rpcauth_refreshcred(task); | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /* | ||
| 1490 | * 8a. Process the results of a credential refresh | ||
| 1491 | */ | ||
| 1492 | static void | ||
| 1493 | call_refreshresult(struct rpc_task *task) | ||
| 1494 | { | ||
| 1495 | int status = task->tk_status; | ||
| 1496 | |||
| 1497 | dprint_status(task); | ||
| 1498 | |||
| 1499 | task->tk_status = 0; | ||
| 1500 | task->tk_action = call_reserve; | ||
| 1501 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
| 1502 | return; | ||
| 1503 | if (status == -EACCES) { | ||
| 1504 | rpc_exit(task, -EACCES); | ||
| 1505 | return; | ||
| 1506 | } | ||
| 1507 | task->tk_action = call_refresh; | ||
| 1508 | if (status != -ETIMEDOUT) | ||
| 1509 | rpc_delay(task, 3*HZ); | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | static __be32 * | 1596 | static __be32 * |
| 1513 | rpc_encode_header(struct rpc_task *task) | 1597 | rpc_encode_header(struct rpc_task *task) |
| 1514 | { | 1598 | { |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 4a843b883b89..cace6049e4a5 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -246,17 +246,8 @@ static inline void rpc_task_set_debuginfo(struct rpc_task *task) | |||
| 246 | 246 | ||
| 247 | static void rpc_set_active(struct rpc_task *task) | 247 | static void rpc_set_active(struct rpc_task *task) |
| 248 | { | 248 | { |
| 249 | struct rpc_clnt *clnt; | ||
| 250 | if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0) | ||
| 251 | return; | ||
| 252 | rpc_task_set_debuginfo(task); | 249 | rpc_task_set_debuginfo(task); |
| 253 | /* Add to global list of all tasks */ | 250 | set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); |
| 254 | clnt = task->tk_client; | ||
| 255 | if (clnt != NULL) { | ||
| 256 | spin_lock(&clnt->cl_lock); | ||
| 257 | list_add_tail(&task->tk_task, &clnt->cl_tasks); | ||
| 258 | spin_unlock(&clnt->cl_lock); | ||
| 259 | } | ||
| 260 | } | 251 | } |
| 261 | 252 | ||
| 262 | /* | 253 | /* |
| @@ -319,11 +310,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
| 319 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", | 310 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", |
| 320 | task->tk_pid, rpc_qname(q), jiffies); | 311 | task->tk_pid, rpc_qname(q), jiffies); |
| 321 | 312 | ||
| 322 | if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) { | ||
| 323 | printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n"); | ||
| 324 | return; | ||
| 325 | } | ||
| 326 | |||
| 327 | __rpc_add_wait_queue(q, task); | 313 | __rpc_add_wait_queue(q, task); |
| 328 | 314 | ||
| 329 | BUG_ON(task->tk_callback != NULL); | 315 | BUG_ON(task->tk_callback != NULL); |
| @@ -334,8 +320,8 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
| 334 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 320 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, |
| 335 | rpc_action action) | 321 | rpc_action action) |
| 336 | { | 322 | { |
| 337 | /* Mark the task as being activated if so needed */ | 323 | /* We shouldn't ever put an inactive task to sleep */ |
| 338 | rpc_set_active(task); | 324 | BUG_ON(!RPC_IS_ACTIVATED(task)); |
| 339 | 325 | ||
| 340 | /* | 326 | /* |
| 341 | * Protect the queue operations. | 327 | * Protect the queue operations. |
| @@ -406,14 +392,6 @@ void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task | |||
| 406 | EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); | 392 | EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); |
| 407 | 393 | ||
| 408 | /* | 394 | /* |
| 409 | * Wake up the specified task | ||
| 410 | */ | ||
| 411 | static void rpc_wake_up_task(struct rpc_task *task) | ||
| 412 | { | ||
| 413 | rpc_wake_up_queued_task(task->tk_waitqueue, task); | ||
| 414 | } | ||
| 415 | |||
| 416 | /* | ||
| 417 | * Wake up the next task on a priority queue. | 395 | * Wake up the next task on a priority queue. |
| 418 | */ | 396 | */ |
| 419 | static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) | 397 | static struct rpc_task * __rpc_wake_up_next_priority(struct rpc_wait_queue *queue) |
| @@ -600,7 +578,15 @@ void rpc_exit_task(struct rpc_task *task) | |||
| 600 | } | 578 | } |
| 601 | } | 579 | } |
| 602 | } | 580 | } |
| 603 | EXPORT_SYMBOL_GPL(rpc_exit_task); | 581 | |
| 582 | void rpc_exit(struct rpc_task *task, int status) | ||
| 583 | { | ||
| 584 | task->tk_status = status; | ||
| 585 | task->tk_action = rpc_exit_task; | ||
| 586 | if (RPC_IS_QUEUED(task)) | ||
| 587 | rpc_wake_up_queued_task(task->tk_waitqueue, task); | ||
| 588 | } | ||
| 589 | EXPORT_SYMBOL_GPL(rpc_exit); | ||
| 604 | 590 | ||
| 605 | void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) | 591 | void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) |
| 606 | { | 592 | { |
| @@ -690,7 +676,6 @@ static void __rpc_execute(struct rpc_task *task) | |||
| 690 | dprintk("RPC: %5u got signal\n", task->tk_pid); | 676 | dprintk("RPC: %5u got signal\n", task->tk_pid); |
| 691 | task->tk_flags |= RPC_TASK_KILLED; | 677 | task->tk_flags |= RPC_TASK_KILLED; |
| 692 | rpc_exit(task, -ERESTARTSYS); | 678 | rpc_exit(task, -ERESTARTSYS); |
| 693 | rpc_wake_up_task(task); | ||
| 694 | } | 679 | } |
| 695 | rpc_set_running(task); | 680 | rpc_set_running(task); |
| 696 | dprintk("RPC: %5u sync task resuming\n", task->tk_pid); | 681 | dprintk("RPC: %5u sync task resuming\n", task->tk_pid); |
| @@ -714,8 +699,9 @@ static void __rpc_execute(struct rpc_task *task) | |||
| 714 | void rpc_execute(struct rpc_task *task) | 699 | void rpc_execute(struct rpc_task *task) |
| 715 | { | 700 | { |
| 716 | rpc_set_active(task); | 701 | rpc_set_active(task); |
| 717 | rpc_set_running(task); | 702 | rpc_make_runnable(task); |
| 718 | __rpc_execute(task); | 703 | if (!RPC_IS_ASYNC(task)) |
| 704 | __rpc_execute(task); | ||
| 719 | } | 705 | } |
| 720 | 706 | ||
| 721 | static void rpc_async_schedule(struct work_struct *work) | 707 | static void rpc_async_schedule(struct work_struct *work) |
| @@ -808,26 +794,9 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
| 808 | /* Initialize workqueue for async tasks */ | 794 | /* Initialize workqueue for async tasks */ |
| 809 | task->tk_workqueue = task_setup_data->workqueue; | 795 | task->tk_workqueue = task_setup_data->workqueue; |
| 810 | 796 | ||
| 811 | task->tk_client = task_setup_data->rpc_client; | ||
| 812 | if (task->tk_client != NULL) { | ||
| 813 | kref_get(&task->tk_client->cl_kref); | ||
| 814 | if (task->tk_client->cl_softrtry) | ||
| 815 | task->tk_flags |= RPC_TASK_SOFT; | ||
| 816 | } | ||
| 817 | |||
| 818 | if (task->tk_ops->rpc_call_prepare != NULL) | 797 | if (task->tk_ops->rpc_call_prepare != NULL) |
| 819 | task->tk_action = rpc_prepare_task; | 798 | task->tk_action = rpc_prepare_task; |
| 820 | 799 | ||
| 821 | if (task_setup_data->rpc_message != NULL) { | ||
| 822 | task->tk_msg.rpc_proc = task_setup_data->rpc_message->rpc_proc; | ||
| 823 | task->tk_msg.rpc_argp = task_setup_data->rpc_message->rpc_argp; | ||
| 824 | task->tk_msg.rpc_resp = task_setup_data->rpc_message->rpc_resp; | ||
| 825 | /* Bind the user cred */ | ||
| 826 | rpcauth_bindcred(task, task_setup_data->rpc_message->rpc_cred, task_setup_data->flags); | ||
| 827 | if (task->tk_action == NULL) | ||
| 828 | rpc_call_start(task); | ||
| 829 | } | ||
| 830 | |||
| 831 | /* starting timestamp */ | 800 | /* starting timestamp */ |
| 832 | task->tk_start = ktime_get(); | 801 | task->tk_start = ktime_get(); |
| 833 | 802 | ||
| @@ -896,11 +865,8 @@ void rpc_put_task(struct rpc_task *task) | |||
| 896 | if (task->tk_rqstp) | 865 | if (task->tk_rqstp) |
| 897 | xprt_release(task); | 866 | xprt_release(task); |
| 898 | if (task->tk_msg.rpc_cred) | 867 | if (task->tk_msg.rpc_cred) |
| 899 | rpcauth_unbindcred(task); | 868 | put_rpccred(task->tk_msg.rpc_cred); |
| 900 | if (task->tk_client) { | 869 | rpc_task_release_client(task); |
| 901 | rpc_release_client(task->tk_client); | ||
| 902 | task->tk_client = NULL; | ||
| 903 | } | ||
| 904 | if (task->tk_workqueue != NULL) { | 870 | if (task->tk_workqueue != NULL) { |
| 905 | INIT_WORK(&task->u.tk_work, rpc_async_release); | 871 | INIT_WORK(&task->u.tk_work, rpc_async_release); |
| 906 | queue_work(task->tk_workqueue, &task->u.tk_work); | 872 | queue_work(task->tk_workqueue, &task->u.tk_work); |
| @@ -913,13 +879,6 @@ static void rpc_release_task(struct rpc_task *task) | |||
| 913 | { | 879 | { |
| 914 | dprintk("RPC: %5u release task\n", task->tk_pid); | 880 | dprintk("RPC: %5u release task\n", task->tk_pid); |
| 915 | 881 | ||
| 916 | if (!list_empty(&task->tk_task)) { | ||
| 917 | struct rpc_clnt *clnt = task->tk_client; | ||
| 918 | /* Remove from client task list */ | ||
| 919 | spin_lock(&clnt->cl_lock); | ||
| 920 | list_del(&task->tk_task); | ||
| 921 | spin_unlock(&clnt->cl_lock); | ||
| 922 | } | ||
| 923 | BUG_ON (RPC_IS_QUEUED(task)); | 882 | BUG_ON (RPC_IS_QUEUED(task)); |
| 924 | 883 | ||
| 925 | /* Wake up anyone who is waiting for task completion */ | 884 | /* Wake up anyone who is waiting for task completion */ |
| @@ -928,35 +887,6 @@ static void rpc_release_task(struct rpc_task *task) | |||
| 928 | rpc_put_task(task); | 887 | rpc_put_task(task); |
| 929 | } | 888 | } |
| 930 | 889 | ||
| 931 | /* | ||
| 932 | * Kill all tasks for the given client. | ||
| 933 | * XXX: kill their descendants as well? | ||
| 934 | */ | ||
| 935 | void rpc_killall_tasks(struct rpc_clnt *clnt) | ||
| 936 | { | ||
| 937 | struct rpc_task *rovr; | ||
| 938 | |||
| 939 | |||
| 940 | if (list_empty(&clnt->cl_tasks)) | ||
| 941 | return; | ||
| 942 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
| 943 | /* | ||
| 944 | * Spin lock all_tasks to prevent changes... | ||
| 945 | */ | ||
| 946 | spin_lock(&clnt->cl_lock); | ||
| 947 | list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { | ||
| 948 | if (! RPC_IS_ACTIVATED(rovr)) | ||
| 949 | continue; | ||
| 950 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | ||
| 951 | rovr->tk_flags |= RPC_TASK_KILLED; | ||
| 952 | rpc_exit(rovr, -EIO); | ||
| 953 | rpc_wake_up_task(rovr); | ||
| 954 | } | ||
| 955 | } | ||
| 956 | spin_unlock(&clnt->cl_lock); | ||
| 957 | } | ||
| 958 | EXPORT_SYMBOL_GPL(rpc_killall_tasks); | ||
| 959 | |||
| 960 | int rpciod_up(void) | 890 | int rpciod_up(void) |
| 961 | { | 891 | { |
| 962 | return try_module_get(THIS_MODULE) ? 0 : -EINVAL; | 892 | return try_module_get(THIS_MODULE) ? 0 : -EINVAL; |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index f438347d817b..c0d085013a2b 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
| @@ -33,21 +33,27 @@ init_sunrpc(void) | |||
| 33 | if (err) | 33 | if (err) |
| 34 | goto out; | 34 | goto out; |
| 35 | err = rpc_init_mempool(); | 35 | err = rpc_init_mempool(); |
| 36 | if (err) { | 36 | if (err) |
| 37 | unregister_rpc_pipefs(); | 37 | goto out2; |
| 38 | goto out; | 38 | err = rpcauth_init_module(); |
| 39 | } | 39 | if (err) |
| 40 | goto out3; | ||
| 40 | #ifdef RPC_DEBUG | 41 | #ifdef RPC_DEBUG |
| 41 | rpc_register_sysctl(); | 42 | rpc_register_sysctl(); |
| 42 | #endif | 43 | #endif |
| 43 | #ifdef CONFIG_PROC_FS | 44 | #ifdef CONFIG_PROC_FS |
| 44 | rpc_proc_init(); | 45 | rpc_proc_init(); |
| 45 | #endif | 46 | #endif |
| 47 | cache_initialize(); | ||
| 46 | cache_register(&ip_map_cache); | 48 | cache_register(&ip_map_cache); |
| 47 | cache_register(&unix_gid_cache); | 49 | cache_register(&unix_gid_cache); |
| 48 | svc_init_xprt_sock(); /* svc sock transport */ | 50 | svc_init_xprt_sock(); /* svc sock transport */ |
| 49 | init_socket_xprt(); /* clnt sock transport */ | 51 | init_socket_xprt(); /* clnt sock transport */ |
| 50 | rpcauth_init_module(); | 52 | return 0; |
| 53 | out3: | ||
| 54 | rpc_destroy_mempool(); | ||
| 55 | out2: | ||
| 56 | unregister_rpc_pipefs(); | ||
| 51 | out: | 57 | out: |
| 52 | return err; | 58 | return err; |
| 53 | } | 59 | } |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index dcd0132396ba..970fb00f388c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -1032,6 +1032,8 @@ void xprt_release(struct rpc_task *task) | |||
| 1032 | spin_unlock_bh(&xprt->transport_lock); | 1032 | spin_unlock_bh(&xprt->transport_lock); |
| 1033 | if (req->rq_buffer) | 1033 | if (req->rq_buffer) |
| 1034 | xprt->ops->buf_free(req->rq_buffer); | 1034 | xprt->ops->buf_free(req->rq_buffer); |
| 1035 | if (req->rq_cred != NULL) | ||
| 1036 | put_rpccred(req->rq_cred); | ||
| 1035 | task->tk_rqstp = NULL; | 1037 | task->tk_rqstp = NULL; |
| 1036 | if (req->rq_release_snd_buf) | 1038 | if (req->rq_release_snd_buf) |
| 1037 | req->rq_release_snd_buf(req); | 1039 | req->rq_release_snd_buf(req); |
| @@ -1129,6 +1131,7 @@ static void xprt_destroy(struct kref *kref) | |||
| 1129 | rpc_destroy_wait_queue(&xprt->sending); | 1131 | rpc_destroy_wait_queue(&xprt->sending); |
| 1130 | rpc_destroy_wait_queue(&xprt->resend); | 1132 | rpc_destroy_wait_queue(&xprt->resend); |
| 1131 | rpc_destroy_wait_queue(&xprt->backlog); | 1133 | rpc_destroy_wait_queue(&xprt->backlog); |
| 1134 | cancel_work_sync(&xprt->task_cleanup); | ||
| 1132 | /* | 1135 | /* |
| 1133 | * Tear down transport state and free the rpc_xprt | 1136 | * Tear down transport state and free the rpc_xprt |
| 1134 | */ | 1137 | */ |
