1 /*
2 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3 * University Research and Technology
4 * Corporation. All rights reserved.
5 * Copyright (c) 2004-2005 The University of Tennessee and The University
6 * of Tennessee Research Foundation. All rights
7 * reserved.
8 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9 * University of Stuttgart. All rights reserved.
10 * Copyright (c) 2004-2005 The Regents of the University of California.
11 * All rights reserved.
12 * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved.
13 * Copyright (c) 2008-2011 University of Houston. All rights reserved.
14 * Copyright (c) 2015 Research Organization for Information Science
15 * and Technology (RIST). All rights reserved.
16 * Copyright (c) 2016-2017 IBM Corporation. All rights reserved.
17 * $COPYRIGHT$
18 *
19 * Additional copyrights may follow
20 *
21 * $HEADER$
22 */
23
24 #include "ompi_config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "mpi.h"
31 #include "ompi/file/file.h"
32 #include "opal/util/argv.h"
33 #include "opal/util/output.h"
34 #include "opal/util/info.h"
35 #include "opal/class/opal_list.h"
36 #include "opal/class/opal_object.h"
37 #include "ompi/mca/mca.h"
38 #include "opal/mca/base/base.h"
39 #include "ompi/mca/io/io.h"
40 #include "ompi/mca/io/base/base.h"
41 #include "ompi/mca/io/base/io_base_request.h"
42 #include "ompi/mca/fs/fs.h"
43 #include "ompi/mca/fs/base/base.h"
44 #include "ompi/mca/fcoll/fcoll.h"
45 #include "ompi/mca/fcoll/base/base.h"
46 #include "ompi/mca/fbtl/fbtl.h"
47 #include "ompi/mca/fbtl/base/base.h"
48 #include "ompi/mca/sharedfp/sharedfp.h"
49 #include "ompi/mca/sharedfp/base/base.h"
50
51 opal_mutex_t ompi_mpi_ompio_bootstrap_mutex = OPAL_MUTEX_STATIC_INIT;
52 /*
53 * Local types
54 */
55 struct avail_io_t {
56 opal_list_item_t super;
57
58 mca_io_base_version_t ai_version;
59
60 int ai_priority;
61 mca_io_base_components_t ai_component;
62 mca_io_base_modules_t ai_module;
63 struct mca_io_base_file_t *ai_module_data;
64 };
65 typedef struct avail_io_t avail_io_t;
66
67 /*
68 * Local functions
69 */
70 static opal_list_t *check_components(opal_list_t *components,
71 ompi_file_t *file,
72 char **names, int num_names);
73 static avail_io_t *check_one_component(ompi_file_t *file,
74 const mca_base_component_t *component);
75
76 static avail_io_t *query(const mca_base_component_t *component,
77 ompi_file_t *file);
78 static avail_io_t *query_2_0_0(const mca_io_base_component_2_0_0_t *io_component,
79 ompi_file_t *file);
80
81 static void unquery(avail_io_t *avail, ompi_file_t *file);
82
83 static int module_init(ompi_file_t *file);
84
85
86 /*
87 * Stuff for the OBJ interface
88 */
89 static OBJ_CLASS_INSTANCE(avail_io_t, opal_list_item_t, NULL, NULL);
90
91
92 /*
93 * This function is called at the initialization time of every
94 * file. It is used to select which io component will be
95 * active for a given file.
96 */
mca_io_base_file_select(ompi_file_t * file,mca_base_component_t * preferred)97 int mca_io_base_file_select(ompi_file_t *file,
98 mca_base_component_t *preferred)
99 {
100 int err;
101 char *str;
102 opal_list_t *selectable;
103 opal_list_item_t *item;
104 avail_io_t *avail, selected;
105
106 /* Announce */
107
108 opal_output_verbose(10, ompi_io_base_framework.framework_output,
109 "io:base:file_select: new file: %s",
110 file->f_filename);
111
112 /* Initialize all the relevant pointers, since they're used as
113 sentinel values */
114
115 file->f_io_version = MCA_IO_BASE_V_NONE;
116 file->f_io_selected_data = NULL;
117
118 /* Compute the intersection of all of my available components with
119 the components from all the other processes in this file */
120
121 /* JMS CONTINUE HERE */
122
123 /* See if a preferred component was provided. If so, try to
124 select it. If we don't succeed, fall through and do a normal
125 selection. */
126
127 err = OMPI_ERROR;
128 if (NULL != preferred) {
129 str = &(preferred->mca_component_name[0]);
130
131 opal_output_verbose(10, ompi_io_base_framework.framework_output,
132 "io:base:file_select: Checking preferred module: %s",
133 str);
134 selectable = check_components(&ompi_io_base_framework.framework_components,
135 file, &str, 1);
136
137 /* If we didn't get a preferred module, then call again
138 without a preferred module. This makes the logic below
139 dramatically simpler. */
140
141 if (NULL == selectable) {
142 return mca_io_base_file_select(file, NULL);
143 }
144
145 /* We only fall through here if we were able to select one of
146 the preferred modules */
147 }
148
149 /* Nope -- a specific [set of] component[s] was not requested. Go
150 check them all. */
151
152 else {
153 opal_output_verbose(10, ompi_io_base_framework.framework_output,
154 "io:base:file_select: Checking all available modules");
155 selectable = check_components(&ompi_io_base_framework.framework_components,
156 file, NULL, 0);
157 }
158
159 /* Upon return from the above, the modules list will contain the
160 list of modules that returned (priority >= 0). If we have no
161 io modules available, it's an error */
162
163 if (NULL == selectable) {
164 /* There's no modules available. Doh! */
165 /* show_help */
166 return OMPI_ERROR;
167 }
168
169 /* Do some kind of collective operation to find a module that
170 everyone has available */
171
172 #if 1
173 /* For the moment, just take the top module off the list */
174 /* MSC actually take the buttom */
175 item = opal_list_remove_last(selectable);
176 avail = (avail_io_t *) item;
177 selected = *avail;
178 OBJ_RELEASE(avail);
179 #else
180 /* JMS CONTINUE HERE */
181 #endif
182
183 /* Everything left in the selectable list is therefore unwanted,
184 and we call their unquery() method (because they all had
185 query() invoked, but will never have init() invoked in this
186 scope). */
187
188 for (item = opal_list_remove_first(selectable); item != NULL;
189 item = opal_list_remove_first(selectable)) {
190 avail = (avail_io_t *) item;
191 unquery(avail, file);
192 OBJ_RELEASE(item);
193 }
194 OBJ_RELEASE(selectable);
195
196 /* Save the pointers of the selected module on the ompi_file_t */
197
198 file->f_io_version = selected.ai_version;
199 file->f_io_selected_component = selected.ai_component;
200 file->f_io_selected_module = selected.ai_module;
201 file->f_io_selected_data = selected.ai_module_data;
202
203 if (!strcmp (selected.ai_component.v2_0_0.io_version.mca_component_name,
204 "ompio")) {
205 int ret;
206
207 opal_mutex_lock(&ompi_mpi_ompio_bootstrap_mutex);
208 if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_fs_base_framework, 0))) {
209 opal_mutex_unlock(&ompi_mpi_ompio_bootstrap_mutex);
210 return err;
211 }
212 if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_fcoll_base_framework, 0))) {
213 opal_mutex_unlock(&ompi_mpi_ompio_bootstrap_mutex);
214 return err;
215 }
216 if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_fbtl_base_framework, 0))) {
217 opal_mutex_unlock(&ompi_mpi_ompio_bootstrap_mutex);
218 return err;
219 }
220 if (OMPI_SUCCESS != (ret = mca_base_framework_open(&ompi_sharedfp_base_framework, 0))) {
221 opal_mutex_unlock(&ompi_mpi_ompio_bootstrap_mutex);
222 return err;
223 }
224 opal_mutex_unlock(&ompi_mpi_ompio_bootstrap_mutex);
225
226 if (OMPI_SUCCESS !=
227 (ret = mca_fs_base_find_available(OPAL_ENABLE_PROGRESS_THREADS, 1))) {
228 return err;
229 }
230 if (OMPI_SUCCESS !=
231 (ret = mca_fcoll_base_find_available(OPAL_ENABLE_PROGRESS_THREADS, 1))) {
232 return err;
233 }
234 if (OMPI_SUCCESS !=
235 (ret = mca_fbtl_base_find_available(OPAL_ENABLE_PROGRESS_THREADS, 1))) {
236 return err;
237 }
238 if (OMPI_SUCCESS !=
239 (ret = mca_sharedfp_base_find_available(OPAL_ENABLE_PROGRESS_THREADS, 1))) {
240 return err;
241 }
242
243 }
244 /* Finally -- intialize the selected module. */
245
246 if (OMPI_SUCCESS != (err = module_init(file))) {
247 return err;
248 }
249
250 /* Announce the winner */
251
252 opal_output_verbose(10, ompi_io_base_framework.framework_output,
253 "io:base:file_select: Selected io module %s",
254 selected.ai_component.v2_0_0.io_version.mca_component_name);
255
256 return OMPI_SUCCESS;
257 }
258
avail_io_compare(opal_list_item_t ** itema,opal_list_item_t ** itemb)259 static int avail_io_compare (opal_list_item_t **itema,
260 opal_list_item_t **itemb)
261 {
262 const avail_io_t *availa = (const avail_io_t *) *itema;
263 const avail_io_t *availb = (const avail_io_t *) *itemb;
264
265 /* highest component last */
266 if (availa->ai_priority > availb->ai_priority) {
267 return 1;
268 } else if (availa->ai_priority < availb->ai_priority) {
269 return -1;
270 } else {
271 return 0;
272 }
273 }
274
275 /*
276 * For each component in the list, if it is in the list of names (or
277 * the list of names is NULL), then check and see if it wants to run,
278 * and do the resulting priority comparison. Make a list of
279 * (component, module) tuples (of type avail_io_t) to be only those
280 * who returned that they want to run, and put them in priority order.
281 */
check_components(opal_list_t * components,ompi_file_t * file,char ** names,int num_names)282 static opal_list_t *check_components(opal_list_t *components,
283 ompi_file_t *file,
284 char **names, int num_names)
285 {
286 int i;
287 const mca_base_component_t *component;
288 mca_base_component_list_item_t *cli;
289 bool want_to_check;
290 opal_list_t *selectable;
291 avail_io_t *avail;
292
293 /* Make a list of the components that query successfully */
294
295 selectable = OBJ_NEW(opal_list_t);
296
297 /* Scan through the list of components. This nested loop is
298 O(N^2), but we should never have too many components and/or
299 names, so this *hopefully* shouldn't matter... */
300
301 OPAL_LIST_FOREACH(cli, components, mca_base_component_list_item_t) {
302 component = cli->cli_component;
303
304 /* If we have a list of names, scan through it */
305
306 if (0 == num_names) {
307 want_to_check = true;
308 } else {
309 want_to_check = false;
310 for (i = 0; i < num_names; ++i) {
311 if (0 == strcmp(names[i], component->mca_component_name)) {
312 want_to_check = true;
313 }
314 }
315 }
316
317 /* If we determined that we want to check this component, then
318 do so */
319
320 if (want_to_check) {
321 avail = check_one_component(file, component);
322 if (NULL != avail) {
323 /* Put this item on the list in priority order
324 (highest priority first). Should it go first? */
325 /* MSC actually put it Lowest priority first */
326 /* NTH sorted later */
327 opal_list_append(selectable, (opal_list_item_t*)avail);
328 }
329 }
330 }
331
332 /* If we didn't find any available components, return an error */
333
334 if (0 == opal_list_get_size(selectable)) {
335 OBJ_RELEASE(selectable);
336 return NULL;
337 }
338
339 opal_list_sort(selectable, avail_io_compare);
340
341 /* All done */
342
343 return selectable;
344 }
345
346 /*
347 * Check a single component
348 */
check_one_component(ompi_file_t * file,const mca_base_component_t * component)349 static avail_io_t *check_one_component(ompi_file_t *file,
350 const mca_base_component_t *component)
351 {
352 avail_io_t *avail;
353
354 avail = query(component, file);
355 if (NULL != avail) {
356 avail->ai_priority = (avail->ai_priority < 100) ?
357 avail->ai_priority : 100;
358 avail->ai_priority = (avail->ai_priority < 0) ?
359 0 : avail->ai_priority;
360 opal_output_verbose(10, ompi_io_base_framework.framework_output,
361 "io:base:file_select: component available: %s, priority: %d",
362 component->mca_component_name,
363 avail->ai_priority);
364 } else {
365 opal_output_verbose(10, ompi_io_base_framework.framework_output,
366 "io:base:file_select: component not available: %s",
367 component->mca_component_name);
368 }
369
370 return avail;
371 }
372
373
374 /**************************************************************************
375 * Query functions
376 **************************************************************************/
377
378 /*
379 * Take any version of a io module, query it, and return the right
380 * module struct
381 */
query(const mca_base_component_t * component,ompi_file_t * file)382 static avail_io_t *query(const mca_base_component_t *component,
383 ompi_file_t *file)
384 {
385 const mca_io_base_component_2_0_0_t *ioc_200;
386
387 /* MCA version check */
388
389 if (MCA_BASE_VERSION_MAJOR == component->mca_major_version &&
390 MCA_BASE_VERSION_MINOR == component->mca_minor_version &&
391 MCA_BASE_VERSION_RELEASE == component->mca_release_version) {
392 ioc_200 = (mca_io_base_component_2_0_0_t *) component;
393
394 return query_2_0_0(ioc_200, file);
395 }
396
397 /* Unknown io API version -- return error */
398
399 return NULL;
400 }
401
402
query_2_0_0(const mca_io_base_component_2_0_0_t * component,ompi_file_t * file)403 static avail_io_t *query_2_0_0(const mca_io_base_component_2_0_0_t *component,
404 ompi_file_t *file)
405 {
406 int priority;
407 avail_io_t *avail;
408 const mca_io_base_module_2_0_0_t *module;
409 struct mca_io_base_file_t *module_data;
410
411 /* Query v2.0.0 */
412
413 avail = NULL;
414 module_data = NULL;
415 module = component->io_file_query(file, &module_data, &priority);
416 if (NULL != module) {
417 avail = OBJ_NEW(avail_io_t);
418 avail->ai_version = MCA_IO_BASE_V_2_0_0;
419 avail->ai_priority = priority;
420 avail->ai_component.v2_0_0 = *component;
421 avail->ai_module.v2_0_0 = *module;
422 avail->ai_module_data = module_data;
423 }
424
425 return avail;
426 }
427
428
429 /**************************************************************************
430 * Unquery functions
431 **************************************************************************/
432
unquery(avail_io_t * avail,ompi_file_t * file)433 static void unquery(avail_io_t *avail, ompi_file_t *file)
434 {
435 const mca_io_base_component_2_0_0_t *ioc_200;
436
437 switch(avail->ai_version) {
438 case MCA_IO_BASE_V_2_0_0:
439 ioc_200 = &(avail->ai_component.v2_0_0);
440 ioc_200->io_file_unquery(file, avail->ai_module_data);
441 break;
442
443 default:
444 break;
445 }
446 }
447
448
449 /**************************************************************************
450 * Module_Init functions
451 **************************************************************************/
452
453 /*
454 * Initialize a module
455 */
module_init(ompi_file_t * file)456 static int module_init(ompi_file_t *file)
457 {
458 const mca_io_base_module_2_0_0_t *iom_200;
459
460 switch(file->f_io_version) {
461 case MCA_IO_BASE_V_2_0_0:
462 iom_200 = &(file->f_io_selected_module.v2_0_0);
463 return iom_200->io_module_file_open(file->f_comm, file->f_filename,
464 file->f_amode, file->super.s_info,
465 file);
466 break;
467
468 default:
469 return OMPI_ERROR;
470 break;
471 }
472
473 /* No way to reach here */
474 }
475