9enum { CREATE, REPLACE, REMOVE, WRITE_MANY, READ_MANY };
11 int fd, ready, gate, operation;
12 const unsigned char* value;
17static unsigned char short_value[191], long_value[257];
19static void* compete(
void* opaque) {
23 if (xa_send(item->ready,
'r') || xa_receive(item->gate,
'g'))
25 if (item->operation == REMOVE) {
26 item->result = fremovexattr(item->fd,
"user.race");
28 }
else if (item->operation == CREATE || item->operation == REPLACE) {
29 item->result = fsetxattr(item->fd,
"user.race", item->value, item->length,
30 item->operation == CREATE ? XATTR_CREATE : XATTR_REPLACE);
35 for (
int n = 0; n < 64; ++n) {
36 if (item->operation == WRITE_MANY) {
37 const void* value = (n & 1) ? (
const void*)short_value : long_value;
38 size_t length = (n & 1) ?
sizeof(short_value) :
sizeof(long_value);
39 if (fsetxattr(item->fd,
"user.race", value, length, XATTR_REPLACE)) {
45 unsigned char buffer[
sizeof(long_value) + 1];
46 memset(buffer, 0xa5,
sizeof(buffer));
47 ssize_t length = fgetxattr(item->fd,
"user.race", buffer,
sizeof(buffer));
48 int valid = (length ==
sizeof(short_value) && !memcmp(buffer, short_value, length)) ||
49 (length ==
sizeof(long_value) && !memcmp(buffer, long_value, length));
50 if (!valid || buffer[length] != 0xa5) {
52 item->error = length < 0 ? errno : EIO;
62 int failed = 0, ready[2] = {-1, -1}, gate[2] = {-1, -1}, created = 0;
64 struct contender* items[] = {first, second};
65 CHECK(!pipe(ready) && !pipe(gate));
66 for (
int n = 0; n < 2; ++n) {
67 items[n]->ready = ready[1];
68 items[n]->gate = gate[0];
69 CHECK(!pthread_create(&threads[n], NULL, compete, items[n]));
72 CHECK(!xa_receive(ready[0],
'r') && !xa_receive(ready[0],
'r'));
73 CHECK(!xa_send(gate[1],
'g') && !xa_send(gate[1],
'g'));
79 for (
int n = 0; n < created; ++n) {
80 int result = pthread_join(threads[n], NULL);
82 fprintf(stderr,
"XATTR-CONTRACT: contender join=%d\n", result);
86 for (
int n = 0; n < 2; ++n) {
95static int atomic_updates(
int backend) {
96 int failed = 0, alias = -1;
97 struct xa_file file = {.fd = -1};
98 CHECK(!xa_create(&file, backend, 0));
99 CHECK((alias = xa_open_alias(&file)) >= 0);
100 for (
int round = 0; round < 4; ++round) {
102 .fd = file.fd, .operation = CREATE, .value = short_value, .length =
sizeof(short_value)};
104 .fd = alias, .operation = CREATE, .value = long_value, .length =
sizeof(long_value)};
105 CHECK(!pair(&first, &second));
106 CHECK((!first.result && second.result == -1 && second.error == EEXIST) ||
107 (!second.result && first.result == -1 && first.error == EEXIST));
108 struct contender* winner = !first.result ? &first : &second;
109 CHECK(!xa_value(&file, XA_FD,
"user.race", winner->value, winner->length));
110 first.operation = REPLACE;
111 second.operation = REPLACE;
112 CHECK(!pair(&first, &second));
113 CHECK(!first.result && !second.result);
114 unsigned char buffer[
sizeof(long_value)];
115 ssize_t length = fgetxattr(alias,
"user.race", buffer,
sizeof(buffer));
116 CHECK((length ==
sizeof(short_value) && !memcmp(buffer, short_value, length)) ||
117 (length ==
sizeof(long_value) && !memcmp(buffer, long_value, length)));
118 second.operation = REMOVE;
119 CHECK(!pair(&first, &second));
120 CHECK(!second.result);
121 CHECK(!first.result || (first.result == -1 && first.error == ENODATA));
122 CHECK(fgetxattr(file.fd,
"user.race", NULL, 0) == -1 && errno == ENODATA);
124 CHECK(!fsetxattr(file.fd,
"user.race", short_value,
sizeof(short_value), XATTR_CREATE));
125 struct contender writer = {.fd = file.fd, .operation = WRITE_MANY};
127 CHECK(!pair(&writer, &
reader));
128 if (writer.result ||
reader.result)
129 fprintf(stderr,
"XATTR-CONTRACT: snapshots backend=%d writer=%d/%d reader=%d/%d\n", backend,
130 writer.result, writer.error,
reader.result,
reader.error);
131 CHECK(!writer.result && !
reader.result);
139int xa_concurrency(
void) {
140 for (
size_t n = 0; n <
sizeof(short_value); ++n)
141 short_value[n] = (
unsigned char)(n * 17 + 3);
142 for (
size_t n = 0; n <
sizeof(long_value); ++n)
143 long_value[n] = (
unsigned char)(n * 31 + 11);
144 for (
int backend = XA_MEMFD; backend <= XA_EXT2; ++backend)
145 if (atomic_updates(backend))