~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/lib/bpf/strset.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2 /* Copyright (c) 2021 Facebook */
  3 #include <stdint.h>
  4 #include <stdlib.h>
  5 #include <stdio.h>
  6 #include <errno.h>
  7 #include <linux/err.h>
  8 #include "hashmap.h"
  9 #include "libbpf_internal.h"
 10 #include "strset.h"
 11 
 12 struct strset {
 13         void *strs_data;
 14         size_t strs_data_len;
 15         size_t strs_data_cap;
 16         size_t strs_data_max_len;
 17 
 18         /* lookup index for each unique string in strings set */
 19         struct hashmap *strs_hash;
 20 };
 21 
 22 static size_t strset_hash_fn(long key, void *ctx)
 23 {
 24         const struct strset *s = ctx;
 25         const char *str = s->strs_data + key;
 26 
 27         return str_hash(str);
 28 }
 29 
 30 static bool strset_equal_fn(long key1, long key2, void *ctx)
 31 {
 32         const struct strset *s = ctx;
 33         const char *str1 = s->strs_data + key1;
 34         const char *str2 = s->strs_data + key2;
 35 
 36         return strcmp(str1, str2) == 0;
 37 }
 38 
 39 struct strset *strset__new(size_t max_data_sz, const char *init_data, size_t init_data_sz)
 40 {
 41         struct strset *set = calloc(1, sizeof(*set));
 42         struct hashmap *hash;
 43         int err = -ENOMEM;
 44 
 45         if (!set)
 46                 return ERR_PTR(-ENOMEM);
 47 
 48         hash = hashmap__new(strset_hash_fn, strset_equal_fn, set);
 49         if (IS_ERR(hash))
 50                 goto err_out;
 51 
 52         set->strs_data_max_len = max_data_sz;
 53         set->strs_hash = hash;
 54 
 55         if (init_data) {
 56                 long off;
 57 
 58                 set->strs_data = malloc(init_data_sz);
 59                 if (!set->strs_data)
 60                         goto err_out;
 61 
 62                 memcpy(set->strs_data, init_data, init_data_sz);
 63                 set->strs_data_len = init_data_sz;
 64                 set->strs_data_cap = init_data_sz;
 65 
 66                 for (off = 0; off < set->strs_data_len; off += strlen(set->strs_data + off) + 1) {
 67                         /* hashmap__add() returns EEXIST if string with the same
 68                          * content already is in the hash map
 69                          */
 70                         err = hashmap__add(hash, off, off);
 71                         if (err == -EEXIST)
 72                                 continue; /* duplicate */
 73                         if (err)
 74                                 goto err_out;
 75                 }
 76         }
 77 
 78         return set;
 79 err_out:
 80         strset__free(set);
 81         return ERR_PTR(err);
 82 }
 83 
 84 void strset__free(struct strset *set)
 85 {
 86         if (IS_ERR_OR_NULL(set))
 87                 return;
 88 
 89         hashmap__free(set->strs_hash);
 90         free(set->strs_data);
 91         free(set);
 92 }
 93 
 94 size_t strset__data_size(const struct strset *set)
 95 {
 96         return set->strs_data_len;
 97 }
 98 
 99 const char *strset__data(const struct strset *set)
100 {
101         return set->strs_data;
102 }
103 
104 static void *strset_add_str_mem(struct strset *set, size_t add_sz)
105 {
106         return libbpf_add_mem(&set->strs_data, &set->strs_data_cap, 1,
107                               set->strs_data_len, set->strs_data_max_len, add_sz);
108 }
109 
110 /* Find string offset that corresponds to a given string *s*.
111  * Returns:
112  *   - >0 offset into string data, if string is found;
113  *   - -ENOENT, if string is not in the string data;
114  *   - <0, on any other error.
115  */
116 int strset__find_str(struct strset *set, const char *s)
117 {
118         long old_off, new_off, len;
119         void *p;
120 
121         /* see strset__add_str() for why we do this */
122         len = strlen(s) + 1;
123         p = strset_add_str_mem(set, len);
124         if (!p)
125                 return -ENOMEM;
126 
127         new_off = set->strs_data_len;
128         memcpy(p, s, len);
129 
130         if (hashmap__find(set->strs_hash, new_off, &old_off))
131                 return old_off;
132 
133         return -ENOENT;
134 }
135 
136 /* Add a string s to the string data. If the string already exists, return its
137  * offset within string data.
138  * Returns:
139  *   - > 0 offset into string data, on success;
140  *   - < 0, on error.
141  */
142 int strset__add_str(struct strset *set, const char *s)
143 {
144         long old_off, new_off, len;
145         void *p;
146         int err;
147 
148         /* Hashmap keys are always offsets within set->strs_data, so to even
149          * look up some string from the "outside", we need to first append it
150          * at the end, so that it can be addressed with an offset. Luckily,
151          * until set->strs_data_len is incremented, that string is just a piece
152          * of garbage for the rest of the code, so no harm, no foul. On the
153          * other hand, if the string is unique, it's already appended and
154          * ready to be used, only a simple set->strs_data_len increment away.
155          */
156         len = strlen(s) + 1;
157         p = strset_add_str_mem(set, len);
158         if (!p)
159                 return -ENOMEM;
160 
161         new_off = set->strs_data_len;
162         memcpy(p, s, len);
163 
164         /* Now attempt to add the string, but only if the string with the same
165          * contents doesn't exist already (HASHMAP_ADD strategy). If such
166          * string exists, we'll get its offset in old_off (that's old_key).
167          */
168         err = hashmap__insert(set->strs_hash, new_off, new_off,
169                               HASHMAP_ADD, &old_off, NULL);
170         if (err == -EEXIST)
171                 return old_off; /* duplicated string, return existing offset */
172         if (err)
173                 return err;
174 
175         set->strs_data_len += len; /* new unique string, adjust data length */
176         return new_off;
177 }
178 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php