diff options
Diffstat (limited to 'net/netlabel/netlabel_domainhash.c')
| -rw-r--r-- | net/netlabel/netlabel_domainhash.c | 30 |
1 files changed, 19 insertions, 11 deletions
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index c5d9f97ef217..d37b7f80fa37 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
| 36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
| 37 | #include <linux/audit.h> | 37 | #include <linux/audit.h> |
| 38 | #include <linux/slab.h> | ||
| 38 | #include <net/netlabel.h> | 39 | #include <net/netlabel.h> |
| 39 | #include <net/cipso_ipv4.h> | 40 | #include <net/cipso_ipv4.h> |
| 40 | #include <asm/bug.h> | 41 | #include <asm/bug.h> |
| @@ -50,9 +51,12 @@ struct netlbl_domhsh_tbl { | |||
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | /* Domain hash table */ | 53 | /* Domain hash table */ |
| 53 | /* XXX - updates should be so rare that having one spinlock for the entire | 54 | /* updates should be so rare that having one spinlock for the entire hash table |
| 54 | * hash table should be okay */ | 55 | * should be okay */ |
| 55 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); | 56 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); |
| 57 | #define netlbl_domhsh_rcu_deref(p) \ | ||
| 58 | rcu_dereference_check(p, rcu_read_lock_held() || \ | ||
| 59 | lockdep_is_held(&netlbl_domhsh_lock)) | ||
| 56 | static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; | 60 | static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; |
| 57 | static struct netlbl_dom_map *netlbl_domhsh_def = NULL; | 61 | static struct netlbl_dom_map *netlbl_domhsh_def = NULL; |
| 58 | 62 | ||
| @@ -106,7 +110,8 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry) | |||
| 106 | * Description: | 110 | * Description: |
| 107 | * This is the hashing function for the domain hash table, it returns the | 111 | * This is the hashing function for the domain hash table, it returns the |
| 108 | * correct bucket number for the domain. The caller is responsibile for | 112 | * correct bucket number for the domain. The caller is responsibile for |
| 109 | * calling the rcu_read_[un]lock() functions. | 113 | * ensuring that the hash table is protected with either a RCU read lock or the |
| 114 | * hash table lock. | ||
| 110 | * | 115 | * |
| 111 | */ | 116 | */ |
| 112 | static u32 netlbl_domhsh_hash(const char *key) | 117 | static u32 netlbl_domhsh_hash(const char *key) |
| @@ -120,7 +125,7 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
| 120 | 125 | ||
| 121 | for (iter = 0, val = 0, len = strlen(key); iter < len; iter++) | 126 | for (iter = 0, val = 0, len = strlen(key); iter < len; iter++) |
| 122 | val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter]; | 127 | val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter]; |
| 123 | return val & (rcu_dereference(netlbl_domhsh)->size - 1); | 128 | return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1); |
| 124 | } | 129 | } |
| 125 | 130 | ||
| 126 | /** | 131 | /** |
| @@ -130,7 +135,8 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
| 130 | * Description: | 135 | * Description: |
| 131 | * Searches the domain hash table and returns a pointer to the hash table | 136 | * Searches the domain hash table and returns a pointer to the hash table |
| 132 | * entry if found, otherwise NULL is returned. The caller is responsibile for | 137 | * entry if found, otherwise NULL is returned. The caller is responsibile for |
| 133 | * the rcu hash table locks (i.e. the caller much call rcu_read_[un]lock()). | 138 | * ensuring that the hash table is protected with either a RCU read lock or the |
| 139 | * hash table lock. | ||
| 134 | * | 140 | * |
| 135 | */ | 141 | */ |
| 136 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | 142 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) |
| @@ -141,7 +147,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | |||
| 141 | 147 | ||
| 142 | if (domain != NULL) { | 148 | if (domain != NULL) { |
| 143 | bkt = netlbl_domhsh_hash(domain); | 149 | bkt = netlbl_domhsh_hash(domain); |
| 144 | bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; | 150 | bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt]; |
| 145 | list_for_each_entry_rcu(iter, bkt_list, list) | 151 | list_for_each_entry_rcu(iter, bkt_list, list) |
| 146 | if (iter->valid && strcmp(iter->domain, domain) == 0) | 152 | if (iter->valid && strcmp(iter->domain, domain) == 0) |
| 147 | return iter; | 153 | return iter; |
| @@ -159,8 +165,8 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | |||
| 159 | * Searches the domain hash table and returns a pointer to the hash table | 165 | * Searches the domain hash table and returns a pointer to the hash table |
| 160 | * entry if an exact match is found, if an exact match is not present in the | 166 | * entry if an exact match is found, if an exact match is not present in the |
| 161 | * hash table then the default entry is returned if valid otherwise NULL is | 167 | * hash table then the default entry is returned if valid otherwise NULL is |
| 162 | * returned. The caller is responsibile for the rcu hash table locks | 168 | * returned. The caller is responsibile ensuring that the hash table is |
| 163 | * (i.e. the caller much call rcu_read_[un]lock()). | 169 | * protected with either a RCU read lock or the hash table lock. |
| 164 | * | 170 | * |
| 165 | */ | 171 | */ |
| 166 | static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | 172 | static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) |
| @@ -169,7 +175,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | |||
| 169 | 175 | ||
| 170 | entry = netlbl_domhsh_search(domain); | 176 | entry = netlbl_domhsh_search(domain); |
| 171 | if (entry == NULL) { | 177 | if (entry == NULL) { |
| 172 | entry = rcu_dereference(netlbl_domhsh_def); | 178 | entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def); |
| 173 | if (entry != NULL && !entry->valid) | 179 | if (entry != NULL && !entry->valid) |
| 174 | entry = NULL; | 180 | entry = NULL; |
| 175 | } | 181 | } |
| @@ -306,8 +312,11 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, | |||
| 306 | struct netlbl_af6list *tmp6; | 312 | struct netlbl_af6list *tmp6; |
| 307 | #endif /* IPv6 */ | 313 | #endif /* IPv6 */ |
| 308 | 314 | ||
| 315 | /* XXX - we can remove this RCU read lock as the spinlock protects the | ||
| 316 | * entire function, but before we do we need to fixup the | ||
| 317 | * netlbl_af[4,6]list RCU functions to do "the right thing" with | ||
| 318 | * respect to rcu_dereference() when only a spinlock is held. */ | ||
| 309 | rcu_read_lock(); | 319 | rcu_read_lock(); |
| 310 | |||
| 311 | spin_lock(&netlbl_domhsh_lock); | 320 | spin_lock(&netlbl_domhsh_lock); |
| 312 | if (entry->domain != NULL) | 321 | if (entry->domain != NULL) |
| 313 | entry_old = netlbl_domhsh_search(entry->domain); | 322 | entry_old = netlbl_domhsh_search(entry->domain); |
| @@ -315,7 +324,6 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, | |||
| 315 | entry_old = netlbl_domhsh_search_def(entry->domain); | 324 | entry_old = netlbl_domhsh_search_def(entry->domain); |
| 316 | if (entry_old == NULL) { | 325 | if (entry_old == NULL) { |
| 317 | entry->valid = 1; | 326 | entry->valid = 1; |
| 318 | INIT_RCU_HEAD(&entry->rcu); | ||
| 319 | 327 | ||
| 320 | if (entry->domain != NULL) { | 328 | if (entry->domain != NULL) { |
| 321 | u32 bkt = netlbl_domhsh_hash(entry->domain); | 329 | u32 bkt = netlbl_domhsh_hash(entry->domain); |
