/* * Get the MMUPageSize of the memory region including input * address from proc file. * * return value: on error case, 0 will be returned. * Otherwise the page size(in bytes) is returned.
*/ int get_proc_page_size(unsignedlong addr)
{
FILE *smaps; char *line; unsignedlong mmupage_size = 0;
size_t size;
smaps = seek_to_smaps_entry(addr); if (!smaps)
ksft_exit_fail_msg("Unable to parse /proc/self/smaps\n");
while (getline(&line, &size, smaps) > 0) { if (!strstr(line, "MMUPageSize")) {
free(line);
line = NULL;
size = 0; continue;
}
/* found the MMUPageSize of this section */ if (sscanf(line, "MMUPageSize: %8lu kB", &mmupage_size) < 1)
ksft_exit_fail_msg("Unable to parse smaps entry for Size:%s\n",
line);
}
free(line); if (smaps)
fclose(smaps); return mmupage_size << 10;
}
/* * Test mlock/mlock2() on provided memory chunk. * It expects the mlock/mlock2() to be successful (within rlimit) * * With allocated memory chunk [p, p + alloc_size), this * test will choose start/len randomly to perform mlock/mlock2 * [start, start + len] memory range. The range is within range * of the allocated chunk. * * The memory region size alloc_size is within the rlimit. * So we always expect a success of mlock/mlock2. * * VmLck is assumed to be 0 before this test. * * return value: 0 - success * else: failure
*/ staticvoid test_mlock_within_limit(char *p, int alloc_size)
{ int i; int ret = 0; int locked_vm_size = 0; struct rlimit cur; int page_size = 0;
getrlimit(RLIMIT_MEMLOCK, &cur); if (cur.rlim_cur < alloc_size)
ksft_exit_fail_msg("alloc_size[%d] < %u rlimit,lead to mlock failure\n",
alloc_size, (unsignedint)cur.rlim_cur);
srand(time(NULL)); for (i = 0; i < TEST_LOOP; i++) { /* * - choose mlock/mlock2 randomly * - choose lock_size randomly but lock_size < alloc_size * - choose start_offset randomly but p+start_offset+lock_size * < p+alloc_size
*/ int is_mlock = !!(rand() % 2); int lock_size = rand() % alloc_size; int start_offset = rand() % (alloc_size - lock_size);
if (is_mlock)
ret = mlock(p + start_offset, lock_size); else
ret = mlock2_(p + start_offset, lock_size,
MLOCK_ONFAULT);
if (ret)
ksft_exit_fail_msg("%s() failure (%s) at |%p(%d)| mlock:|%p(%d)|\n",
is_mlock ? "mlock" : "mlock2",
strerror(errno), p, alloc_size,
p + start_offset, lock_size);
}
/* * Check VmLck left by the tests.
*/
locked_vm_size = get_proc_locked_vm_size();
page_size = get_proc_page_size((unsignedlong)p);
if (locked_vm_size > PAGE_ALIGN(alloc_size, page_size) + page_size)
ksft_exit_fail_msg("%s left VmLck:%d on %d chunk\n",
__func__, locked_vm_size, alloc_size);
ksft_test_result_pass("%s\n", __func__);
}
/* * We expect the mlock/mlock2() to be fail (outof limitation) * * With allocated memory chunk [p, p + alloc_size), this * test will randomly choose start/len and perform mlock/mlock2 * on [start, start+len] range. * * The memory region size alloc_size is above the rlimit. * And the len to be locked is higher than rlimit. * So we always expect a failure of mlock/mlock2. * No locked page number should be increased as a side effect. * * return value: 0 - success * else: failure
*/ staticvoid test_mlock_outof_limit(char *p, int alloc_size)
{ int i; int ret = 0; int locked_vm_size = 0, old_locked_vm_size = 0; struct rlimit cur;
getrlimit(RLIMIT_MEMLOCK, &cur); if (cur.rlim_cur >= alloc_size)
ksft_exit_fail_msg("alloc_size[%d] >%u rlimit, violates test condition\n",
alloc_size, (unsignedint)cur.rlim_cur);
old_locked_vm_size = get_proc_locked_vm_size();
srand(time(NULL)); for (i = 0; i < TEST_LOOP; i++) { int is_mlock = !!(rand() % 2); int lock_size = (rand() % (alloc_size - cur.rlim_cur))
+ cur.rlim_cur; int start_offset = rand() % (alloc_size - lock_size);
if (is_mlock)
ret = mlock(p + start_offset, lock_size); else
ret = mlock2_(p + start_offset, lock_size,
MLOCK_ONFAULT); if (ret == 0)
ksft_exit_fail_msg("%s() succeeds? on %p(%d) mlock%p(%d)\n",
is_mlock ? "mlock" : "mlock2",
p, alloc_size, p + start_offset, lock_size);
}
locked_vm_size = get_proc_locked_vm_size(); if (locked_vm_size != old_locked_vm_size)
ksft_exit_fail_msg("tests leads to new mlocked page: old[%d], new[%d]\n",
old_locked_vm_size,
locked_vm_size);
ksft_test_result_pass("%s\n", __func__);
}
int main(int argc, char **argv)
{ char *p = NULL;
ksft_print_header();
if (set_cap_limits(MLOCK_RLIMIT_SIZE))
ksft_finished();
ksft_set_plan(2);
p = malloc(MLOCK_WITHIN_LIMIT_SIZE); if (p == NULL)
ksft_exit_fail_msg("malloc() failure: %s\n", strerror(errno));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.