FD.io VPP  v16.06
Vector Packet Processing
svmtool.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * svmtool.c
4  *
5  * Copyright (c) 2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/mman.h>
24 #include <sys/stat.h>
25 #include <netinet/in.h>
26 #include <signal.h>
27 #include <pthread.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <vppinfra/clib.h>
33 #include <vppinfra/vec.h>
34 #include <vppinfra/hash.h>
35 #include <vppinfra/bitmap.h>
36 #include <vppinfra/fifo.h>
37 #include <vppinfra/time.h>
38 #include <vppinfra/mheap.h>
39 #include <vppinfra/heap.h>
40 #include <vppinfra/pool.h>
41 #include <vppinfra/format.h>
42 
43 #include "svm.h"
44 
45 
46 
47 /*
48  * format_all_svm_regions
49  * Maps / unmaps regions. Do NOT call from client code!
50  */
51 u8 *format_all_svm_regions (u8 *s, va_list * args)
52 {
53  int verbose = va_arg (*args, int);
56  svm_subregion_t *subp;
57  svm_region_t *rp;
59  u8 ** svm_names=0;
60  u8 *name=0;
61  int i;
62 
63  ASSERT(root_rp);
64 
65  pthread_mutex_lock (&root_rp->mutex);
66 
67  s = format (s, "%U", format_svm_region, root_rp, verbose);
68 
69  mp = root_rp->data_base;
70 
71  /*
72  * Snapshoot names, can't hold root rp mutex across
73  * find_or_create.
74  */
75  pool_foreach (subp, mp->subregions, ({
76  name = vec_dup (subp->subregion_name);
77  vec_add1(svm_names, name);
78  }));
79 
80  pthread_mutex_unlock (&root_rp->mutex);
81 
82  for (i = 0; i < vec_len(svm_names); i++) {
83  vec_validate(a, 0);
84  a->name = (char *) svm_names[i];
86  if (rp) {
87  pthread_mutex_lock (&rp->mutex);
88  s = format (s, "%U", format_svm_region, rp, verbose);
89  pthread_mutex_unlock (&rp->mutex);
90  svm_region_unmap (rp);
91  vec_free(svm_names[i]);
92  }
93  vec_free (a);
94  }
95  vec_free(svm_names);
96  return (s);
97 }
98 
99 void show (char *chroot_path, int verbose)
100 {
102 
103  vec_validate (a, 0);
104 
105  svm_region_init_chroot(chroot_path);
106 
107  fformat(stdout, "My pid is %d\n", getpid());
108 
109  fformat(stdout, "%U", format_all_svm_regions, verbose);
110 
111  svm_region_exit ();
112 
113  vec_free (a);
114 }
115 
116 
118 {
119  int svm_fd;
120  svm_region_t *rp;
121  int deadman=0;
122  u8 *shm_name;
123 
124  ASSERT((a->size & ~(MMAP_PAGESIZE-1)) == a->size);
125 
126  shm_name = shm_name_from_svm_map_region_args (a);
127 
128  svm_fd = shm_open((char *)shm_name, O_RDWR, 0777);
129 
130  if (svm_fd < 0) {
131  perror("svm_region_map(mmap open)");
132  return (0);
133  }
134  vec_free (shm_name);
135 
136  rp = mmap(0, MMAP_PAGESIZE,
137  PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0);
138 
139  if (rp == (svm_region_t *) MAP_FAILED) {
140  close(svm_fd);
141  clib_warning("mmap");
142  return (0);
143  }
144  /*
145  * We lost the footrace to create this region; make sure
146  * the winner has crossed the finish line.
147  */
148  while (rp->version == 0 && deadman++ < 5) {
149  sleep(1);
150  }
151 
152  /*
153  * <bleep>-ed?
154  */
155  if (rp->version == 0) {
156  clib_warning("rp->version %d not %d", rp->version,
157  SVM_VERSION);
158  return (0);
159  }
160  /* Remap now that the region has been placed */
161  a->baseva = rp->virtual_base;
162  a->size = rp->virtual_size;
163  munmap(rp, MMAP_PAGESIZE);
164 
165  rp = (void *) mmap ((void *)a->baseva, a->size,
166  PROT_READ | PROT_WRITE,
167  MAP_SHARED | MAP_FIXED, svm_fd, 0);
168  if ((uword)rp == (uword)MAP_FAILED) {
169  clib_unix_warning ("mmap");
170  return (0);
171  }
172 
173  if ((uword) rp != rp->virtual_base) {
174  clib_warning("mmap botch");
175  }
176 
177  if (pthread_mutex_trylock(&rp->mutex)) {
178  clib_warning ("rp->mutex LOCKED by pid %d, tag %d, cleared...",
180  memset(&rp->mutex, 0, sizeof (rp->mutex));
181 
182  } else {
183  clib_warning ("mutex OK...\n");
184  pthread_mutex_unlock(&rp->mutex);
185  }
186 
187  return ((void *) rp);
188 }
189 
190 /*
191  * rnd_pagesize
192  * Round to a pagesize multiple, presumably 4k works
193  */
194 static unsigned int rnd_pagesize(unsigned int size)
195 {
196  unsigned int rv;
197 
198  rv = (size + (MMAP_PAGESIZE-1)) & ~(MMAP_PAGESIZE-1);
199  return(rv);
200 }
201 
202 #define MUTEX_DEBUG
203 
205 {
206  pthread_mutex_lock(&rp->mutex);
207 #ifdef MUTEX_DEBUG
208  rp->mutex_owner_pid = getpid();
209  rp->mutex_owner_tag = tag;
210 #endif
211 }
212 
214 {
215 #ifdef MUTEX_DEBUG
216  rp->mutex_owner_pid = 0;
217  rp->mutex_owner_tag = 0;
218 #endif
219  pthread_mutex_unlock(&rp->mutex);
220 }
221 
222 
223 static void *svm_existing_region_map_nolock (void *root_arg,
225 {
226  svm_region_t *root_rp = root_arg;
227  svm_main_region_t *mp;
228  svm_region_t *rp;
229  void *oldheap;
230  uword *p;
231 
233  a->size = rnd_pagesize(a->size);
234 
235  region_lock (root_rp, 4);
236  oldheap = svm_push_pvt_heap(root_rp);
237  mp = root_rp->data_base;
238 
239  ASSERT(mp);
240 
241  p = hash_get_mem (mp->name_hash, a->name);
242 
243  if (p) {
244  rp = svm_map_region_nolock (a);
245  region_unlock(root_rp);
246  svm_pop_heap (oldheap);
247  return rp;
248  }
249  return 0;
250 
251 }
252 
253 static void trace (char *chroot_path, char *name, int enable_disable)
254 {
256  svm_region_t *db_rp;
257  void *oldheap;
258 
259  vec_validate (a, 0);
260 
261  svm_region_init_chroot(chroot_path);
262 
263  a->name = name;
264  a->size = 1<<20;
265  a->flags = SVM_FLAGS_MHEAP;
266 
267  db_rp = svm_region_find_or_create (a);
268 
269  ASSERT(db_rp);
270 
271  region_lock (db_rp, 20);
272 
273  oldheap = svm_push_data_heap (db_rp);
274 
275  mheap_trace (db_rp->data_heap, enable_disable);
276 
277  svm_pop_heap (oldheap);
278  region_unlock (db_rp);
279 
280  svm_region_unmap ((void *)db_rp);
281  svm_region_exit ();
282  vec_free (a);
283 }
284 
285 
286 
287 static void subregion_repair(char *chroot_path)
288 {
289  int i;
290  svm_main_region_t *mp;
293  svm_region_t *rp;
294  svm_subregion_t *subp;
295  u8 *name=0;
296  u8 ** svm_names=0;
297 
298  svm_region_init_chroot(chroot_path);
299  root_rp = svm_get_root_rp();
300 
301  pthread_mutex_lock (&root_rp->mutex);
302 
303  mp = root_rp->data_base;
304 
305  /*
306  * Snapshoot names, can't hold root rp mutex across
307  * find_or_create.
308  */
309  pool_foreach (subp, mp->subregions, ({
310  name = vec_dup (subp->subregion_name);
311  vec_add1(svm_names, name);
312  }));
313 
314  pthread_mutex_unlock (&root_rp->mutex);
315 
316  for (i = 0; i < vec_len(svm_names); i++) {
317  memset (&a, 0, sizeof (a));
318  a.root_path = chroot_path;
319  a.name = (char *) svm_names[i];
320  fformat(stdout, "Checking %s region...\n",
321  a.name);
322  rp = svm_existing_region_map_nolock (root_rp, &a);
323  if (rp) {
324  svm_region_unmap (rp);
325  vec_free(svm_names[i]);
326  }
327  }
328  vec_free(svm_names);
329 }
330 
331 void repair (char *chroot_path, int crash_root_region)
332 {
333  svm_region_t *root_rp = 0;
336  int svm_fd;
337  u8 *shm_name;
338 
339  fformat(stdout, "our pid: %d\n", getpid());
340 
341  vec_validate (a, 0);
342 
343  a->root_path = chroot_path;
347  a->flags = SVM_FLAGS_NODATA;
348 
349  shm_name = shm_name_from_svm_map_region_args (a);
350 
351  svm_fd = shm_open ((char *)shm_name, O_RDWR, 0777);
352 
353  if (svm_fd < 0) {
354  perror("svm_region_map(mmap open)");
355  goto out;
356  }
357 
358  vec_free(shm_name);
359 
360  root_rp = mmap(0, MMAP_PAGESIZE,
361  PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0);
362 
363  if (root_rp == (svm_region_t *) MAP_FAILED) {
364  close(svm_fd);
365  clib_warning("mmap");
366  goto out;
367  }
368 
369  /* Remap now that the region has been placed */
370  clib_warning ("remap to 0x%x", root_rp->virtual_base);
371 
372  a->baseva = root_rp->virtual_base;
373  a->size = root_rp->virtual_size;
374  munmap(root_rp, MMAP_PAGESIZE);
375 
376  root_rp = (void *) mmap ((void *)a->baseva, a->size,
377  PROT_READ | PROT_WRITE,
378  MAP_SHARED | MAP_FIXED, svm_fd, 0);
379  if ((uword)root_rp == (uword)MAP_FAILED) {
380  clib_unix_warning ("mmap");
381  goto out;
382  }
383 
384  close(svm_fd);
385 
386  if ((uword) root_rp != root_rp->virtual_base) {
387  clib_warning("mmap botch");
388  goto out;
389  }
390 
391  if (pthread_mutex_trylock(&root_rp->mutex)) {
392  clib_warning ("root_rp->mutex LOCKED by pid %d, tag %d, cleared...",
393  root_rp->mutex_owner_pid, root_rp->mutex_owner_tag);
394  memset(&root_rp->mutex, 0, sizeof (root_rp->mutex));
395  goto out;
396  } else {
397  clib_warning ("root_rp->mutex OK...\n");
398  pthread_mutex_unlock(&root_rp->mutex);
399  }
400 
401  out:
402  vec_free (a);
403  /*
404  * Now that the root region is known to be OK,
405  * fix broken subregions
406  */
407  subregion_repair(chroot_path);
408 
409  if (crash_root_region) {
410  clib_warning ("Leaving root region locked on purpose...");
411  pthread_mutex_lock(&root_rp->mutex);
412  root_rp->mutex_owner_pid = getpid();
413  root_rp->mutex_owner_tag = 99;
414  }
415  svm_region_exit ();
416 }
417 
418 int main (int argc, char **argv)
419 {
420  unformat_input_t input;
421  int parsed =0;
422  char *name;
423  char *chroot_path = 0;
424  u8 *chroot_u8;
425 
426  unformat_init_command_line (&input, argv);
427 
428  while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) {
429  if (unformat(&input, "show-verbose")) {
430  show (chroot_path, 1);
431  parsed++;
432  } else if (unformat (&input, "show")) {
433  show (chroot_path, 0);
434  parsed++;
435  } else if (unformat (&input, "client-scan")) {
436  svm_client_scan(chroot_path);
437  parsed++;
438  } else if (unformat (&input, "repair")) {
439  repair(chroot_path, 0 /* fix it */);
440  parsed++;
441  } else if (unformat (&input, "crash")) {
442  repair (chroot_path, 1 /* crash it */);
443  parsed++;
444  } else if (unformat (&input, "trace-on %s", &name)) {
445  trace (chroot_path, name, 1);
446  parsed++;
447  } else if (unformat (&input, "trace-off %s", &name)) {
448  trace (chroot_path, name, 0);
449  parsed++;
450  } else if (unformat (&input, "chroot %s", &chroot_u8)) {
451  chroot_path = (char *) chroot_u8;
452  } else {
453  break;
454  }
455  }
456 
457  unformat_free (&input);
458 
459  if (!parsed) {
460  fformat(stdout, "%s: show | show-verbose | client-scan | trace-on <region-name>\n", argv[0]);
461  fformat(stdout, " trace-off <region-name>\n");
462  }
463  exit (0);
464 }
char * root_path
Definition: svm.h:70
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
svm_region_t * svm_get_root_rp(void)
Definition: svm.c:53
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
static void svm_pop_heap(void *oldheap)
Definition: svm.h:179
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
a
Definition: bitmap.h:393
void * svm_map_region(svm_map_region_args_t *a)
Definition: svm.c:363
always_inline void unformat_free(unformat_input_t *i)
Definition: format.h:160
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
always_inline void region_unlock(svm_region_t *rp)
Definition: svmtool.c:213
uword virtual_base
Definition: svm.h:46
#define SVM_FLAGS_MHEAP
Definition: svm.h:32
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
#define pool_foreach(VAR, POOL, BODY)
Definition: pool.h:328
static void * svm_push_data_heap(svm_region_t *rp)
Definition: svm.h:172
#define always_inline
Definition: clib.h:84
void * svm_region_find_or_create(svm_map_region_args_t *a)
Definition: svm.c:692
char * name
Definition: svm.h:71
#define clib_warning(format, args...)
Definition: error.h:59
#define SVM_GLOBAL_REGION_BASEVA
Definition: svm.h:88
u8 * format_svm_region(u8 *s, va_list *args)
Definition: svm.c:130
static void * svm_existing_region_map_nolock(void *root_arg, svm_map_region_args_t *a)
Definition: svmtool.c:223
#define SVM_FLAGS_NODATA
Definition: svm.h:34
void * data_base
Definition: svm.h:49
uword * name_hash
Definition: svm.h:106
void unformat_init_command_line(unformat_input_t *input, char *argv[])
Definition: unformat.c:975
svm_subregion_t * subregions
Definition: svm.h:105
uword virtual_size
Definition: svm.h:47
void svm_region_exit()
Definition: svm.c:918
void repair(char *chroot_path, int crash_root_region)
Definition: svmtool.c:331
static void * svm_map_region_nolock(svm_map_region_args_t *a)
Definition: svmtool.c:117
static void * svm_push_pvt_heap(svm_region_t *rp)
Definition: svm.h:165
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
#define clib_unix_warning(format, args...)
Definition: error.h:68
u8 * shm_name_from_svm_map_region_args(svm_map_region_args_t *a)
Definition: svm.c:314
int main(int argc, char **argv)
Definition: svmtool.c:418
void mheap_trace(void *v, int enable)
Definition: mheap.c:1549
#define ASSERT(truth)
static unsigned int rnd_pagesize(unsigned int size)
Definition: svmtool.c:194
void svm_region_init_chroot(char *root_path)
Definition: svm.c:682
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
u32 size
Definition: vhost-user.h:74
volatile uword version
Definition: svm.h:40
int mutex_owner_tag
Definition: svm.h:44
#define SVM_GLOBAL_REGION_SIZE
Definition: svm.h:89
#define SVM_VERSION
Definition: svm.h:30
static void subregion_repair(char *chroot_path)
Definition: svmtool.c:287
#define MMAP_PAGESIZE
Definition: ssvm.h:41
u64 uword
Definition: types.h:112
#define SVM_GLOBAL_REGION_NAME
Definition: svm.h:90
#define SVM_PVT_MHEAP_SIZE
Definition: svm.h:37
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u8 * format_all_svm_regions(u8 *s, va_list *args)
Definition: svmtool.c:51
void svm_region_unmap(void *rp_arg)
Definition: svm.c:802
void show(char *chroot_path, int verbose)
Definition: svmtool.c:99
word fformat(FILE *f, char *fmt,...)
Definition: format.c:437
#define hash_get_mem(h, key)
Definition: hash.h:251
void * data_heap
Definition: svm.h:50
struct _unformat_input_t unformat_input_t
void svm_client_scan(char *root_path)
Definition: svm.c:988
static void trace(char *chroot_path, char *name, int enable_disable)
Definition: svmtool.c:253
int mutex_owner_pid
Definition: svm.h:43
uword baseva
Definition: svm.h:72
pthread_mutex_t mutex
Definition: svm.h:41
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".
always_inline void region_lock(svm_region_t *rp, int tag)
Definition: svmtool.c:204
static svm_region_t * root_rp
Definition: svm.c:46