| 1 | #include <errno.h> |
| 2 | #include <string.h> |
| 3 | #include <stdio.h> |
| 4 | #include <sys/stat.h> |
| 5 | #include <sys/types.h> |
| 6 | #include <sys/mman.h> |
| 7 | #include <sys/types.h> |
| 8 | |
| 9 | #define _GNU_SOURCE /* See feature_test_macros(7) */ |
| 10 | #define __USE_GNU |
| 11 | #include <fcntl.h> |
| 12 | #include <unistd.h> |
| 13 | |
| 14 | void test_sync_file_range(char *output, char *text, size_t length) |
| 15 | { |
| 16 | int fd = open (output, O_WRONLY | O_CREAT | O_APPEND, 0660); |
| 17 | if (fd < 0 ) { |
| 18 | perror("Cannot get page size"); |
| 19 | return; |
| 20 | } |
| 21 | |
| 22 | int i; |
| 23 | size_t offset = 0; |
| 24 | for ( i = 0 ; i < 10000; i++ ) { |
| 25 | write(fd, text, length); |
| 26 | sync_file_range(fd, offset, length, SYNC_FILE_RANGE_WRITE); |
| 27 | offset += length; |
| 28 | } |
| 29 | |
| 30 | close(fd); |
| 31 | sleep(5); |
| 32 | } |
| 33 | |
| 34 | // test based on IBM example https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/apis/msync.htm |
| 35 | void test_msync(char *output, char *text, size_t length) |
| 36 | { |
| 37 | int pagesize = sysconf(_SC_PAGE_SIZE); |
| 38 | if (pagesize < 0) { |
| 39 | perror("Cannot get page size"); |
| 40 | return; |
| 41 | } |
| 42 | |
| 43 | int fd = open(output, (O_CREAT | O_TRUNC | O_RDWR), (S_IRWXU | S_IRWXG | S_IRWXO)); |
| 44 | if (fd < 0 ) { |
| 45 | perror("Cannot open file"); |
| 46 | return; |
| 47 | } |
| 48 | |
| 49 | off_t lastoffset = lseek( fd, pagesize, SEEK_SET); |
| 50 | ssize_t written = write(fd, " ", 1); |
| 51 | if ( written != 1 ) { |
| 52 | perror("Write error. "); |
| 53 | close(fd); |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | off_t my_offset = 0; |
| 58 | void *address = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, fd, my_offset); |
| 59 | |
| 60 | if ( address == MAP_FAILED ) { |
| 61 | perror("Map error. "); |
| 62 | close(fd); |
| 63 | return; |
| 64 | } |
| 65 | |
| 66 | (void) strcpy( (char*) address, text); |
| 67 | |
| 68 | if ( msync( address, pagesize, MS_SYNC) < 0 ) { |
| 69 | perror("msync failed with error:"); |
| 70 | } |
| 71 | |
| 72 | close(fd); |
| 73 | sleep(5); |
| 74 | } |
| 75 | |
| 76 | void test_synchronization(char *output, char *text, size_t length, int (*fcnt)(int)) |
| 77 | { |
| 78 | int fd = open (output, O_WRONLY | O_CREAT | O_APPEND, 0660); |
| 79 | if (fd < 0 ) { |
| 80 | perror("Cannot get page size"); |
| 81 | return; |
| 82 | } |
| 83 | |
| 84 | int i; |
| 85 | for ( i = 0 ; i < 10000; i++ ) |
| 86 | write(fd, text, length); |
| 87 | |
| 88 | fcnt(fd); |
| 89 | close(fd); |
| 90 | |
| 91 | sleep(5); |
| 92 | } |
| 93 | |
| 94 | void remove_files(char **files) { |
| 95 | size_t i = 0; |
| 96 | while (files[i]) { |
| 97 | unlink(files[i]); |
| 98 | i++; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | int main() |
| 103 | { |
| 104 | char *default_text = { "This is a simple example to test a PR. The sleep is used to create different peaks on charts.\n" }; |
| 105 | char *files[] = { "fsync.txt", "fdatasync.txt", "syncfs.txt", "msync.txt", "sync_file_range.txt", NULL }; |
| 106 | size_t length = strlen(default_text); |
| 107 | test_synchronization(files[0], default_text, length, fsync); |
| 108 | test_synchronization(files[1], default_text, length, fdatasync); |
| 109 | test_synchronization(files[2], default_text, length, syncfs); |
| 110 | |
| 111 | test_msync(files[3], default_text, length); |
| 112 | |
| 113 | test_sync_file_range(files[4], default_text, length); |
| 114 | |
| 115 | sync(); |
| 116 | |
| 117 | remove_files(files); |
| 118 | |
| 119 | return 0; |
| 120 | } |