1 /*
2  * Copyright (c) 2002, Intel Corporation. All rights reserved.
3  * Copyright (c) 2012, Cyril Hrubis <chrubis@suse.cz>
4  *
5  * This file is licensed under the GPL license.  For the full content
6  * of this license, see the COPYING file at the top level of this
7  * source tree.
8  *
9  * The st_atime field of the mapped file may be marked for update
10  * at any time between the mmap() call and the corresponding munmap()
11  * call. The initial read or write reference to a mapped region
12  * shall cause the file st_atime field to be marked for update if
13  * it has not already been marked for update.
14  *
15  * Test Steps:
16  * 1. Do stat before mmap() and after munmap(),
17  *    also after writing the mapped region.
18  * 2. Compare whether st_atime has been updated.
19  */
20 
21 #define _XOPEN_SOURCE 600
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/mman.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <time.h>
34 #include "noatime.h"
35 #include "posixtest.h"
36 
main(void)37 int main(void)
38 {
39 	char tmpfname[256];
40 	ssize_t size = 1024;
41 	char data[size];
42 	void *pa;
43 	int fd;
44 
45 	struct stat stat_buff, stat_buff2;
46 	time_t atime1, atime2, atime3;
47 
48 	char *ch;
49 
50 	if (mounted_noatime("/tmp") == 1) {
51 		printf("UNTESTED: The /tmp is mounted noatime\n");
52 		return PTS_UNTESTED;
53 	}
54 
55 	snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_mmap_13_1_%d", getpid());
56 	unlink(tmpfname);
57 	fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
58 	if (fd == -1) {
59 		printf("Error at open(): %s\n", strerror(errno));
60 		return PTS_UNRESOLVED;
61 	}
62 
63 	memset(data, 'a', size);
64 	printf("Time before write(): %ld\n", time(NULL));
65 	if (write(fd, data, size) != size) {
66 		printf("Error at write(): %s\n", strerror(errno));
67 		unlink(tmpfname);
68 		return PTS_UNRESOLVED;
69 	}
70 
71 	if (stat(tmpfname, &stat_buff) == -1) {
72 		printf("Error at 1st stat(): %s\n", strerror(errno));
73 		unlink(tmpfname);
74 		return PTS_UNRESOLVED;
75 	}
76 	/* atime1: write */
77 	atime1 = stat_buff.st_atime;
78 
79 	sleep(1);
80 
81 	printf("Time before mmap(): %ld\n", time(NULL));
82 	pa = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
83 	if (pa == MAP_FAILED) {
84 		printf("Error at mmap: %s\n", strerror(errno));
85 		unlink(tmpfname);
86 		return PTS_FAIL;
87 	}
88 
89 	if (stat(tmpfname, &stat_buff2) == -1) {
90 		printf("Error at 2nd stat(): %s\n", strerror(errno));
91 		unlink(tmpfname);
92 		return PTS_UNRESOLVED;
93 	}
94 	/* for mmap */
95 	atime2 = stat_buff2.st_atime;
96 
97 	/* Wait a while in case the precision of the sa_time
98 	 * is not acurate enough to reflect the change
99 	 */
100 	sleep(1);
101 
102 	/* write reference to mapped memory */
103 	ch = pa;
104 	*ch = 'b';
105 
106 	printf("Time before munmap(): %ld\n", time(NULL));
107 	munmap(pa, size);
108 
109 	/* FIXME: Update the in-core meta data to the disk */
110 	fsync(fd);
111 	close(fd);
112 	if (stat(tmpfname, &stat_buff) == -1) {
113 		printf("Error at 3rd stat(): %s\n", strerror(errno));
114 		unlink(tmpfname);
115 		return PTS_UNRESOLVED;
116 	}
117 	/* atime3: write to memory */
118 	atime3 = stat_buff.st_atime;
119 
120 	printf("atime1: %d, atime2: %d, atime3: %d\n",
121 	       (int)atime1, (int)atime2, (int)atime3);
122 	if (atime1 != atime3 || atime1 != atime2) {
123 		printf("Test PASSED\n");
124 		unlink(tmpfname);
125 		return PTS_PASS;
126 	}
127 
128 	printf("Test FAILED: st_atime was not updated properly\n");
129 	unlink(tmpfname);
130 	return PTS_FAIL;
131 }
132