Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  mlock2-tests.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <sys/mman.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdbool.h>
#include "../kselftest.h"
#include "mlock2.h"

struct vm_boundaries {
 unsigned long start;
 unsigned long end;
};

static int get_vm_area(unsigned long addr, struct vm_boundaries *area)
{
 FILE *file;
 int ret = 1;
 char line[1024] = {0};
 unsigned long start;
 unsigned long end;

 if (!area)
  return ret;

 file = fopen("/proc/self/maps""r");
 if (!file) {
  perror("fopen");
  return ret;
 }

 memset(area, 0, sizeof(struct vm_boundaries));

 while(fgets(line, 1024, file)) {
  if (sscanf(line, "%lx-%lx", &start, &end) != 2) {
   ksft_print_msg("cannot parse /proc/self/maps\n");
   goto out;
  }

  if (start <= addr && end > addr) {
   area->start = start;
   area->end = end;
   ret = 0;
   goto out;
  }
 }
out:
 fclose(file);
 return ret;
}

#define VMFLAGS "VmFlags:"

static bool is_vmflag_set(unsigned long addr, const char *vmflag)
{
 char *line = NULL;
 char *flags;
 size_t size = 0;
 bool ret = false;
 FILE *smaps;

 smaps = seek_to_smaps_entry(addr);
 if (!smaps) {
  ksft_print_msg("Unable to parse /proc/self/smaps\n");
  goto out;
 }

 while (getline(&line, &size, smaps) > 0) {
  if (!strstr(line, VMFLAGS)) {
   free(line);
   line = NULL;
   size = 0;
   continue;
  }

  flags = line + strlen(VMFLAGS);
  ret = (strstr(flags, vmflag) != NULL);
  goto out;
 }

out:
 free(line);
 fclose(smaps);
 return ret;
}

#define SIZE "Size:"
#define RSS  "Rss:"
#define LOCKED "lo"

static unsigned long get_value_for_name(unsigned long addr, const char *name)
{
 char *line = NULL;
 size_t size = 0;
 char *value_ptr;
 FILE *smaps = NULL;
 unsigned long value = -1UL;

 smaps = seek_to_smaps_entry(addr);
 if (!smaps) {
  ksft_print_msg("Unable to parse /proc/self/smaps\n");
  goto out;
 }

 while (getline(&line, &size, smaps) > 0) {
  if (!strstr(line, name)) {
   free(line);
   line = NULL;
   size = 0;
   continue;
  }

  value_ptr = line + strlen(name);
  if (sscanf(value_ptr, "%lu kB", &value) < 1) {
   ksft_print_msg("Unable to parse smaps entry for Size\n");
   goto out;
  }
  break;
 }

out:
 if (smaps)
  fclose(smaps);
 free(line);
 return value;
}

static bool is_vma_lock_on_fault(unsigned long addr)
{
 bool locked;
 unsigned long vma_size, vma_rss;

 locked = is_vmflag_set(addr, LOCKED);
 if (!locked)
  return false;

 vma_size = get_value_for_name(addr, SIZE);
 vma_rss = get_value_for_name(addr, RSS);

 /* only one page is faulted in */
 return (vma_rss < vma_size);
}

#define PRESENT_BIT     0x8000000000000000ULL
#define PFN_MASK        0x007FFFFFFFFFFFFFULL
#define UNEVICTABLE_BIT (1UL << 18)

static int lock_check(unsigned long addr)
{
 bool locked;
 unsigned long vma_size, vma_rss;

 locked = is_vmflag_set(addr, LOCKED);
 if (!locked)
  return false;

 vma_size = get_value_for_name(addr, SIZE);
 vma_rss = get_value_for_name(addr, RSS);

 return (vma_rss == vma_size);
}

static int unlock_lock_check(char *map)
{
 if (is_vmflag_set((unsigned long)map, LOCKED)) {
  ksft_print_msg("VMA flag %s is present on page 1 after unlock\n", LOCKED);
  return 1;
 }

 return 0;
}

static void test_mlock_lock(void)
{
 char *map;
 unsigned long page_size = getpagesize();

 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s", strerror(errno));

 if (mlock2_(map, 2 * page_size, 0)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("mlock2(0): %s\n", strerror(errno));
 }

 ksft_test_result(lock_check((unsigned long)map), "%s: Locked\n", __func__);

 /* Now unlock and recheck attributes */
 if (munlock(map, 2 * page_size)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("munlock(): %s\n", strerror(errno));
 }

 ksft_test_result(!unlock_lock_check(map), "%s: Unlocked\n", __func__);
 munmap(map, 2 * page_size);
}

static int onfault_check(char *map)
{
 *map = 'a';
 if (!is_vma_lock_on_fault((unsigned long)map)) {
  ksft_print_msg("VMA is not marked for lock on fault\n");
  return 1;
 }

 return 0;
}

static int unlock_onfault_check(char *map)
{
 unsigned long page_size = getpagesize();

 if (is_vma_lock_on_fault((unsigned long)map) ||
     is_vma_lock_on_fault((unsigned long)map + page_size)) {
  ksft_print_msg("VMA is still lock on fault after unlock\n");
  return 1;
 }

 return 0;
}

static void test_mlock_onfault(void)
{
 char *map;
 unsigned long page_size = getpagesize();

 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s", strerror(errno));

 if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("mlock2(MLOCK_ONFAULT): %s\n", strerror(errno));
 }

 ksft_test_result(!onfault_check(map), "%s: VMA marked for lock on fault\n", __func__);

 /* Now unlock and recheck attributes */
 if (munlock(map, 2 * page_size)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("munlock(): %s\n", strerror(errno));
 }

 ksft_test_result(!unlock_onfault_check(map), "VMA open lock after fault\n");
 munmap(map, 2 * page_size);
}

static void test_lock_onfault_of_present(void)
{
 char *map;
 unsigned long page_size = getpagesize();

 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s", strerror(errno));

 *map = 'a';

 if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) {
  munmap(map, 2 * page_size);
  ksft_test_result_fail("mlock2(MLOCK_ONFAULT) error: %s", strerror(errno));
 }

 ksft_test_result(is_vma_lock_on_fault((unsigned long)map) ||
    is_vma_lock_on_fault((unsigned long)map + page_size),
    "VMA with present pages is not marked lock on fault\n");
 munmap(map, 2 * page_size);
}

static void test_munlockall0(void)
{
 char *map;
 unsigned long page_size = getpagesize();

 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s\n", strerror(errno));

 if (mlockall(MCL_CURRENT)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("mlockall(MCL_CURRENT): %s\n", strerror(errno));
 }

 ksft_test_result(lock_check((unsigned long)map), "%s: Locked memory area\n", __func__);

 if (munlockall()) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("munlockall(): %s\n", strerror(errno));
 }

 ksft_test_result(!unlock_lock_check(map), "%s: No locked memory\n", __func__);
 munmap(map, 2 * page_size);
}

static void test_munlockall1(void)
{
 char *map;
 unsigned long page_size = getpagesize();

 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s", strerror(errno));

 if (mlockall(MCL_CURRENT | MCL_ONFAULT)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("mlockall(MCL_CURRENT | MCL_ONFAULT): %s\n", strerror(errno));
 }

 ksft_test_result(!onfault_check(map), "%s: VMA marked for lock on fault\n", __func__);

 if (munlockall()) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("munlockall(): %s\n", strerror(errno));
 }

 ksft_test_result(!unlock_onfault_check(map), "%s: Unlocked\n", __func__);

 if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("mlockall(MCL_CURRENT | MCL_FUTURE): %s\n", strerror(errno));
 }

 ksft_test_result(lock_check((unsigned long)map), "%s: Locked\n", __func__);

 if (munlockall()) {
  munmap(map, 2 * page_size);
  ksft_exit_fail_msg("munlockall() %s\n", strerror(errno));
 }

 ksft_test_result(!unlock_lock_check(map), "%s: No locked memory\n", __func__);
 munmap(map, 2 * page_size);
}

static void test_vma_management(bool call_mlock)
{
 void *map;
 unsigned long page_size = getpagesize();
 struct vm_boundaries page1;
 struct vm_boundaries page2;
 struct vm_boundaries page3;

 map = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s", strerror(errno));

 if (call_mlock && mlock2_(map, 3 * page_size, MLOCK_ONFAULT)) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("mlock error: %s", strerror(errno));
 }

 if (get_vm_area((unsigned long)map, &page1) ||
     get_vm_area((unsigned long)map + page_size, &page2) ||
     get_vm_area((unsigned long)map + page_size * 2, &page3)) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("couldn't find mapping in /proc/self/maps");
 }

 /*
 * Before we unlock a portion, we need to that all three pages are in
 * the same VMA.  If they are not we abort this test (Note that this is
 * not a failure)
 */

 if (page1.start != page2.start || page2.start != page3.start) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("VMAs are not merged to start, aborting test");
 }

 if (munlock(map + page_size, page_size)) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("munlock(): %s", strerror(errno));
 }

 if (get_vm_area((unsigned long)map, &page1) ||
     get_vm_area((unsigned long)map + page_size, &page2) ||
     get_vm_area((unsigned long)map + page_size * 2, &page3)) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("couldn't find mapping in /proc/self/maps");
 }

 /* All three VMAs should be different */
 if (page1.start == page2.start || page2.start == page3.start) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("failed to split VMA for munlock");
 }

 /* Now unlock the first and third page and check the VMAs again */
 if (munlock(map, page_size * 3)) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("munlock(): %s", strerror(errno));
 }

 if (get_vm_area((unsigned long)map, &page1) ||
     get_vm_area((unsigned long)map + page_size, &page2) ||
     get_vm_area((unsigned long)map + page_size * 2, &page3)) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("couldn't find mapping in /proc/self/maps");
 }

 /* Now all three VMAs should be the same */
 if (page1.start != page2.start || page2.start != page3.start) {
  munmap(map, 3 * page_size);
  ksft_test_result_fail("failed to merge VMAs after munlock");
 }

 ksft_test_result_pass("%s call_mlock %d\n", __func__, call_mlock);
 munmap(map, 3 * page_size);
}

static void test_mlockall(void)
{
 if (mlockall(MCL_CURRENT | MCL_ONFAULT | MCL_FUTURE))
  ksft_exit_fail_msg("mlockall failed: %s\n", strerror(errno));

 test_vma_management(false);
 munlockall();
}

int main(int argc, char **argv)
{
 int ret, size = 3 * getpagesize();
 void *map;

 ksft_print_header();

 map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 if (map == MAP_FAILED)
  ksft_exit_fail_msg("mmap error: %s", strerror(errno));

 ret = mlock2_(map, size, MLOCK_ONFAULT);
 if (ret && errno == ENOSYS)
  ksft_finished();

 munmap(map, size);

 ksft_set_plan(13);

 test_mlock_lock();
 test_mlock_onfault();
 test_munlockall0();
 test_munlockall1();
 test_lock_onfault_of_present();
 test_vma_management(true);
 test_mlockall();

 ksft_finished();
}

Messung V0.5
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge