1 /*-
2  * Copyright (c) 2014-2018 MongoDB, Inc.
3  * Copyright (c) 2008-2014 WiredTiger, Inc.
4  *	All rights reserved.
5  *
6  * See the file LICENSE for redistribution information.
7  */
8 
9 #include "wt_internal.h"
10 
11 /*
12  * __wt_posix_map --
13  *	Map a file into memory.
14  */
15 int
__wt_posix_map(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,void * mapped_regionp,size_t * lenp,void * mapped_cookiep)16 __wt_posix_map(WT_FILE_HANDLE *fh, WT_SESSION *wt_session,
17     void *mapped_regionp, size_t *lenp, void *mapped_cookiep)
18 {
19 	WT_FILE_HANDLE_POSIX *pfh;
20 	WT_SESSION_IMPL *session;
21 	wt_off_t file_size;
22 	size_t len;
23 	void *map;
24 
25 	WT_UNUSED(mapped_cookiep);
26 
27 	session = (WT_SESSION_IMPL *)wt_session;
28 	pfh = (WT_FILE_HANDLE_POSIX *)fh;
29 
30 	/*
31 	 * Mapping isn't possible if direct I/O configured for the file, the
32 	 * Linux open(2) documentation says applications should avoid mixing
33 	 * mmap(2) of files with direct I/O to the same files.
34 	 */
35 	if (pfh->direct_io)
36 		return (__wt_set_return(session, ENOTSUP));
37 
38 	/*
39 	 * There's no locking here to prevent the underlying file from changing
40 	 * underneath us, our caller needs to ensure consistency of the mapped
41 	 * region vs. any other file activity.
42 	 */
43 	WT_RET(fh->fh_size(fh, wt_session, &file_size));
44 	len = (size_t)file_size;
45 
46 	__wt_verbose(session, WT_VERB_HANDLEOPS,
47 	    "%s: memory-map: %" WT_SIZET_FMT " bytes", fh->name, len);
48 
49 	if ((map = mmap(NULL, len,
50 	    PROT_READ,
51 #ifdef MAP_NOCORE
52 	    MAP_NOCORE |
53 #endif
54 	    MAP_PRIVATE,
55 	    pfh->fd, (wt_off_t)0)) == MAP_FAILED)
56 		WT_RET_MSG(session,
57 		    __wt_errno(), "%s: memory-map: mmap", fh->name);
58 
59 	*(void **)mapped_regionp = map;
60 	*lenp = len;
61 	return (0);
62 }
63 
64 #ifdef HAVE_POSIX_MADVISE
65 /*
66  * __wt_posix_map_preload --
67  *	Cause a section of a memory map to be faulted in.
68  */
69 int
__wt_posix_map_preload(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,const void * map,size_t length,void * mapped_cookie)70 __wt_posix_map_preload(WT_FILE_HANDLE *fh,
71     WT_SESSION *wt_session, const void *map, size_t length, void *mapped_cookie)
72 {
73 	WT_BM *bm;
74 	WT_CONNECTION_IMPL *conn;
75 	WT_DECL_RET;
76 	WT_SESSION_IMPL *session;
77 	void *blk;
78 
79 	WT_UNUSED(mapped_cookie);
80 
81 	session = (WT_SESSION_IMPL *)wt_session;
82 
83 	conn = S2C(session);
84 	bm = S2BT(session)->bm;
85 
86 	/* Linux requires the address be aligned to a 4KB boundary. */
87 	blk = (void *)((uintptr_t)map & ~(uintptr_t)(conn->page_size - 1));
88 	length += WT_PTRDIFF(map, blk);
89 
90 	/* XXX proxy for "am I doing a scan?" -- manual read-ahead */
91 	if (F_ISSET(session, WT_SESSION_READ_WONT_NEED)) {
92 		/* Read in 2MB blocks every 1MB of data. */
93 		if (((uintptr_t)((uint8_t *)blk + length) &
94 		    (uintptr_t)((1<<20) - 1)) < (uintptr_t)blk)
95 			return (0);
96 		length = WT_MIN(WT_MAX(20 * length, 2 << 20),
97 		    WT_PTRDIFF((uint8_t *)bm->map + bm->maplen, blk));
98 	}
99 
100 	/*
101 	 * Manual pages aren't clear on whether alignment is required for the
102 	 * size, so we will be conservative.
103 	 */
104 	length &= ~(size_t)(conn->page_size - 1);
105 	if (length <= (size_t)conn->page_size)
106 		return (0);
107 
108 	WT_SYSCALL(posix_madvise(blk, length, POSIX_MADV_WILLNEED), ret);
109 	if (ret == 0)
110 		return (0);
111 
112 	WT_RET_MSG(session, ret,
113 	    "%s: memory-map preload: posix_madvise: POSIX_MADV_WILLNEED",
114 	    fh->name);
115 }
116 #endif
117 
118 #ifdef HAVE_POSIX_MADVISE
119 /*
120  * __wt_posix_map_discard --
121  *	Discard a chunk of the memory map.
122  */
123 int
__wt_posix_map_discard(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,void * map,size_t length,void * mapped_cookie)124 __wt_posix_map_discard(WT_FILE_HANDLE *fh,
125     WT_SESSION *wt_session, void *map, size_t length, void *mapped_cookie)
126 {
127 	WT_CONNECTION_IMPL *conn;
128 	WT_DECL_RET;
129 	WT_SESSION_IMPL *session;
130 	void *blk;
131 
132 	WT_UNUSED(mapped_cookie);
133 
134 	session = (WT_SESSION_IMPL *)wt_session;
135 	conn = S2C(session);
136 
137 	/* Linux requires the address be aligned to a 4KB boundary. */
138 	blk = (void *)((uintptr_t)map & ~(uintptr_t)(conn->page_size - 1));
139 	length += WT_PTRDIFF(map, blk);
140 
141 	WT_SYSCALL(posix_madvise(blk, length, POSIX_MADV_DONTNEED), ret);
142 	if (ret == 0)
143 		return (0);
144 
145 	WT_RET_MSG(session, ret,
146 	    "%s: memory-map discard: posix_madvise: POSIX_MADV_DONTNEED",
147 	    fh->name);
148 }
149 #endif
150 
151 /*
152  * __wt_posix_unmap --
153  *	Remove a memory mapping.
154  */
155 int
__wt_posix_unmap(WT_FILE_HANDLE * fh,WT_SESSION * wt_session,void * mapped_region,size_t len,void * mapped_cookie)156 __wt_posix_unmap(WT_FILE_HANDLE *fh, WT_SESSION *wt_session,
157     void *mapped_region, size_t len, void *mapped_cookie)
158 {
159 	WT_SESSION_IMPL *session;
160 
161 	WT_UNUSED(mapped_cookie);
162 
163 	session = (WT_SESSION_IMPL *)wt_session;
164 
165 	__wt_verbose(session, WT_VERB_HANDLEOPS,
166 	    "%s: memory-unmap: %" WT_SIZET_FMT " bytes", fh->name, len);
167 
168 	if (munmap(mapped_region, len) == 0)
169 		return (0);
170 
171 	WT_RET_MSG(session, __wt_errno(), "%s: memory-unmap: munmap", fh->name);
172 }
173