12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * HMM stands for Heterogeneous Memory Management, it is a helper layer inside
- * the linux kernel to help device drivers mirror a process address space in
- * the device. This allows the device to use the same address space which
- * makes communication and data exchange a lot easier.
- *
- * This framework's sole purpose is to exercise various code paths inside
- * the kernel to make sure that HMM performs as expected and to flush out any
- * bugs.
- */
- #include "../kselftest_harness.h"
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <strings.h>
- #include <time.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- /*
- * This is a private UAPI to the kernel test module so it isn't exported
- * in the usual include/uapi/... directory.
- */
- #include <lib/test_hmm_uapi.h>
- #include <mm/gup_test.h>
- struct hmm_buffer {
- void *ptr;
- void *mirror;
- unsigned long size;
- int fd;
- uint64_t cpages;
- uint64_t faults;
- };
- enum {
- HMM_PRIVATE_DEVICE_ONE,
- HMM_PRIVATE_DEVICE_TWO,
- HMM_COHERENCE_DEVICE_ONE,
- HMM_COHERENCE_DEVICE_TWO,
- };
- #define TWOMEG (1 << 21)
- #define HMM_BUFFER_SIZE (1024 << 12)
- #define HMM_PATH_MAX 64
- #define NTIMES 10
- #define ALIGN(x, a) (((x) + (a - 1)) & (~((a) - 1)))
- /* Just the flags we need, copied from mm.h: */
- #define FOLL_WRITE 0x01 /* check pte is writable */
- #define FOLL_LONGTERM 0x10000 /* mapping lifetime is indefinite */
- FIXTURE(hmm)
- {
- int fd;
- unsigned int page_size;
- unsigned int page_shift;
- };
- FIXTURE_VARIANT(hmm)
- {
- int device_number;
- };
- FIXTURE_VARIANT_ADD(hmm, hmm_device_private)
- {
- .device_number = HMM_PRIVATE_DEVICE_ONE,
- };
- FIXTURE_VARIANT_ADD(hmm, hmm_device_coherent)
- {
- .device_number = HMM_COHERENCE_DEVICE_ONE,
- };
- FIXTURE(hmm2)
- {
- int fd0;
- int fd1;
- unsigned int page_size;
- unsigned int page_shift;
- };
- FIXTURE_VARIANT(hmm2)
- {
- int device_number0;
- int device_number1;
- };
- FIXTURE_VARIANT_ADD(hmm2, hmm2_device_private)
- {
- .device_number0 = HMM_PRIVATE_DEVICE_ONE,
- .device_number1 = HMM_PRIVATE_DEVICE_TWO,
- };
- FIXTURE_VARIANT_ADD(hmm2, hmm2_device_coherent)
- {
- .device_number0 = HMM_COHERENCE_DEVICE_ONE,
- .device_number1 = HMM_COHERENCE_DEVICE_TWO,
- };
- static int hmm_open(int unit)
- {
- char pathname[HMM_PATH_MAX];
- int fd;
- snprintf(pathname, sizeof(pathname), "/dev/hmm_dmirror%d", unit);
- fd = open(pathname, O_RDWR, 0);
- if (fd < 0)
- fprintf(stderr, "could not open hmm dmirror driver (%s)\n",
- pathname);
- return fd;
- }
- static bool hmm_is_coherent_type(int dev_num)
- {
- return (dev_num >= HMM_COHERENCE_DEVICE_ONE);
- }
- FIXTURE_SETUP(hmm)
- {
- self->page_size = sysconf(_SC_PAGE_SIZE);
- self->page_shift = ffs(self->page_size) - 1;
- self->fd = hmm_open(variant->device_number);
- if (self->fd < 0 && hmm_is_coherent_type(variant->device_number))
- SKIP(exit(0), "DEVICE_COHERENT not available");
- ASSERT_GE(self->fd, 0);
- }
- FIXTURE_SETUP(hmm2)
- {
- self->page_size = sysconf(_SC_PAGE_SIZE);
- self->page_shift = ffs(self->page_size) - 1;
- self->fd0 = hmm_open(variant->device_number0);
- if (self->fd0 < 0 && hmm_is_coherent_type(variant->device_number0))
- SKIP(exit(0), "DEVICE_COHERENT not available");
- ASSERT_GE(self->fd0, 0);
- self->fd1 = hmm_open(variant->device_number1);
- ASSERT_GE(self->fd1, 0);
- }
- FIXTURE_TEARDOWN(hmm)
- {
- int ret = close(self->fd);
- ASSERT_EQ(ret, 0);
- self->fd = -1;
- }
- FIXTURE_TEARDOWN(hmm2)
- {
- int ret = close(self->fd0);
- ASSERT_EQ(ret, 0);
- self->fd0 = -1;
- ret = close(self->fd1);
- ASSERT_EQ(ret, 0);
- self->fd1 = -1;
- }
- static int hmm_dmirror_cmd(int fd,
- unsigned long request,
- struct hmm_buffer *buffer,
- unsigned long npages)
- {
- struct hmm_dmirror_cmd cmd;
- int ret;
- /* Simulate a device reading system memory. */
- cmd.addr = (__u64)buffer->ptr;
- cmd.ptr = (__u64)buffer->mirror;
- cmd.npages = npages;
- for (;;) {
- ret = ioctl(fd, request, &cmd);
- if (ret == 0)
- break;
- if (errno == EINTR)
- continue;
- return -errno;
- }
- buffer->cpages = cmd.cpages;
- buffer->faults = cmd.faults;
- return 0;
- }
- static void hmm_buffer_free(struct hmm_buffer *buffer)
- {
- if (buffer == NULL)
- return;
- if (buffer->ptr)
- munmap(buffer->ptr, buffer->size);
- free(buffer->mirror);
- free(buffer);
- }
- /*
- * Create a temporary file that will be deleted on close.
- */
- static int hmm_create_file(unsigned long size)
- {
- char path[HMM_PATH_MAX];
- int fd;
- strcpy(path, "/tmp");
- fd = open(path, O_TMPFILE | O_EXCL | O_RDWR, 0600);
- if (fd >= 0) {
- int r;
- do {
- r = ftruncate(fd, size);
- } while (r == -1 && errno == EINTR);
- if (!r)
- return fd;
- close(fd);
- }
- return -1;
- }
- /*
- * Return a random unsigned number.
- */
- static unsigned int hmm_random(void)
- {
- static int fd = -1;
- unsigned int r;
- if (fd < 0) {
- fd = open("/dev/urandom", O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "%s:%d failed to open /dev/urandom\n",
- __FILE__, __LINE__);
- return ~0U;
- }
- }
- read(fd, &r, sizeof(r));
- return r;
- }
- static void hmm_nanosleep(unsigned int n)
- {
- struct timespec t;
- t.tv_sec = 0;
- t.tv_nsec = n;
- nanosleep(&t, NULL);
- }
- static int hmm_migrate_sys_to_dev(int fd,
- struct hmm_buffer *buffer,
- unsigned long npages)
- {
- return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE_TO_DEV, buffer, npages);
- }
- static int hmm_migrate_dev_to_sys(int fd,
- struct hmm_buffer *buffer,
- unsigned long npages)
- {
- return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE_TO_SYS, buffer, npages);
- }
- /*
- * Simple NULL test of device open/close.
- */
- TEST_F(hmm, open_close)
- {
- }
- /*
- * Read private anonymous memory.
- */
- TEST_F(hmm, anon_read)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- int val;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /*
- * Initialize buffer in system memory but leave the first two pages
- * zero (pte_none and pfn_zero).
- */
- i = 2 * self->page_size / sizeof(*ptr);
- for (ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Set buffer permission to read-only. */
- ret = mprotect(buffer->ptr, size, PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Populate the CPU page table with a special zero page. */
- val = *(int *)(buffer->ptr + self->page_size);
- ASSERT_EQ(val, 0);
- /* Simulate a device reading system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device read. */
- ptr = buffer->mirror;
- for (i = 0; i < 2 * self->page_size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], 0);
- for (; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Read private anonymous memory which has been protected with
- * mprotect() PROT_NONE.
- */
- TEST_F(hmm, anon_read_prot)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Initialize mirror buffer so we can verify it isn't written. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = -i;
- /* Protect buffer from reading. */
- ret = mprotect(buffer->ptr, size, PROT_NONE);
- ASSERT_EQ(ret, 0);
- /* Simulate a device reading system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages);
- ASSERT_EQ(ret, -EFAULT);
- /* Allow CPU to read the buffer so we can check it. */
- ret = mprotect(buffer->ptr, size, PROT_READ);
- ASSERT_EQ(ret, 0);
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], -i);
- hmm_buffer_free(buffer);
- }
- /*
- * Write private anonymous memory.
- */
- TEST_F(hmm, anon_write)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Write private anonymous memory which has been protected with
- * mprotect() PROT_READ.
- */
- TEST_F(hmm, anon_write_prot)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Simulate a device reading a zero page of memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, 1);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, 1);
- ASSERT_EQ(buffer->faults, 1);
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, -EPERM);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], 0);
- /* Now allow writing and see that the zero page is replaced. */
- ret = mprotect(buffer->ptr, size, PROT_WRITE | PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Check that a device writing an anonymous private mapping
- * will copy-on-write if a child process inherits the mapping.
- */
- TEST_F(hmm, anon_write_child)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- pid_t pid;
- int child_fd;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer->ptr so we can tell if it is written. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = -i;
- pid = fork();
- if (pid == -1)
- ASSERT_EQ(pid, 0);
- if (pid != 0) {
- waitpid(pid, &ret, 0);
- ASSERT_EQ(WIFEXITED(ret), 1);
- /* Check that the parent's buffer did not change. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- return;
- }
- /* Check that we see the parent's values. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], -i);
- /* The child process needs its own mirror to its own mm. */
- child_fd = hmm_open(0);
- ASSERT_GE(child_fd, 0);
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(child_fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], -i);
- close(child_fd);
- exit(0);
- }
- /*
- * Check that a device writing an anonymous shared mapping
- * will not copy-on-write if a child process inherits the mapping.
- */
- TEST_F(hmm, anon_write_child_shared)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- pid_t pid;
- int child_fd;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer->ptr so we can tell if it is written. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = -i;
- pid = fork();
- if (pid == -1)
- ASSERT_EQ(pid, 0);
- if (pid != 0) {
- waitpid(pid, &ret, 0);
- ASSERT_EQ(WIFEXITED(ret), 1);
- /* Check that the parent's buffer did change. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], -i);
- return;
- }
- /* Check that we see the parent's values. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], -i);
- /* The child process needs its own mirror to its own mm. */
- child_fd = hmm_open(0);
- ASSERT_GE(child_fd, 0);
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(child_fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], -i);
- close(child_fd);
- exit(0);
- }
- /*
- * Write private anonymous huge page.
- */
- TEST_F(hmm, anon_write_huge)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- void *old_ptr;
- void *map;
- int *ptr;
- int ret;
- size = 2 * TWOMEG;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- size = TWOMEG;
- npages = size >> self->page_shift;
- map = (void *)ALIGN((uintptr_t)buffer->ptr, size);
- ret = madvise(map, size, MADV_HUGEPAGE);
- ASSERT_EQ(ret, 0);
- old_ptr = buffer->ptr;
- buffer->ptr = map;
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- buffer->ptr = old_ptr;
- hmm_buffer_free(buffer);
- }
- /*
- * Read numeric data from raw and tagged kernel status files. Used to read
- * /proc and /sys data (without a tag) and from /proc/meminfo (with a tag).
- */
- static long file_read_ulong(char *file, const char *tag)
- {
- int fd;
- char buf[2048];
- int len;
- char *p, *q;
- long val;
- fd = open(file, O_RDONLY);
- if (fd < 0) {
- /* Error opening the file */
- return -1;
- }
- len = read(fd, buf, sizeof(buf));
- close(fd);
- if (len < 0) {
- /* Error in reading the file */
- return -1;
- }
- if (len == sizeof(buf)) {
- /* Error file is too large */
- return -1;
- }
- buf[len] = '\0';
- /* Search for a tag if provided */
- if (tag) {
- p = strstr(buf, tag);
- if (!p)
- return -1; /* looks like the line we want isn't there */
- p += strlen(tag);
- } else
- p = buf;
- val = strtol(p, &q, 0);
- if (*q != ' ') {
- /* Error parsing the file */
- return -1;
- }
- return val;
- }
- /*
- * Write huge TLBFS page.
- */
- TEST_F(hmm, anon_write_hugetlbfs)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long default_hsize;
- unsigned long i;
- int *ptr;
- int ret;
- default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:");
- if (default_hsize < 0 || default_hsize*1024 < default_hsize)
- SKIP(return, "Huge page size could not be determined");
- default_hsize = default_hsize*1024; /* KB to B */
- size = ALIGN(TWOMEG, default_hsize);
- npages = size >> self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
- -1, 0);
- if (buffer->ptr == MAP_FAILED) {
- free(buffer);
- SKIP(return, "Huge page could not be allocated");
- }
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- munmap(buffer->ptr, buffer->size);
- buffer->ptr = NULL;
- hmm_buffer_free(buffer);
- }
- /*
- * Read mmap'ed file memory.
- */
- TEST_F(hmm, file_read)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- int fd;
- ssize_t len;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- fd = hmm_create_file(size);
- ASSERT_GE(fd, 0);
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = fd;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- /* Write initial contents of the file. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- len = pwrite(fd, buffer->mirror, size, 0);
- ASSERT_EQ(len, size);
- memset(buffer->mirror, 0, size);
- buffer->ptr = mmap(NULL, size,
- PROT_READ,
- MAP_SHARED,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Simulate a device reading system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Write mmap'ed file memory.
- */
- TEST_F(hmm, file_write)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- int fd;
- ssize_t len;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- fd = hmm_create_file(size);
- ASSERT_GE(fd, 0);
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = fd;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize data that the device will write to buffer->ptr. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device wrote. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Check that the device also wrote the file. */
- len = pread(fd, buffer->mirror, size, 0);
- ASSERT_EQ(len, size);
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Migrate anonymous memory to device private memory.
- */
- TEST_F(hmm, migrate)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Migrate anonymous memory to device private memory and fault some of it back
- * to system memory, then try migrating the resulting mix of system and device
- * private memory to the device.
- */
- TEST_F(hmm, migrate_fault)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Fault half the pages back to system memory and check them. */
- for (i = 0, ptr = buffer->ptr; i < size / (2 * sizeof(*ptr)); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Migrate memory to the device again. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- TEST_F(hmm, migrate_release)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Release device memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_RELEASE, buffer, npages);
- ASSERT_EQ(ret, 0);
- /* Fault pages back to system memory and check them. */
- for (i = 0, ptr = buffer->ptr; i < size / (2 * sizeof(*ptr)); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Migrate anonymous shared memory to device private memory.
- */
- TEST_F(hmm, migrate_shared)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, -ENOENT);
- hmm_buffer_free(buffer);
- }
- /*
- * Try to migrate various memory types to device private memory.
- */
- TEST_F(hmm2, migrate_mixed)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- int *ptr;
- unsigned char *p;
- int ret;
- int val;
- npages = 6;
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- /* Reserve a range of addresses. */
- buffer->ptr = mmap(NULL, size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- p = buffer->ptr;
- /* Migrating a protected area should be an error. */
- ret = hmm_migrate_sys_to_dev(self->fd1, buffer, npages);
- ASSERT_EQ(ret, -EINVAL);
- /* Punch a hole after the first page address. */
- ret = munmap(buffer->ptr + self->page_size, self->page_size);
- ASSERT_EQ(ret, 0);
- /* We expect an error if the vma doesn't cover the range. */
- ret = hmm_migrate_sys_to_dev(self->fd1, buffer, 3);
- ASSERT_EQ(ret, -EINVAL);
- /* Page 2 will be a read-only zero page. */
- ret = mprotect(buffer->ptr + 2 * self->page_size, self->page_size,
- PROT_READ);
- ASSERT_EQ(ret, 0);
- ptr = (int *)(buffer->ptr + 2 * self->page_size);
- val = *ptr + 3;
- ASSERT_EQ(val, 3);
- /* Page 3 will be read-only. */
- ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size,
- PROT_READ | PROT_WRITE);
- ASSERT_EQ(ret, 0);
- ptr = (int *)(buffer->ptr + 3 * self->page_size);
- *ptr = val;
- ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size,
- PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Page 4-5 will be read-write. */
- ret = mprotect(buffer->ptr + 4 * self->page_size, 2 * self->page_size,
- PROT_READ | PROT_WRITE);
- ASSERT_EQ(ret, 0);
- ptr = (int *)(buffer->ptr + 4 * self->page_size);
- *ptr = val;
- ptr = (int *)(buffer->ptr + 5 * self->page_size);
- *ptr = val;
- /* Now try to migrate pages 2-5 to device 1. */
- buffer->ptr = p + 2 * self->page_size;
- ret = hmm_migrate_sys_to_dev(self->fd1, buffer, 4);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, 4);
- /* Page 5 won't be migrated to device 0 because it's on device 1. */
- buffer->ptr = p + 5 * self->page_size;
- ret = hmm_migrate_sys_to_dev(self->fd0, buffer, 1);
- ASSERT_EQ(ret, -ENOENT);
- buffer->ptr = p;
- buffer->ptr = p;
- hmm_buffer_free(buffer);
- }
- /*
- * Migrate anonymous memory to device memory and back to system memory
- * multiple times. In case of private zone configuration, this is done
- * through fault pages accessed by CPU. In case of coherent zone configuration,
- * the pages from the device should be explicitly migrated back to system memory.
- * The reason is Coherent device zone has coherent access by CPU, therefore
- * it will not generate any page fault.
- */
- TEST_F(hmm, migrate_multiple)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- unsigned long c;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- for (c = 0; c < NTIMES; c++) {
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Migrate back to system memory and check them. */
- if (hmm_is_coherent_type(variant->device_number)) {
- ret = hmm_migrate_dev_to_sys(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- }
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- }
- /*
- * Read anonymous memory multiple times.
- */
- TEST_F(hmm, anon_read_multiple)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- unsigned long c;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- for (c = 0; c < NTIMES; c++) {
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i + c;
- /* Simulate a device reading system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer,
- npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i + c);
- hmm_buffer_free(buffer);
- }
- }
- void *unmap_buffer(void *p)
- {
- struct hmm_buffer *buffer = p;
- /* Delay for a bit and then unmap buffer while it is being read. */
- hmm_nanosleep(hmm_random() % 32000);
- munmap(buffer->ptr + buffer->size / 2, buffer->size / 2);
- buffer->ptr = NULL;
- return NULL;
- }
- /*
- * Try reading anonymous memory while it is being unmapped.
- */
- TEST_F(hmm, anon_teardown)
- {
- unsigned long npages;
- unsigned long size;
- unsigned long c;
- void *ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- for (c = 0; c < NTIMES; ++c) {
- pthread_t thread;
- struct hmm_buffer *buffer;
- unsigned long i;
- int *ptr;
- int rc;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i + c;
- rc = pthread_create(&thread, NULL, unmap_buffer, buffer);
- ASSERT_EQ(rc, 0);
- /* Simulate a device reading system memory. */
- rc = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer,
- npages);
- if (rc == 0) {
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror;
- i < size / sizeof(*ptr);
- ++i)
- ASSERT_EQ(ptr[i], i + c);
- }
- pthread_join(thread, &ret);
- hmm_buffer_free(buffer);
- }
- }
- /*
- * Test memory snapshot without faulting in pages accessed by the device.
- */
- TEST_F(hmm, mixedmap)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned char *m;
- int ret;
- npages = 1;
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(npages);
- ASSERT_NE(buffer->mirror, NULL);
- /* Reserve a range of addresses. */
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE,
- self->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Simulate a device snapshotting CPU pagetables. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device saw. */
- m = buffer->mirror;
- ASSERT_EQ(m[0], HMM_DMIRROR_PROT_READ);
- hmm_buffer_free(buffer);
- }
- /*
- * Test memory snapshot without faulting in pages accessed by the device.
- */
- TEST_F(hmm2, snapshot)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- int *ptr;
- unsigned char *p;
- unsigned char *m;
- int ret;
- int val;
- npages = 7;
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(npages);
- ASSERT_NE(buffer->mirror, NULL);
- /* Reserve a range of addresses. */
- buffer->ptr = mmap(NULL, size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- p = buffer->ptr;
- /* Punch a hole after the first page address. */
- ret = munmap(buffer->ptr + self->page_size, self->page_size);
- ASSERT_EQ(ret, 0);
- /* Page 2 will be read-only zero page. */
- ret = mprotect(buffer->ptr + 2 * self->page_size, self->page_size,
- PROT_READ);
- ASSERT_EQ(ret, 0);
- ptr = (int *)(buffer->ptr + 2 * self->page_size);
- val = *ptr + 3;
- ASSERT_EQ(val, 3);
- /* Page 3 will be read-only. */
- ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size,
- PROT_READ | PROT_WRITE);
- ASSERT_EQ(ret, 0);
- ptr = (int *)(buffer->ptr + 3 * self->page_size);
- *ptr = val;
- ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size,
- PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Page 4-6 will be read-write. */
- ret = mprotect(buffer->ptr + 4 * self->page_size, 3 * self->page_size,
- PROT_READ | PROT_WRITE);
- ASSERT_EQ(ret, 0);
- ptr = (int *)(buffer->ptr + 4 * self->page_size);
- *ptr = val;
- /* Page 5 will be migrated to device 0. */
- buffer->ptr = p + 5 * self->page_size;
- ret = hmm_migrate_sys_to_dev(self->fd0, buffer, 1);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, 1);
- /* Page 6 will be migrated to device 1. */
- buffer->ptr = p + 6 * self->page_size;
- ret = hmm_migrate_sys_to_dev(self->fd1, buffer, 1);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, 1);
- /* Simulate a device snapshotting CPU pagetables. */
- buffer->ptr = p;
- ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_SNAPSHOT, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device saw. */
- m = buffer->mirror;
- ASSERT_EQ(m[0], HMM_DMIRROR_PROT_ERROR);
- ASSERT_EQ(m[1], HMM_DMIRROR_PROT_ERROR);
- ASSERT_EQ(m[2], HMM_DMIRROR_PROT_ZERO | HMM_DMIRROR_PROT_READ);
- ASSERT_EQ(m[3], HMM_DMIRROR_PROT_READ);
- ASSERT_EQ(m[4], HMM_DMIRROR_PROT_WRITE);
- if (!hmm_is_coherent_type(variant->device_number0)) {
- ASSERT_EQ(m[5], HMM_DMIRROR_PROT_DEV_PRIVATE_LOCAL |
- HMM_DMIRROR_PROT_WRITE);
- ASSERT_EQ(m[6], HMM_DMIRROR_PROT_NONE);
- } else {
- ASSERT_EQ(m[5], HMM_DMIRROR_PROT_DEV_COHERENT_LOCAL |
- HMM_DMIRROR_PROT_WRITE);
- ASSERT_EQ(m[6], HMM_DMIRROR_PROT_DEV_COHERENT_REMOTE |
- HMM_DMIRROR_PROT_WRITE);
- }
- hmm_buffer_free(buffer);
- }
- /*
- * Test the hmm_range_fault() HMM_PFN_PMD flag for large pages that
- * should be mapped by a large page table entry.
- */
- TEST_F(hmm, compound)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long default_hsize;
- int *ptr;
- unsigned char *m;
- int ret;
- unsigned long i;
- /* Skip test if we can't allocate a hugetlbfs page. */
- default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:");
- if (default_hsize < 0 || default_hsize*1024 < default_hsize)
- SKIP(return, "Huge page size could not be determined");
- default_hsize = default_hsize*1024; /* KB to B */
- size = ALIGN(TWOMEG, default_hsize);
- npages = size >> self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
- -1, 0);
- if (buffer->ptr == MAP_FAILED) {
- free(buffer);
- return;
- }
- buffer->size = size;
- buffer->mirror = malloc(npages);
- ASSERT_NE(buffer->mirror, NULL);
- /* Initialize the pages the device will snapshot in buffer->ptr. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Simulate a device snapshotting CPU pagetables. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device saw. */
- m = buffer->mirror;
- for (i = 0; i < npages; ++i)
- ASSERT_EQ(m[i], HMM_DMIRROR_PROT_WRITE |
- HMM_DMIRROR_PROT_PMD);
- /* Make the region read-only. */
- ret = mprotect(buffer->ptr, size, PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Simulate a device snapshotting CPU pagetables. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device saw. */
- m = buffer->mirror;
- for (i = 0; i < npages; ++i)
- ASSERT_EQ(m[i], HMM_DMIRROR_PROT_READ |
- HMM_DMIRROR_PROT_PMD);
- munmap(buffer->ptr, buffer->size);
- buffer->ptr = NULL;
- hmm_buffer_free(buffer);
- }
- /*
- * Test two devices reading the same memory (double mapped).
- */
- TEST_F(hmm2, double_map)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = 6;
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(npages);
- ASSERT_NE(buffer->mirror, NULL);
- /* Reserve a range of addresses. */
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Make region read-only. */
- ret = mprotect(buffer->ptr, size, PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Simulate device 0 reading system memory. */
- ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_READ, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Simulate device 1 reading system memory. */
- ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_READ, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Migrate pages to device 1 and try to read from device 0. */
- ret = hmm_migrate_sys_to_dev(self->fd1, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_READ, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- ASSERT_EQ(buffer->faults, 1);
- /* Check what device 0 read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- hmm_buffer_free(buffer);
- }
- /*
- * Basic check of exclusive faulting.
- */
- TEST_F(hmm, exclusive)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Map memory exclusively for device access. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- /* Fault pages back to system memory and check them. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i]++, i);
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i+1);
- /* Check atomic access revoked */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_CHECK_EXCLUSIVE, buffer, npages);
- ASSERT_EQ(ret, 0);
- hmm_buffer_free(buffer);
- }
- TEST_F(hmm, exclusive_mprotect)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Map memory exclusively for device access. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- ret = mprotect(buffer->ptr, size, PROT_READ);
- ASSERT_EQ(ret, 0);
- /* Simulate a device writing system memory. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
- ASSERT_EQ(ret, -EPERM);
- hmm_buffer_free(buffer);
- }
- /*
- * Check copy-on-write works.
- */
- TEST_F(hmm, exclusive_cow)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
- ASSERT_NE(npages, 0);
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Map memory exclusively for device access. */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- fork();
- /* Fault pages back to system memory and check them. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i]++, i);
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i+1);
- hmm_buffer_free(buffer);
- }
- static int gup_test_exec(int gup_fd, unsigned long addr, int cmd,
- int npages, int size, int flags)
- {
- struct gup_test gup = {
- .nr_pages_per_call = npages,
- .addr = addr,
- .gup_flags = FOLL_WRITE | flags,
- .size = size,
- };
- if (ioctl(gup_fd, cmd, &gup)) {
- perror("ioctl on error\n");
- return errno;
- }
- return 0;
- }
- /*
- * Test get user device pages through gup_test. Setting PIN_LONGTERM flag.
- * This should trigger a migration back to system memory for both, private
- * and coherent type pages.
- * This test makes use of gup_test module. Make sure GUP_TEST_CONFIG is added
- * to your configuration before you run it.
- */
- TEST_F(hmm, hmm_gup_test)
- {
- struct hmm_buffer *buffer;
- int gup_fd;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- unsigned char *m;
- gup_fd = open("/sys/kernel/debug/gup_test", O_RDWR);
- if (gup_fd == -1)
- SKIP(return, "Skipping test, could not find gup_test driver");
- npages = 4;
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- /* Check what the device read. */
- for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- ASSERT_EQ(gup_test_exec(gup_fd,
- (unsigned long)buffer->ptr,
- GUP_BASIC_TEST, 1, self->page_size, 0), 0);
- ASSERT_EQ(gup_test_exec(gup_fd,
- (unsigned long)buffer->ptr + 1 * self->page_size,
- GUP_FAST_BENCHMARK, 1, self->page_size, 0), 0);
- ASSERT_EQ(gup_test_exec(gup_fd,
- (unsigned long)buffer->ptr + 2 * self->page_size,
- PIN_FAST_BENCHMARK, 1, self->page_size, FOLL_LONGTERM), 0);
- ASSERT_EQ(gup_test_exec(gup_fd,
- (unsigned long)buffer->ptr + 3 * self->page_size,
- PIN_LONGTERM_BENCHMARK, 1, self->page_size, 0), 0);
- /* Take snapshot to CPU pagetables */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- m = buffer->mirror;
- if (hmm_is_coherent_type(variant->device_number)) {
- ASSERT_EQ(HMM_DMIRROR_PROT_DEV_COHERENT_LOCAL | HMM_DMIRROR_PROT_WRITE, m[0]);
- ASSERT_EQ(HMM_DMIRROR_PROT_DEV_COHERENT_LOCAL | HMM_DMIRROR_PROT_WRITE, m[1]);
- } else {
- ASSERT_EQ(HMM_DMIRROR_PROT_WRITE, m[0]);
- ASSERT_EQ(HMM_DMIRROR_PROT_WRITE, m[1]);
- }
- ASSERT_EQ(HMM_DMIRROR_PROT_WRITE, m[2]);
- ASSERT_EQ(HMM_DMIRROR_PROT_WRITE, m[3]);
- /*
- * Check again the content on the pages. Make sure there's no
- * corrupted data.
- */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ASSERT_EQ(ptr[i], i);
- close(gup_fd);
- hmm_buffer_free(buffer);
- }
- /*
- * Test copy-on-write in device pages.
- * In case of writing to COW private page(s), a page fault will migrate pages
- * back to system memory first. Then, these pages will be duplicated. In case
- * of COW device coherent type, pages are duplicated directly from device
- * memory.
- */
- TEST_F(hmm, hmm_cow_in_device)
- {
- struct hmm_buffer *buffer;
- unsigned long npages;
- unsigned long size;
- unsigned long i;
- int *ptr;
- int ret;
- unsigned char *m;
- pid_t pid;
- int status;
- npages = 4;
- size = npages << self->page_shift;
- buffer = malloc(sizeof(*buffer));
- ASSERT_NE(buffer, NULL);
- buffer->fd = -1;
- buffer->size = size;
- buffer->mirror = malloc(size);
- ASSERT_NE(buffer->mirror, NULL);
- buffer->ptr = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- buffer->fd, 0);
- ASSERT_NE(buffer->ptr, MAP_FAILED);
- /* Initialize buffer in system memory. */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Migrate memory to device. */
- ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- pid = fork();
- if (pid == -1)
- ASSERT_EQ(pid, 0);
- if (!pid) {
- /* Child process waitd for SIGTERM from the parent. */
- while (1) {
- }
- perror("Should not reach this\n");
- exit(0);
- }
- /* Parent process writes to COW pages(s) and gets a
- * new copy in system. In case of device private pages,
- * this write causes a migration to system mem first.
- */
- for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
- ptr[i] = i;
- /* Terminate child and wait */
- EXPECT_EQ(0, kill(pid, SIGTERM));
- EXPECT_EQ(pid, waitpid(pid, &status, 0));
- EXPECT_NE(0, WIFSIGNALED(status));
- EXPECT_EQ(SIGTERM, WTERMSIG(status));
- /* Take snapshot to CPU pagetables */
- ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
- ASSERT_EQ(ret, 0);
- ASSERT_EQ(buffer->cpages, npages);
- m = buffer->mirror;
- for (i = 0; i < npages; i++)
- ASSERT_EQ(HMM_DMIRROR_PROT_WRITE, m[i]);
- hmm_buffer_free(buffer);
- }
- TEST_HARNESS_MAIN
|