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 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/wait.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <time.h>
33 #include "noatime.h"
34 #include "posixtest.h"
35 
main(void)36 int main(void)
37 {
38 	char tmpfname[256];
39 	ssize_t size = 1024;
40 	char data[size];
41 	void *pa;
42 	int fd;
43 
44 	struct stat stat_buff, stat_buff2;
45 	time_t atime1, atime2, atime3;
46 
47 	char *ch;
48 
49 	if (mounted_noatime("/tmp") == 1) {
50 		printf("UNTESTED: The /tmp is mounted noatime\n");
51 		return PTS_UNTESTED;
52 	}
53 
54 	snprintf(tmpfname, sizeof(tmpfname), "/tmp/pts_mmap_13_1_%d", getpid());
55 	unlink(tmpfname);
56 	fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
57 	if (fd == -1) {
58 		printf("Error at open(): %s\n", strerror(errno));
59 		return PTS_UNRESOLVED;
60 	}
61 
62 	memset(data, 'a', size);
63 	printf("Time before write(): %ld\n", time(NULL));
64 	if (write(fd, data, size) != size) {
65 		printf("Error at write(): %s\n", strerror(errno));
66 		unlink(tmpfname);
67 		return PTS_UNRESOLVED;
68 	}
69 
70 	if (stat(tmpfname, &stat_buff) == -1) {
71 		printf("Error at 1st stat(): %s\n", strerror(errno));
72 		unlink(tmpfname);
73 		return PTS_UNRESOLVED;
74 	}
75 	/* atime1: write */
76 	atime1 = stat_buff.st_atime;
77 
78 	sleep(1);
79 
80 	printf("Time before mmap(): %ld\n", time(NULL));
81 	pa = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
82 	if (pa == MAP_FAILED) {
83 		printf("Error at mmap: %s\n", strerror(errno));
84 		unlink(tmpfname);
85 		return PTS_FAIL;
86 	}
87 
88 	if (stat(tmpfname, &stat_buff2) == -1) {
89 		printf("Error at 2nd stat(): %s\n", strerror(errno));
90 		unlink(tmpfname);
91 		return PTS_UNRESOLVED;
92 	}
93 	/* for mmap */
94 	atime2 = stat_buff2.st_atime;
95 
96 	/* Wait a while in case the precision of the sa_time
97 	 * is not acurate enough to reflect the change
98 	 */
99 	sleep(1);
100 
101 	/* write reference to mapped memory */
102 	ch = pa;
103 	*ch = 'b';
104 
105 	printf("Time before munmap(): %ld\n", time(NULL));
106 	munmap(pa, size);
107 
108 	/* FIXME: Update the in-core meta data to the disk */
109 	fsync(fd);
110 	close(fd);
111 	if (stat(tmpfname, &stat_buff) == -1) {
112 		printf("Error at 3rd stat(): %s\n", strerror(errno));
113 		unlink(tmpfname);
114 		return PTS_UNRESOLVED;
115 	}
116 	/* atime3: write to memory */
117 	atime3 = stat_buff.st_atime;
118 
119 	printf("atime1: %d, atime2: %d, atime3: %d\n",
120 	       (int)atime1, (int)atime2, (int)atime3);
121 	if (atime1 != atime3 || atime1 != atime2) {
122 		printf("Test PASSED\n");
123 		unlink(tmpfname);
124 		return PTS_PASS;
125 	}
126 
127 	printf("Test FAILED: st_atime was not updated properly\n");
128 	unlink(tmpfname);
129 	return PTS_FAIL;
130 }
131