/* * fsync() is implemented via noop_fsync() on tmpfs. This makes the fsync() * test fail below, so we need to check for test file living on a tmpfs.
*/ staticbool is_on_tmpfs(int fd)
{ struct statfs statfs_buf;
if (fstatfs(fd, &statfs_buf)) returnfalse;
return statfs_buf.f_type == TMPFS_MAGIC;
}
/* * Open/create the file at filename, (optionally) write random data to it * (exactly num_pages), then test the cachestat syscall on this file. * * If test_fsync == true, fsync the file, then check the number of dirty * pages.
*/ staticint test_cachestat(constchar *filename, bool write_random, bool create, bool test_fsync, unsignedlong num_pages, int open_flags, mode_t open_mode)
{
size_t PS = sysconf(_SC_PAGESIZE); int filesize = num_pages * PS; int ret = KSFT_PASS; long syscall_ret; struct cachestat cs; struct cachestat_range cs_range = { 0, filesize };
int fd = open(filename, open_flags, open_mode);
if (fd == -1) {
ksft_print_msg("Unable to create/open file.\n");
ret = KSFT_FAIL; goto out;
} else {
ksft_print_msg("Create/open %s\n", filename);
}
if (write_random) { if (!write_exactly(fd, filesize)) {
ksft_print_msg("Unable to access urandom.\n");
ret = KSFT_FAIL; goto out1;
}
}
ksft_print_msg("Cachestat call returned %ld\n", syscall_ret);
if (syscall_ret) {
ksft_print_msg("Cachestat returned non-zero.\n");
ret = KSFT_FAIL; goto out1;
} else {
print_cachestat(&cs);
if (write_random) { if (cs.nr_cache + cs.nr_evicted != num_pages) {
ksft_print_msg( "Total number of cached and evicted pages is off.\n");
ret = KSFT_FAIL;
}
}
}
if (test_fsync) { if (is_on_tmpfs(fd)) {
ret = KSFT_SKIP;
} elseif (fsync(fd)) {
ksft_print_msg("fsync fails.\n");
ret = KSFT_FAIL;
} else {
syscall_ret = syscall(__NR_cachestat, fd, &cs_range, &cs, 0);
ksft_print_msg("Cachestat call (after fsync) returned %ld\n",
syscall_ret);
if (!syscall_ret) {
print_cachestat(&cs);
if (cs.nr_dirty) {
ret = KSFT_FAIL;
ksft_print_msg( "Number of dirty should be zero after fsync.\n");
}
} else {
ksft_print_msg("Cachestat (after fsync) returned non-zero.\n");
ret = KSFT_FAIL; goto out1;
}
}
}
out1:
close(fd);
if (create)
remove(filename);
out: return ret;
} constchar *file_type_str(enum file_type type)
{ switch (type) { case FILE_SHMEM: return"shmem"; case FILE_MMAP: return"mmap"; default: return"unknown";
}
}
if (fd < 0) {
ksft_print_msg("Unable to create %s file.\n",
file_type_str(type));
ret = false; goto out;
}
if (ftruncate(fd, filesize)) {
ksft_print_msg("Unable to truncate %s file.\n",file_type_str(type));
ret = false; goto close_fd;
} switch (type) { case FILE_SHMEM: if (!write_exactly(fd, filesize)) {
ksft_print_msg("Unable to write to file.\n");
ret = false; goto close_fd;
} break; case FILE_MMAP: char *map = mmap(NULL, filesize, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
ksft_print_msg("mmap failed.\n");
ret = false; goto close_fd;
} for (int i = 0; i < filesize; i++)
map[i] = 'A'; break; default:
ksft_print_msg("Unsupported file type.\n");
ret = false; goto close_fd;
}
syscall_ret = syscall(__NR_cachestat, fd, &cs_range, &cs, 0);
if (syscall_ret) {
ksft_print_msg("Cachestat returned non-zero.\n");
ret = false; goto close_fd;
} else {
print_cachestat(&cs); if (cs.nr_cache + cs.nr_evicted != num_pages) {
ksft_print_msg( "Total number of cached and evicted pages is off.\n");
ret = false;
}
}
ret = syscall(__NR_cachestat, -1, NULL, NULL, 0); if (ret == -1 && errno == ENOSYS)
ksft_exit_skip("cachestat syscall not available\n");
ksft_set_plan(NR_TESTS);
if (ret == -1 && errno == EBADF) {
ksft_test_result_pass("bad file descriptor recognized\n");
ret = 0;
} else {
ksft_test_result_fail("bad file descriptor ignored\n");
ret = 1;
}
for (int i = 0; i < 5; i++) { constchar *dev_filename = dev_files[i];
if (test_cachestat(dev_filename, false, false, false,
4, O_RDONLY, 0400) == KSFT_PASS)
ksft_test_result_pass("cachestat works with %s\n", dev_filename); else {
ksft_test_result_fail("cachestat fails with %s\n", dev_filename);
ret = 1;
}
}
if (test_cachestat("tmpfilecachestat", true, true, false, 4, O_CREAT | O_RDWR, 0600) == KSFT_PASS)
ksft_test_result_pass("cachestat works with a normal file\n"); else {
ksft_test_result_fail("cachestat fails with normal file\n");
ret = 1;
}
switch (test_cachestat("tmpfilecachestat", true, true, true, 4, O_CREAT | O_RDWR, 0600)) { case KSFT_FAIL:
ksft_test_result_fail("cachestat fsync fails with normal file\n");
ret = KSFT_FAIL; break; case KSFT_PASS:
ksft_test_result_pass("cachestat fsync works with a normal file\n"); break; case KSFT_SKIP:
ksft_test_result_skip("tmpfilecachestat is on tmpfs\n"); break;
}
if (run_cachestat_test(FILE_SHMEM))
ksft_test_result_pass("cachestat works with a shmem file\n"); else {
ksft_test_result_fail("cachestat fails with a shmem file\n");
ret = 1;
}
if (run_cachestat_test(FILE_MMAP))
ksft_test_result_pass("cachestat works with a mmap file\n"); else {
ksft_test_result_fail("cachestat fails with a mmap file\n");
ret = 1;
} return ret;
}
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.