The Pedigree Project 0.1
shared.c
1#define _GNU_SOURCE
2#include <fcntl.h>
3#include <unistd.h>
4
5#include "contract.h"
6#include <sys/mman.h>
7
8int fr_shared(int backend) {
9 int failed = 0, other = -1, duplicate = -1;
10 struct fr_file file = {.fd = -1};
11 const size_t page = fr_page, length = 4 * page, cut = page + 137;
12 unsigned char *shared = MAP_FAILED, *alias = MAP_FAILED, *borrowed = MAP_FAILED;
13 unsigned char byte;
14 CHECK(!fr_create(&file, backend));
15 CHECK((other = fr_open_alias(&file)) >= 0 && (duplicate = dup(file.fd)) >= 0);
16 shared = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, file.fd, 0);
17 alias = mmap(NULL, 3 * page, PROT_READ | PROT_WRITE, MAP_SHARED, other, page);
18 borrowed = mmap(NULL, 3 * page, PROT_READ, MAP_PRIVATE, other, page);
19 CHECK(shared != MAP_FAILED && alias != MAP_FAILED && borrowed != MAP_FAILED);
20 CHECK(fr_matches(shared, 0, length, 0) && fr_matches(alias, page, 3 * page, 0) &&
21 fr_matches(borrowed, page, 3 * page, 0));
22 CHECK(!fr_resident(shared, 4, 15, "shared before shrink") &&
23 !fr_resident(alias, 3, 7, "offset shared before shrink") &&
24 !fr_resident(borrowed, 3, 7, "borrowed private before shrink"));
25 const off_t position = 3 * page + 91;
26 CHECK(lseek(file.fd, position, SEEK_SET) == position);
27 if (file.path[0])
28 CHECK(lseek(other, 7, SEEK_SET) == 7);
29 const off_t other_position = file.path[0] ? 7 : position;
30
31 CHECK(!ftruncate(duplicate, cut));
32 /* Reads would conceal a resize implementation that discarded the valid prefix. */
33 CHECK(!fr_resident(shared, 4, 3, "shared after partial shrink") &&
34 !fr_resident(alias, 3, 1, "offset shared after partial shrink") &&
35 !fr_resident(borrowed, 3, 1, "borrowed private after partial shrink"));
36 CHECK(!fr_size(file.fd, cut) && !fr_size(other, cut));
37 CHECK(lseek(file.fd, 0, SEEK_CUR) == position && lseek(duplicate, 0, SEEK_CUR) == position &&
38 lseek(other, 0, SEEK_CUR) == other_position);
39 CHECK(pread(other, &byte, 1, cut) == 0);
40 CHECK(fr_matches(shared, 0, cut, 0) && fr_matches(shared + cut, cut, 2 * page - cut, 1));
41 CHECK(fr_matches(alias, page, 137, 0) && fr_matches(alias + 137, cut, page - 137, 1));
42 CHECK(fr_matches(borrowed, page, 137, 0) && fr_matches(borrowed + 137, cut, page - 137, 1));
43 CHECK(!fr_contents(file.fd, 0, cut, 0));
44 CHECK(!fr_fault(shared + 2 * page) && !fr_fault(alias + page) && !fr_fault(borrowed + 2 * page));
45
46 CHECK(!ftruncate(other, length));
47 CHECK(!fr_resident(shared, 2, 3, "shared prefix after regrowth") &&
48 !fr_resident(alias, 1, 1, "offset prefix after regrowth"));
49 CHECK(!fr_size(file.fd, length) && fr_matches(shared, 0, cut, 0) &&
50 fr_matches(shared + cut, cut, length - cut, 1));
51 CHECK(fr_matches(alias, page, 137, 0) && fr_matches(alias + 137, cut, length - cut, 1));
52 CHECK(fr_matches(borrowed, page, 137, 0) && fr_matches(borrowed + 137, cut, length - cut, 1));
53 CHECK(!fr_contents(file.fd, 0, cut, 0) && !fr_contents(other, cut, length - cut, 1));
54 alias[137] = 0xd5;
55 CHECK(shared[cut] == 0xd5 && borrowed[137] == 0xd5 && pread(file.fd, &byte, 1, cut) == 1 &&
56 byte == 0xd5);
57 CHECK(lseek(file.fd, 0, SEEK_CUR) == position && lseek(other, 0, SEEK_CUR) == other_position);
58
59 CHECK(!ftruncate(file.fd, page));
60 CHECK(!fr_resident(shared, 4, 1, "shared after aligned shrink") &&
61 !fr_resident(alias, 3, 0, "offset shared after aligned shrink"));
62 CHECK(fr_matches(shared, 0, page, 0) && !fr_fault(shared + page));
63 CHECK(!ftruncate(file.fd, length));
64 CHECK(!fr_resident(shared, 1, 1, "aligned prefix after regrowth"));
65 CHECK(fr_matches(shared, 0, page, 0) && fr_matches(shared + page, page, 3 * page, 1));
66 CHECK(fr_matches(alias, page, 3 * page, 1) && fr_matches(borrowed, page, 3 * page, 1));
67 CHECK(!fr_contents(file.fd, page, 3 * page, 1));
68out:
69 if (borrowed != MAP_FAILED)
70 munmap(borrowed, 3 * page);
71 if (alias != MAP_FAILED)
72 munmap(alias, 3 * page);
73 if (shared != MAP_FAILED)
74 munmap(shared, length);
75 if (duplicate >= 0)
76 close(duplicate);
77 if (other >= 0)
78 close(other);
79 fr_close(&file);
80 return failed;
81}