1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2017 Red Hat, Inc. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/* 8f08c3bdfSopenharmony_ci * Test description: Verify msync() after writing into mmap()-ed file works. 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Write to mapped region and sync the memory back with file. Check the page 11f08c3bdfSopenharmony_ci * is no longer dirty after msync() call. 12f08c3bdfSopenharmony_ci */ 13f08c3bdfSopenharmony_ci 14f08c3bdfSopenharmony_ci#include <errno.h> 15f08c3bdfSopenharmony_ci#include "tst_test.h" 16f08c3bdfSopenharmony_ci 17f08c3bdfSopenharmony_cistatic int test_fd; 18f08c3bdfSopenharmony_cistatic char *mmaped_area; 19f08c3bdfSopenharmony_cistatic long pagesize; 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_ci#define STRING_TO_WRITE "AAAAAAAAAA" 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ciuint64_t get_dirty_bit(void *data) 24f08c3bdfSopenharmony_ci{ 25f08c3bdfSopenharmony_ci int pagemap_fd, pageflags_fd; 26f08c3bdfSopenharmony_ci unsigned long addr; 27f08c3bdfSopenharmony_ci uint64_t pagemap_entry, pageflag_entry, pfn, index; 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_ci addr = (unsigned long)data; 30f08c3bdfSopenharmony_ci index = (addr / pagesize) * sizeof(uint64_t); 31f08c3bdfSopenharmony_ci pagemap_fd = SAFE_OPEN("/proc/self/pagemap", O_RDONLY); 32f08c3bdfSopenharmony_ci SAFE_LSEEK(pagemap_fd, index, SEEK_SET); 33f08c3bdfSopenharmony_ci SAFE_READ(1, pagemap_fd, &pagemap_entry, sizeof(pagemap_entry)); 34f08c3bdfSopenharmony_ci SAFE_CLOSE(pagemap_fd); 35f08c3bdfSopenharmony_ci pfn = pagemap_entry & ((1ULL << 55) - 1); 36f08c3bdfSopenharmony_ci if (!pfn) 37f08c3bdfSopenharmony_ci return 0; 38f08c3bdfSopenharmony_ci pageflags_fd = SAFE_OPEN("/proc/kpageflags", O_RDONLY); 39f08c3bdfSopenharmony_ci index = pfn * sizeof(uint64_t); 40f08c3bdfSopenharmony_ci SAFE_LSEEK(pageflags_fd, index, SEEK_SET); 41f08c3bdfSopenharmony_ci SAFE_READ(1, pageflags_fd, &pageflag_entry, sizeof(pageflag_entry)); 42f08c3bdfSopenharmony_ci SAFE_CLOSE(pageflags_fd); 43f08c3bdfSopenharmony_ci return pageflag_entry & (1ULL << 4); 44f08c3bdfSopenharmony_ci} 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic void test_msync(void) 47f08c3bdfSopenharmony_ci{ 48f08c3bdfSopenharmony_ci uint64_t dirty; 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_ci test_fd = SAFE_OPEN("msync04/testfile", O_CREAT | O_TRUNC | O_RDWR, 51f08c3bdfSopenharmony_ci 0644); 52f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ANY, test_fd, STRING_TO_WRITE, sizeof(STRING_TO_WRITE) - 1); 53f08c3bdfSopenharmony_ci mmaped_area = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE, 54f08c3bdfSopenharmony_ci MAP_SHARED, test_fd, 0); 55f08c3bdfSopenharmony_ci SAFE_CLOSE(test_fd); 56f08c3bdfSopenharmony_ci mmaped_area[8] = 'B'; 57f08c3bdfSopenharmony_ci dirty = get_dirty_bit(mmaped_area); 58f08c3bdfSopenharmony_ci if (!dirty) { 59f08c3bdfSopenharmony_ci tst_res(TFAIL, "Expected dirty bit to be set after writing to" 60f08c3bdfSopenharmony_ci " mmap()-ed area"); 61f08c3bdfSopenharmony_ci goto clean; 62f08c3bdfSopenharmony_ci } 63f08c3bdfSopenharmony_ci if (msync(mmaped_area, pagesize, MS_SYNC) < 0) { 64f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "msync() failed"); 65f08c3bdfSopenharmony_ci goto clean; 66f08c3bdfSopenharmony_ci } 67f08c3bdfSopenharmony_ci dirty = get_dirty_bit(mmaped_area); 68f08c3bdfSopenharmony_ci if (dirty) 69f08c3bdfSopenharmony_ci tst_res(TFAIL, "msync() failed to write dirty page despite" 70f08c3bdfSopenharmony_ci " succeeding"); 71f08c3bdfSopenharmony_ci else 72f08c3bdfSopenharmony_ci tst_res(TPASS, "msync() working correctly"); 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ciclean: 75f08c3bdfSopenharmony_ci SAFE_MUNMAP(mmaped_area, pagesize); 76f08c3bdfSopenharmony_ci mmaped_area = NULL; 77f08c3bdfSopenharmony_ci} 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_cistatic void setup(void) 80f08c3bdfSopenharmony_ci{ 81f08c3bdfSopenharmony_ci pagesize = (off_t)SAFE_SYSCONF(_SC_PAGESIZE); 82f08c3bdfSopenharmony_ci} 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_cistatic void cleanup(void) 85f08c3bdfSopenharmony_ci{ 86f08c3bdfSopenharmony_ci if (mmaped_area) 87f08c3bdfSopenharmony_ci SAFE_MUNMAP(mmaped_area, pagesize); 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_ci if (test_fd > 0) 90f08c3bdfSopenharmony_ci SAFE_CLOSE(test_fd); 91f08c3bdfSopenharmony_ci} 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistatic struct tst_test test = { 94f08c3bdfSopenharmony_ci .test_all = test_msync, 95f08c3bdfSopenharmony_ci .setup = setup, 96f08c3bdfSopenharmony_ci .cleanup = cleanup, 97f08c3bdfSopenharmony_ci .needs_root = 1, 98f08c3bdfSopenharmony_ci .mntpoint = "msync04", 99f08c3bdfSopenharmony_ci .mount_device = 1, 100f08c3bdfSopenharmony_ci .all_filesystems = 1, 101f08c3bdfSopenharmony_ci .skip_filesystems = (const char *[]) { 102f08c3bdfSopenharmony_ci "tmpfs", 103f08c3bdfSopenharmony_ci NULL 104f08c3bdfSopenharmony_ci }, 105f08c3bdfSopenharmony_ci}; 106