1 /*
2 * Copyright (c) 2015-2016 Mellanox Technologies, Inc.
3 * All rights reserved.
4 * Copyright (c) 2017 Research Organization for Information Science
5 * and Technology (RIST). All rights reserved.
6 * Copyright (c) 2017-2020 Intel, Inc. All rights reserved.
7 * $COPYRIGHT$
8 *
9 * Additional copyrights may follow
10 *
11 * $HEADER$
12 */
13
14
15 #include <unistd.h>
16 #ifdef HAVE_SYS_TYPES_H
17 #include <sys/types.h>
18 #endif
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <errno.h>
23
24 #include "src/include/pmix_config.h"
25 #include "include/pmix_common.h"
26 #include "src/include/pmix_globals.h"
27
28 //#include "pmix_sm.h"
29 #include "src/mca/pshmem/pshmem.h"
30 #include "pshmem_mmap.h"
31
32 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
33 # define MAP_ANONYMOUS MAP_ANON
34 #endif /* MAP_ANONYMOUS and MAP_ANON */
35
36 static int _mmap_segment_create(pmix_pshmem_seg_t *sm_seg, const char *file_name, size_t size);
37 static int _mmap_segment_attach(pmix_pshmem_seg_t *sm_seg, pmix_pshmem_access_mode_t sm_mode);
38 static int _mmap_segment_detach(pmix_pshmem_seg_t *sm_seg);
39 static int _mmap_segment_unlink(pmix_pshmem_seg_t *sm_seg);
40
41 pmix_pshmem_base_module_t pmix_mmap_module = {
42 .name = "mmap",
43 .segment_create = _mmap_segment_create,
44 .segment_attach = _mmap_segment_attach,
45 .segment_detach = _mmap_segment_detach,
46 .segment_unlink = _mmap_segment_unlink
47 };
48
_mmap_segment_create(pmix_pshmem_seg_t * sm_seg,const char * file_name,size_t size)49 static int _mmap_segment_create(pmix_pshmem_seg_t *sm_seg, const char *file_name, size_t size)
50 {
51 int rc = PMIX_SUCCESS;
52 void *seg_addr = MAP_FAILED;
53 pid_t my_pid = getpid();
54
55 _segment_ds_reset(sm_seg);
56 /* enough space is available, so create the segment */
57 if (-1 == (sm_seg->seg_id = open(file_name, O_CREAT | O_RDWR, 0600))) {
58 pmix_output_verbose(2, pmix_globals.debug_output,
59 "sys call open(2) fail\n");
60 rc = PMIX_ERROR;
61 goto out;
62 }
63 /* size backing file - note the use of real_size here */
64 #ifdef HAVE_POSIX_FALLOCATE
65 if (0 != (rc = posix_fallocate(sm_seg->seg_id, 0, size))) {
66 pmix_output_verbose(2, pmix_globals.debug_output,
67 "sys call posix_fallocate(2) fail\n");
68 if (EINVAL == rc) {
69 goto ftruncate;
70 }
71 if (ENOSPC == rc) {
72 rc = PMIX_ERR_OUT_OF_RESOURCE;
73 goto out;
74 } else if (EINVAL != rc && ENOTSUP != rc
75 #ifdef EOPNOTSUPP
76 && EOPNOTSUPP != rc
77 #endif
78 ){
79 rc = PMIX_ERROR;
80 goto out;
81 }
82 /* else:
83 * Not supported by OS and/or filesystem.
84 * Must fall-back to ftruncate().
85 */
86 } else {
87 goto map_memory;
88 }
89 #endif
90 ftruncate:
91 if (0 != ftruncate(sm_seg->seg_id, size)) {
92 pmix_output_verbose(2, pmix_globals.debug_output,
93 "sys call ftruncate(2) fail\n");
94 rc = PMIX_ERROR;
95 goto out;
96 } else {
97 rc = PMIX_SUCCESS;
98 }
99
100 #ifdef HAVE_POSIX_FALLOCATE
101 map_memory:
102 #endif
103 if (MAP_FAILED == (seg_addr = mmap(NULL, size,
104 PROT_READ | PROT_WRITE, MAP_SHARED,
105 sm_seg->seg_id, 0))) {
106 pmix_output_verbose(2, pmix_globals.debug_output,
107 "sys call mmap(2) fail\n");
108 rc = PMIX_ERROR;
109 goto out;
110 }
111 sm_seg->seg_cpid = my_pid;
112 sm_seg->seg_size = size;
113 sm_seg->seg_base_addr = (unsigned char *)seg_addr;
114 pmix_strncpy(sm_seg->seg_name, file_name, PMIX_PATH_MAX);
115
116 out:
117 if (-1 != sm_seg->seg_id) {
118 if (0 != close(sm_seg->seg_id)) {
119 pmix_output_verbose(2, pmix_globals.debug_output,
120 "sys call close(2) fail\n");
121 rc = PMIX_ERROR;
122 }
123 }
124 /* an error occured, so invalidate the shmem object and munmap if needed */
125 if (PMIX_SUCCESS != rc) {
126 if (MAP_FAILED != seg_addr) {
127 munmap((void *)seg_addr, size);
128 }
129 _segment_ds_reset(sm_seg);
130 }
131 return rc;
132 }
133
_mmap_segment_attach(pmix_pshmem_seg_t * sm_seg,pmix_pshmem_access_mode_t sm_mode)134 static int _mmap_segment_attach(pmix_pshmem_seg_t *sm_seg, pmix_pshmem_access_mode_t sm_mode)
135 {
136 mode_t mode = O_RDWR;
137 int mmap_prot = PROT_READ | PROT_WRITE;
138
139 if (sm_mode == PMIX_PSHMEM_RONLY) {
140 mode = O_RDONLY;
141 mmap_prot = PROT_READ;
142 }
143
144 if (-1 == (sm_seg->seg_id = open(sm_seg->seg_name, mode))) {
145 return PMIX_ERROR;
146 }
147 if (MAP_FAILED == (sm_seg->seg_base_addr = (unsigned char *)
148 mmap(NULL, sm_seg->seg_size,
149 mmap_prot, MAP_SHARED,
150 sm_seg->seg_id, 0))) {
151 /* mmap failed, so close the file and return NULL - no error check
152 * here because we are already in an error path...
153 */
154 pmix_output_verbose(2, pmix_globals.debug_output,
155 "sys call mmap(2) fail\n");
156 close(sm_seg->seg_id);
157 return PMIX_ERROR;
158 }
159 /* all is well */
160 /* if close fails here, that's okay. just let the user know and
161 * continue. if we got this far, open and mmap were successful...
162 */
163 if (0 != close(sm_seg->seg_id)) {
164 pmix_output_verbose(2, pmix_globals.debug_output,
165 "sys call close(2) fail\n");
166 }
167 sm_seg->seg_cpid = 0;/* FIXME */
168 return PMIX_SUCCESS;
169 }
170
_mmap_segment_detach(pmix_pshmem_seg_t * sm_seg)171 static int _mmap_segment_detach(pmix_pshmem_seg_t *sm_seg)
172 {
173 int rc = PMIX_SUCCESS;
174
175 if (0 != munmap((void *)sm_seg->seg_base_addr, sm_seg->seg_size)) {
176 pmix_output_verbose(2, pmix_globals.debug_output,
177 "sys call munmap(2) fail\n");
178 rc = PMIX_ERROR;
179 }
180 /* reset the contents of the pmix_sm_seg_t associated with this
181 * shared memory segment.
182 */
183 _segment_ds_reset(sm_seg);
184 return rc;
185 }
186
_mmap_segment_unlink(pmix_pshmem_seg_t * sm_seg)187 static int _mmap_segment_unlink(pmix_pshmem_seg_t *sm_seg)
188 {
189 if (-1 == unlink(sm_seg->seg_name)) {
190 pmix_output_verbose(2, pmix_globals.debug_output,
191 "sys call unlink(2) fail\n");
192 return PMIX_ERROR;
193 }
194
195 sm_seg->seg_id = PMIX_SHMEM_DS_ID_INVALID;
196 return PMIX_SUCCESS;
197 }
198