*/
/*
* Fork a child that concurrently modifies address space while the main
- * process is reading /proc/$PID/maps and verifying the results. Address
- * space modifications include:
+ * process is reading /proc/$PID/maps and /proc/$PID/smaps, verifying the
+ * results. Address space modifications include:
* VMA splitting and merging
*
*/
TEST_DONE,
};
+enum maps_file {
+ MAPS,
+ SMAPS,
+};
+
struct vma_modifier_info;
FIXTURE(proc_maps_race)
struct line_content last_line;
struct line_content first_line;
unsigned long duration_sec;
+ enum maps_file maps_file;
int shared_mem_size;
int skip_pages;
int page_size;
pid_t pid;
};
+FIXTURE_VARIANT(proc_maps_race)
+{
+ const enum maps_file maps_file;
+};
+
+FIXTURE_VARIANT_ADD(proc_maps_race, maps) {
+ .maps_file = MAPS,
+};
+
+FIXTURE_VARIANT_ADD(proc_maps_race, smaps) {
+ .maps_file = SMAPS,
+};
+
typedef bool (*vma_modifier_op)(FIXTURE_DATA(proc_maps_race) *self);
typedef bool (*vma_mod_result_check_op)(struct line_content *mod_last_line,
struct line_content *mod_first_line,
copy_line(pos, end, last_line, line_size);
}
+static bool copy_first_entry(struct page_content *page, char *first_line,
+ size_t line_size)
+{
+ char *start_pos = page->data;
+
+ while (start_pos < page->data + page->size) {
+ unsigned long start_addr;
+ unsigned long end_addr;
+ char *end_pos;
+
+ end_pos = strchr(start_pos, '\n');
+ if (!end_pos)
+ break;
+
+ if (parse_vma_line(start_pos, end_pos, &start_addr, &end_addr)) {
+ copy_line(start_pos, end_pos, first_line, line_size);
+ return true;
+ }
+
+ start_pos = end_pos + 1;
+ }
+
+ return false;
+}
+
+static bool copy_last_entry(struct page_content *page, char *last_line,
+ size_t line_size)
+{
+ char *end_pos = page->data + page->size - 1;
+ char *start_pos;
+
+ while (end_pos > page->data) {
+ unsigned long start_addr;
+ unsigned long end_addr;
+
+ /* skip last newline */
+ start_pos = end_pos - 1;
+ /* search previous newline */
+ while (start_pos > page->data && start_pos[-1] != '\n')
+ start_pos--;
+ if (parse_vma_line(start_pos, end_pos, &start_addr, &end_addr)) {
+ copy_line(start_pos, end_pos, last_line, line_size);
+ return true;
+ }
+
+ end_pos = start_pos - 1;
+ }
+
+ return false;
+}
+
/* Read the last line of the first page and the first line of the second page */
static bool read_boundary_lines(FIXTURE_DATA(proc_maps_race) *self,
struct line_content *last_line,
if (!read_two_pages(self))
return false;
- copy_last_line(&self->page1, last_line->text, LINE_MAX_SIZE);
- copy_first_line(&self->page2, first_line->text, LINE_MAX_SIZE);
+ if (self->maps_file == MAPS) {
+ copy_last_line(&self->page1, last_line->text, LINE_MAX_SIZE);
+ copy_first_line(&self->page2, first_line->text, LINE_MAX_SIZE);
+ } else if (self->maps_file == SMAPS) {
+ if (!copy_last_entry(&self->page1, last_line->text, LINE_MAX_SIZE) ||
+ !copy_first_entry(&self->page2, first_line->text, LINE_MAX_SIZE))
+ return false;
+ } else {
+ return false;
+ }
return sscanf(last_line->text, "%lx-%lx", &last_line->start_addr,
&last_line->end_addr) == 2 &&
self->page_size = (unsigned long)sysconf(_SC_PAGESIZE);
self->verbose = verbose && !strncmp(verbose, "1", 1);
+ self->maps_file = variant->maps_file;
duration_sec = duration ? atol(duration) : 0;
self->duration_sec = duration_sec ? duration_sec : 5UL;
exit(0);
}
- sprintf(fname, "/proc/%d/maps", self->pid);
+ switch (self->maps_file) {
+ case MAPS:
+ sprintf(fname, "/proc/%d/maps", self->pid);
+ break;
+ case SMAPS:
+ sprintf(fname, "/proc/%d/smaps", self->pid);
+ break;
+ default:
+ ksft_exit_fail();
+ }
self->maps_fd = open(fname, O_RDONLY);
ASSERT_NE(self->maps_fd, -1);
ASSERT_TRUE(mod_info->addr && mod_info->next_addr);
signal_state(mod_info, PARENT_READY);
-
}
FIXTURE_TEARDOWN(proc_maps_race)
last_line_changed = strcmp(new_last_line.text, self->last_line.text) != 0;
first_line_changed = strcmp(new_first_line.text, self->first_line.text) != 0;
ASSERT_EQ(last_line_changed, first_line_changed);
-
- /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
- ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size,
- &vma_start, &vma_end));
- /*
- * The vma at the split address can be either the same as
- * original one (if read before the split) or the same as the
- * first line in the second page (if read after the split).
- */
- ASSERT_TRUE((vma_start == self->last_line.start_addr &&
- vma_end == self->last_line.end_addr) ||
- (vma_start == split_first_line.start_addr &&
- vma_end == split_first_line.end_addr));
-
+ if (self->maps_file == MAPS) {
+ /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
+ ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size,
+ &vma_start, &vma_end));
+ /*
+ * The vma at the split address can be either the same as
+ * original one (if read before the split) or the same as the
+ * first line in the second page (if read after the split).
+ */
+ ASSERT_TRUE((vma_start == self->last_line.start_addr &&
+ vma_end == self->last_line.end_addr) ||
+ (vma_start == split_first_line.start_addr &&
+ vma_end == split_first_line.end_addr));
+ }
clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
end_test_iteration(&end_ts, self->verbose);
} while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
strcmp(new_first_line.text, restored_first_line.text),
"Expand result invalid", self));
}
-
- /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
- ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr, &vma_start, &vma_end));
- /*
- * The vma should stay at the same address and have either the
- * original size of 3 pages or 1 page if read after shrinking.
- */
- ASSERT_TRUE(vma_start == self->last_line.start_addr &&
- (vma_end - vma_start == self->page_size * 3 ||
- vma_end - vma_start == self->page_size));
-
+ if (self->maps_file == MAPS) {
+ /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
+ ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr,
+ &vma_start, &vma_end));
+ /*
+ * The vma should stay at the same address and have either the
+ * original size of 3 pages or 1 page if read after shrinking.
+ */
+ ASSERT_TRUE(vma_start == self->last_line.start_addr &&
+ (vma_end - vma_start == self->page_size * 3 ||
+ vma_end - vma_start == self->page_size));
+ }
clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
end_test_iteration(&end_ts, self->verbose);
} while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
strcmp(new_first_line.text, restored_first_line.text),
"Remap restore result invalid", self));
}
-
- /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
- ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size,
- &vma_start, &vma_end));
- /*
- * The vma should either stay at the same address and have the
- * original size of 3 pages or we should find the remapped vma
- * at the remap destination address with size of 1 page.
- */
- ASSERT_TRUE((vma_start == self->last_line.start_addr &&
- vma_end - vma_start == self->page_size * 3) ||
- (vma_start == self->last_line.start_addr + self->page_size &&
- vma_end - vma_start == self->page_size));
-
+ if (self->maps_file == MAPS) {
+ /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
+ ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size,
+ &vma_start, &vma_end));
+ /*
+ * The vma should either stay at the same address and have the
+ * original size of 3 pages or we should find the remapped vma
+ * at the remap destination address with size of 1 page.
+ */
+ ASSERT_TRUE((vma_start == self->last_line.start_addr &&
+ vma_end - vma_start == self->page_size * 3) ||
+ (vma_start == self->last_line.start_addr + self->page_size &&
+ vma_end - vma_start == self->page_size));
+ }
clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
end_test_iteration(&end_ts, self->verbose);
} while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);