#define MUTEX_DEBUG
+u64
+svm_get_global_region_base_va ()
+{
+#ifdef CLIB_SANITIZE_ADDR
+ return 0x200000000000;
+#endif
+
+#if __aarch64__
+ /* On AArch64 VA space can have different size, from 36 to 48 bits.
+ Here we are trying to detect VA bits by parsing /proc/self/maps
+ address ranges */
+ int fd;
+ unformat_input_t input;
+ u64 start, end = 0;
+ u8 bits = 0;
+
+ if ((fd = open ("/proc/self/maps", 0)) < 0)
+ clib_unix_error ("open '/proc/self/maps'");
+
+ unformat_init_clib_file (&input, fd);
+ while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (&input, "%llx-%llx", &start, &end))
+ end--;
+ unformat_skip_line (&input);
+ }
+ unformat_free (&input);
+ close (fd);
+
+ bits = count_leading_zeros (end);
+ bits = 64 - bits;
+ if (bits >= 36 && bits <= 48)
+ return ((1ul << bits) / 4) - (2 * SVM_GLOBAL_REGION_SIZE);
+ else
+ clib_unix_error ("unexpected va bits '%u'", bits);
+#endif
+
+ /* default value */
+ return 0x130000000ULL;
+}
+
static void
region_lock (svm_region_t * rp, int tag)
{
}
}
}
- s = format (s, " rgn heap stats: %U", format_mheap,
- rp->region_heap, 0);
- if ((rp->flags & SVM_FLAGS_MHEAP) && rp->data_heap)
- {
- s = format (s, "\n data heap stats: %U", format_mheap,
- rp->data_heap, 1);
- }
- s = format (s, "\n");
}
return (s);
if (a->flags & SVM_FLAGS_MHEAP)
{
- rp->data_heap =
- mheap_alloc_with_flags ((void *) (rp->data_base), map_size,
- MHEAP_FLAG_DISABLE_VM);
+ rp->data_heap = create_mspace_with_base (rp->data_base,
+ map_size, 1 /* locked */ );
+ mspace_disable_expand (rp->data_heap);
+
rp->flags |= SVM_FLAGS_MHEAP;
}
return 0;
u8 *
shm_name_from_svm_map_region_args (svm_map_region_args_t * a)
{
- u8 *path;
u8 *shm_name;
- u8 *split_point;
- u8 *mkdir_arg = 0;
int root_path_offset = 0;
int name_offset = 0;
if (a->root_path[0] == '/')
root_path_offset++;
- /* create the root_path under /dev/shm
- iterate through path creating directories */
-
- path = format (0, "/dev/shm/%s%c", &a->root_path[root_path_offset], 0);
- split_point = path + 1;
- vec_add1 (mkdir_arg, '-');
-
- while (*split_point)
- {
- while (*split_point && *split_point != '/')
- {
- vec_add1 (mkdir_arg, *split_point);
- split_point++;
- }
- vec_add1 (mkdir_arg, 0);
-
- /* ready to descend another level */
- mkdir_arg[vec_len (mkdir_arg) - 1] = '-';
- split_point++;
- }
- vec_free (mkdir_arg);
- vec_free (path);
-
if (a->name[0] == '/')
name_offset = 1;
return (shm_name);
}
+void
+svm_region_init_mapped_region (svm_map_region_args_t * a, svm_region_t * rp)
+{
+ pthread_mutexattr_t attr;
+ pthread_condattr_t cattr;
+ int nbits, words, bit;
+ int overhead_space;
+ void *oldheap;
+ uword data_base;
+ ASSERT (rp);
+ int rv;
+
+ clib_memset (rp, 0, sizeof (*rp));
+
+ if (pthread_mutexattr_init (&attr))
+ clib_unix_warning ("mutexattr_init");
+
+ if (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED))
+ clib_unix_warning ("mutexattr_setpshared");
+
+ if (pthread_mutex_init (&rp->mutex, &attr))
+ clib_unix_warning ("mutex_init");
+
+ if (pthread_mutexattr_destroy (&attr))
+ clib_unix_warning ("mutexattr_destroy");
+
+ if (pthread_condattr_init (&cattr))
+ clib_unix_warning ("condattr_init");
+
+ if (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED))
+ clib_unix_warning ("condattr_setpshared");
+
+ if (pthread_cond_init (&rp->condvar, &cattr))
+ clib_unix_warning ("cond_init");
+
+ if (pthread_condattr_destroy (&cattr))
+ clib_unix_warning ("condattr_destroy");
+
+ region_lock (rp, 1);
+
+ rp->virtual_base = a->baseva;
+ rp->virtual_size = a->size;
+
+ rp->region_heap = create_mspace_with_base
+ (uword_to_pointer (a->baseva + MMAP_PAGESIZE, void *),
+ (a->pvt_heap_size !=
+ 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE, 1 /* locked */ );
+
+ mspace_disable_expand (rp->region_heap);
+
+ oldheap = svm_push_pvt_heap (rp);
+
+ rp->region_name = (char *) format (0, "%s%c", a->name, 0);
+ vec_add1 (rp->client_pids, getpid ());
+
+ nbits = rp->virtual_size / MMAP_PAGESIZE;
+
+ ASSERT (nbits > 0);
+ rp->bitmap_size = nbits;
+ words = (nbits + BITS (uword) - 1) / BITS (uword);
+ vec_validate (rp->bitmap, words - 1);
+
+ overhead_space = MMAP_PAGESIZE /* header */ +
+ ((a->pvt_heap_size != 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE);
+
+ bit = 0;
+ data_base = (uword) rp->virtual_base;
+
+ if (a->flags & SVM_FLAGS_NODATA)
+ rp->flags |= SVM_FLAGS_NEED_DATA_INIT;
+
+ do
+ {
+ clib_bitmap_set_no_check (rp->bitmap, bit, 1);
+ bit++;
+ overhead_space -= MMAP_PAGESIZE;
+ data_base += MMAP_PAGESIZE;
+ }
+ while (overhead_space > 0);
+
+ rp->data_base = (void *) data_base;
+
+ /*
+ * Note: although the POSIX spec guarantees that only one
+ * process enters this block, we have to play games
+ * to hold off clients until e.g. the mutex is ready
+ */
+ rp->version = SVM_VERSION;
+
+ /* setup the data portion of the region */
+
+ rv = svm_data_region_create (a, rp);
+ if (rv)
+ {
+ clib_warning ("data_region_create: %d", rv);
+ }
+
+ region_unlock (rp);
+
+ svm_pop_heap (oldheap);
+}
+
/*
* svm_map_region
*/
{
int svm_fd;
svm_region_t *rp;
- pthread_mutexattr_t attr;
- pthread_condattr_t cattr;
int deadman = 0;
u8 junk = 0;
void *oldheap;
- int overhead_space;
int rv;
- uword data_base;
- int nbits, words, bit;
int pid_holding_region_lock;
u8 *shm_name;
int dead_region_recovery = 0;
if (svm_fd >= 0)
{
- if (fchmod (svm_fd, 0770) < 0)
+ if (fchmod (svm_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0)
clib_unix_warning ("segment chmod");
/* This turns out to fail harmlessly if the client starts first */
if (fchown (svm_fd, a->uid, a->gid) < 0)
return (0);
}
close (svm_fd);
- memset (rp, 0, sizeof (*rp));
-
- if (pthread_mutexattr_init (&attr))
- clib_unix_warning ("mutexattr_init");
-
- if (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED))
- clib_unix_warning ("mutexattr_setpshared");
-
- if (pthread_mutex_init (&rp->mutex, &attr))
- clib_unix_warning ("mutex_init");
-
- if (pthread_mutexattr_destroy (&attr))
- clib_unix_warning ("mutexattr_destroy");
-
- if (pthread_condattr_init (&cattr))
- clib_unix_warning ("condattr_init");
-
- if (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED))
- clib_unix_warning ("condattr_setpshared");
-
- if (pthread_cond_init (&rp->condvar, &cattr))
- clib_unix_warning ("cond_init");
-
- if (pthread_condattr_destroy (&cattr))
- clib_unix_warning ("condattr_destroy");
-
- region_lock (rp, 1);
-
- rp->virtual_base = a->baseva;
- rp->virtual_size = a->size;
-
- rp->region_heap =
- mheap_alloc_with_flags (uword_to_pointer
- (a->baseva + MMAP_PAGESIZE, void *),
- (a->pvt_heap_size !=
- 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE,
- MHEAP_FLAG_DISABLE_VM);
- oldheap = svm_push_pvt_heap (rp);
-
- rp->region_name = (char *) format (0, "%s%c", a->name, 0);
- vec_add1 (rp->client_pids, getpid ());
-
- nbits = rp->virtual_size / MMAP_PAGESIZE;
-
- ASSERT (nbits > 0);
- rp->bitmap_size = nbits;
- words = (nbits + BITS (uword) - 1) / BITS (uword);
- vec_validate (rp->bitmap, words - 1);
-
- overhead_space = MMAP_PAGESIZE /* header */ +
- ((a->pvt_heap_size != 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE);
-
- bit = 0;
- data_base = (uword) rp->virtual_base;
-
- if (a->flags & SVM_FLAGS_NODATA)
- rp->flags |= SVM_FLAGS_NEED_DATA_INIT;
-
- do
- {
- clib_bitmap_set_no_check (rp->bitmap, bit, 1);
- bit++;
- overhead_space -= MMAP_PAGESIZE;
- data_base += MMAP_PAGESIZE;
- }
- while (overhead_space > 0);
-
- rp->data_base = (void *) data_base;
-
- /*
- * Note: although the POSIX spec guarantees that only one
- * process enters this block, we have to play games
- * to hold off clients until e.g. the mutex is ready
- */
- rp->version = SVM_VERSION;
- /* setup the data portion of the region */
-
- rv = svm_data_region_create (a, rp);
- if (rv)
- {
- clib_warning ("data_region_create: %d", rv);
- }
-
- region_unlock (rp);
-
- svm_pop_heap (oldheap);
+ svm_region_init_mapped_region (a, rp);
return ((void *) rp);
}
return (0);
}
+ /* Reset ownership in case the client started first */
+ if (fchown (svm_fd, a->uid, a->gid) < 0)
+ clib_unix_warning ("segment chown [ok if client starts first]");
+
time_left = 20;
while (1)
{
return (0);
}
+ close (svm_fd);
+
if ((uword) rp != rp->virtual_base)
{
clib_warning ("mmap botch");
vec_validate (mp, 0);
mp->name_hash = hash_create_string (0, sizeof (uword));
mp->root_path = a->root_path ? format (0, "%s%c", a->root_path, 0) : 0;
+ mp->uid = a->uid;
+ mp->gid = a->gid;
rp->data_base = mp;
svm_pop_heap (oldheap);
}
{
svm_map_region_args_t _a, *a = &_a;
- memset (a, 0, sizeof (*a));
+ clib_memset (a, 0, sizeof (*a));
a->root_path = 0;
a->name = SVM_GLOBAL_REGION_NAME;
- a->baseva = SVM_GLOBAL_REGION_BASEVA;
+ a->baseva = svm_get_global_region_base_va ();
a->size = SVM_GLOBAL_REGION_SIZE;
a->flags = SVM_FLAGS_NODATA;
a->uid = 0;
{
svm_map_region_args_t _a, *a = &_a;
- memset (a, 0, sizeof (*a));
+ clib_memset (a, 0, sizeof (*a));
a->root_path = root_path;
a->name = SVM_GLOBAL_REGION_NAME;
- a->baseva = SVM_GLOBAL_REGION_BASEVA;
+ a->baseva = svm_get_global_region_base_va ();
a->size = SVM_GLOBAL_REGION_SIZE;
a->flags = SVM_FLAGS_NODATA;
a->uid = 0;
{
svm_map_region_args_t _a, *a = &_a;
- memset (a, 0, sizeof (*a));
+ clib_memset (a, 0, sizeof (*a));
a->root_path = root_path;
a->name = SVM_GLOBAL_REGION_NAME;
- a->baseva = SVM_GLOBAL_REGION_BASEVA;
+ a->baseva = svm_get_global_region_base_va ();
a->size = SVM_GLOBAL_REGION_SIZE;
a->flags = SVM_FLAGS_NODATA;
a->uid = uid;
* a new region client showing up at the wrong moment.
*/
void
-svm_region_unmap (void *rp_arg)
+svm_region_unmap_internal (void *rp_arg, u8 is_client)
{
int i, mypid = getpid ();
int nclients_left;
vec_free (name);
region_unlock (rp);
- svm_region_unlink (rp);
+
+ /* If a client asks for the cleanup, don't unlink the backing
+ * file since we can't tell if it has been recreated. */
+ if (!is_client)
+ svm_region_unlink (rp);
+
munmap ((void *) virtual_base, virtual_size);
region_unlock (root_rp);
svm_pop_heap (oldheap);
munmap ((void *) virtual_base, virtual_size);
}
+void
+svm_region_unmap (void *rp_arg)
+{
+ svm_region_unmap_internal (rp_arg, 0 /* is_client */ );
+}
+
+void
+svm_region_unmap_client (void *rp_arg)
+{
+ svm_region_unmap_internal (rp_arg, 1 /* is_client */ );
+}
+
/*
* svm_region_exit
*/
-void
-svm_region_exit ()
+static void
+svm_region_exit_internal (u8 is_client)
{
void *oldheap;
int i, mypid = getpid ();
found:
- if (vec_len (root_rp->client_pids) == 0)
+ if (!is_client && vec_len (root_rp->client_pids) == 0)
svm_region_unlink (root_rp);
region_unlock (root_rp);
munmap ((void *) virtual_base, virtual_size);
}
+void
+svm_region_exit (void)
+{
+ svm_region_exit_internal (0 /* is_client */ );
+}
+
+void
+svm_region_exit_client (void)
+{
+ svm_region_exit_internal (1 /* is_client */ );
+}
+
void
svm_client_scan_this_region_nolock (svm_region_t * rp)
{