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
37int 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