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-2011 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-2016 University of Houston. All rights reserved.
13  * Copyright (c) 2018      Research Organization for Information Science
14  *                         and Technology (RIST). All rights reserved.
15  * $COPYRIGHT$
16  *
17  * Additional copyrights may follow
18  *
19  * $HEADER$
20  */
21 
22 #include "ompi_config.h"
23 
24 #include <string.h>
25 
26 #include "opal/class/opal_list.h"
27 #include "opal/util/argv.h"
28 #include "ompi/mca/mca.h"
29 #include "opal/mca/base/base.h"
30 #include "ompi/mca/fs/fs.h"
31 #include "ompi/mca/fs/base/base.h"
32 #include "ompi/mca/common/ompio/common_ompio.h"
33 
34 /*
35  * This structure is needed so that we can close the modules
36  * which are not selected but were opened. mca_base_modules_close
37  * which does this job for us requires a opal_list_t which contains
38  * these modules
39  */
40 struct queried_module_t {
41     opal_list_item_t super;
42     mca_fs_base_component_t *om_component;
43     mca_fs_base_module_t *om_module;
44 };
45 typedef struct queried_module_t queried_module_t;
46 static OBJ_CLASS_INSTANCE(queried_module_t, opal_list_item_t, NULL, NULL);
47 
48 
49 /*
50  * Only one fs module can be attached to each file.
51  *
52  * This module calls the query funtion on all the components that were
53  * detected by fs_base_open. This function is called on a
54  * per-file basis. This function has the following function.
55  *
56  * 1. Iterate over the list of available_components
57  * 2. Call the query function on each of these components.
58  * 3. query function returns the structure containing pointers
59  *    to its module and its priority
60  * 4. Select the module with the highest priority
61  * 5. Call the init function on the selected module so that it does the
62  *    right setup for the file
63  * 6. Call finalize on all the other modules which returned
64  *    their module but were unfortunate to not get selected
65  */
66 
mca_fs_base_file_select(struct ompio_file_t * file,mca_base_component_t * preferred)67 int mca_fs_base_file_select (struct ompio_file_t *file,
68                              mca_base_component_t *preferred)
69 {
70     int priority;
71     int best_priority;
72     opal_list_item_t *item;
73     mca_base_component_list_item_t *cli;
74     mca_fs_base_component_t *component;
75     mca_fs_base_component_t *best_component;
76     mca_fs_base_module_t *module;
77     opal_list_t queried;
78     queried_module_t *om;
79     int err = MPI_SUCCESS;
80 
81     /* Check and see if a preferred component was provided. If it was
82      provided then it should be used (if possible) */
83 
84     if (NULL != preferred) {
85 
86         /* We have a preferred component. Check if it is available
87            and if so, whether it wants to run */
88          opal_output_verbose(10, ompi_fs_base_framework.framework_output,
89                              "fs:base:file_select: Checking preferred component: %s",
90                              preferred->mca_component_name);
91 
92          /* query the component for its priority and get its module
93             structure. This is necessary to proceed */
94 
95          component = (mca_fs_base_component_t *)preferred;
96          module = component->fsm_file_query (file, &priority);
97          if (NULL != module &&
98              NULL != module->fs_module_init) {
99 
100              /* this query seems to have returned something legitimate
101               * and we can now go ahead and initialize the
102               * file with it * but first, the functions which
103               * are null need to be filled in */
104 
105              /*fill_null_pointers (module);*/
106              file->f_fs = module;
107              file->f_fs_component = preferred;
108 
109              return module->fs_module_init(file);
110          }
111             /* His preferred component is present, but is unable to
112              * run. This is not a good sign. We should try selecting
113              * some other component We let it fall through and select
114              * from the list of available components
115              */
116      } /*end of selection for preferred component */
117 
118     /*
119      * We fall till here if one of the two things happened:
120      * 1. The preferred component was provided but for some reason was
121      * not able to be selected
122      * 2. No preferred component was provided
123      *
124      * All we need to do is to go through the list of available
125      * components and find the one which has the highest priority and
126      * use that for this file
127      */
128 
129     best_component = NULL;
130     best_priority = -1;
131     OBJ_CONSTRUCT(&queried, opal_list_t);
132 
133     OPAL_LIST_FOREACH(cli, &ompi_fs_base_framework.framework_components, mca_base_component_list_item_t) {
134        component = (mca_fs_base_component_t *) cli->cli_component;
135        opal_output_verbose(10, ompi_fs_base_framework.framework_output,
136                            "select: initialising %s component %s",
137                            component->fsm_version.mca_type_name,
138                            component->fsm_version.mca_component_name);
139 
140        /*
141         * we can call the query function only if there is a function :-)
142         */
143        if (NULL == component->fsm_file_query) {
144           opal_output_verbose(10, ompi_fs_base_framework.framework_output,
145                              "select: no query, ignoring the component");
146        } else {
147            /*
148             * call the query function and see what it returns
149             */
150            module = component->fsm_file_query (file, &priority);
151 
152            if (NULL == module ||
153                NULL == module->fs_module_init) {
154                /*
155                 * query did not return any action which can be used
156                 */
157                opal_output_verbose(10, ompi_fs_base_framework.framework_output,
158                                   "select: query returned failure");
159            } else {
160                opal_output_verbose(10, ompi_fs_base_framework.framework_output,
161                                   "select: query returned priority %d",
162                                   priority);
163                /*
164                 * is this the best component we have found till now?
165                 */
166                if (priority > best_priority) {
167                    best_priority = priority;
168                    best_component = component;
169                }
170 
171                om = OBJ_NEW(queried_module_t);
172                /*
173                 * check if we have run out of space
174                 */
175                if (NULL == om) {
176                    OBJ_DESTRUCT(&queried);
177                    return OMPI_ERR_OUT_OF_RESOURCE;
178                }
179                om->om_component = component;
180                om->om_module = module;
181                opal_list_append(&queried, (opal_list_item_t *)om);
182            } /* end else of if (NULL == module) */
183        } /* end else of if (NULL == component->fsm_init) */
184     } /* end for ... end of traversal */
185 
186     /*
187      * Now we have alist of components which successfully returned
188      * their module struct.  One of these components has the best
189      * priority. The rest have to be comm_unqueried to counter the
190      * effects of file_query'ing them. Finalize happens only on
191      * components which should are initialized.
192      */
193     if (NULL == best_component) {
194        /*
195         * This typically means that there was no component which was
196         * able to run properly this time. So, we need to abort
197         */
198         OBJ_DESTRUCT(&queried);
199         return OMPI_ERROR;
200     }
201 
202     /*
203      * We now have a list of components which have successfully
204      * returned their priorities from the query. We now have to
205      * unquery() those components which have not been selected and
206      * init() the component which was selected
207      */
208     while (NULL != (item = opal_list_remove_first(&queried))) {
209         om = (queried_module_t *) item;
210         if (om->om_component == best_component) {
211            /*
212             * this is the chosen component, we have to initialise the
213             * module of this component.
214             *
215             * ANJU: a component might not have all the functions
216             * defined.  Whereever a function pointer is null in the
217             * module structure we need to fill it in with the base
218             * structure function pointers. This is yet to be done
219             */
220 
221             /*
222              * We don return here coz we still need to go through and
223              * elease the other objects
224              */
225 
226             /*fill_null_pointers (om->om_module);*/
227             file->f_fs = om->om_module;
228             err = om->om_module->fs_module_init(file);
229             file->f_fs_component = (mca_base_component_t *)best_component;
230          } else {
231             /*
232              * this is not the "choosen one", finalize
233              */
234              if (NULL != om->om_component->fsm_file_unquery) {
235                 /* unquery the component only if they have some clean
236                  * up job to do. Components which are queried but do
237                  * not actually do anything typically do not have a
238                  * unquery. Hence this check is necessary
239                  */
240                  (void) om->om_component->fsm_file_unquery(file);
241                  opal_output_verbose(10, ompi_fs_base_framework.framework_output,
242                                      "select: component %s is not selected",
243                                      om->om_component->fsm_version.mca_component_name);
244                } /* end if */
245           } /* if not best component */
246           OBJ_RELEASE(om);
247     } /* traversing through the entire list */
248 
249     opal_output_verbose(10, ompi_fs_base_framework.framework_output,
250                        "select: component %s selected",
251                         best_component->fsm_version.mca_component_name);
252 
253     OBJ_DESTRUCT(&queried);
254 
255     return err;
256 }
257