"Fossies" - the Fresh Open Source Software archive 
Member "evms-2.5.5/plugins/multipath/multipath.c" of archive evms-2.5.5.tar.gz:
/*
* (C) Copyright IBM Corp. 2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Module: Multipath Plugin
* File: evms2/engine/plugins/multipath/multipath.c
*
* This is the generic EVMS multipath plugin. It is intended to detect and
* activate multipath devices based on multiple types of metadata (and even
* without metadata). It utilizes the multipath module in Device-Mapper.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <plugin.h>
#include "multipath.h"
/* Pointer to engine-services table. */
engine_functions_t *EngFncs;
/**
* mp_modules
*
* Array of multipath sub-modules. Index into this array using a
* multipath_type_t value.
**/
multipath_module_t mp_modules[] = {
{ .name = "lvm",
.setup = mp_lvm_setup,
.cleanup = mp_lvm_cleanup,
.probe = mp_lvm_probe,
.process = mp_lvm_process,
.allocate = mp_lvm_allocate,
.discard = mp_lvm_discard,
.delete = mp_lvm_delete,
.map = mp_lvm_map,
.build_targets= mp_lvm_build_targets,
},
};
/**
* multipath_setup_evms_plugin
*
* Perform all setup when the plugin is loaded.
**/
static int multipath_setup_evms_plugin(engine_functions_t *functions)
{
int rc, i;
EngFncs = functions;
LOG_ENTRY();
/* Setup each sub-module. */
for (i = 0; i < MULTIPATH_TYPE_MAX; i++) {
rc = mp_modules[i].setup();
if (rc) {
goto out;
}
}
/* Register the base namespace. */
rc = EngFncs->register_name(MP_NAME);
if (rc) {
goto out;
}
out:
if (rc) {
for (; i >= 0; i--) {
mp_modules[i].cleanup();
}
EngFncs->unregister_name(MP_NAME);
}
LOG_EXIT_INT(rc);
return rc;
}
/**
* multipath_cleanup_evms_plugin
*
* Cleanup the plugin when the engine closes.
**/
static void multipath_cleanup_evms_plugin(void)
{
int i;
LOG_ENTRY();
/* Cleanup each sub-module and release the namespace. */
for (i = 0; i < MULTIPATH_TYPE_MAX; i++) {
mp_modules[i].cleanup();
}
EngFncs->unregister_name(MP_NAME);
LOG_EXIT_VOID();
}
/**
* multipath_can_delete
**/
static int multipath_can_delete(storage_object_t *object)
{
LOG_ENTRY();
LOG_EXIT_INT(0);
return 0;
}
/**
* multipath_can_unassign
*
* Just like can_delete().
**/
static int multipath_can_unassign(storage_object_t *object)
{
LOG_ENTRY();
LOG_EXIT_INT(ENOSYS);
return ENOSYS;
}
/**
* multipath_can_set_volume
*
* We aren't yet going to support volumes directly on MP objects, since
* we're initially targetting this for LVM MP-PVs.
**/
static int multipath_can_set_volume(storage_object_t *object, boolean flag)
{
LOG_ENTRY();
LOG_EXIT_INT(EINVAL);
return EINVAL;
}
/**
* multipath_discover
*
* Probe all input objects for multipath metadata and create new segments as
* necessary.
**/
static int multipath_discover(list_anchor_t input_objects,
list_anchor_t output_objects,
boolean final_call)
{
storage_object_t *child;
list_element_t itr;
int i, rc, count = 0;
LOG_ENTRY();
LIST_FOR_EACH(input_objects, itr, child) {
/* Only interested in DATA objects. */
if (child->data_type != DATA_TYPE) {
LOG_DEBUG("%s is not a DATA object.\n", child->name);
EngFncs->insert_thing(output_objects, child, 0, NULL);
continue;
}
/* Don't re-examine multipath objects. */
if (child->plugin == &multipath_plugin) {
LOG_DEBUG("%s is a multipath object.\n", child->name);
EngFncs->insert_thing(output_objects, child, 0, NULL);
continue;
}
/* Give each sub-module a chance to see if they recognize
* this object. If they do, they'll put it on an internal
* list to be processed later in discovery.
*/
for (i = 0; i < MULTIPATH_TYPE_MAX; i++) {
rc = mp_modules[i].probe(child);
if (!rc) {
break;
}
}
if (i == MULTIPATH_TYPE_MAX) {
/* If nobody recognizes it, put it on the output list. */
EngFncs->insert_thing(output_objects, child, 0, NULL);
}
}
/* Now process each type-specific list to actually construct the
* multipath segments.
*/
for (i = 0; i < MULTIPATH_TYPE_MAX; i++) {
count += mp_modules[i].process(output_objects);
}
if (final_call) {
cleanup_stale_daemons();
}
LOG_EXIT_INT(count);
return count;
}
/**
* multipath_discard
*
* Forget about these objects. Don't delete them. Just clean up any data
* structures you may have associated with them. The Engine will call to
* deactivate the objects during commit.
*
* Since we need part of the private data to properly deactivate, we should
* only free it if the object is not active (and hence doesn't need to be
* deactivated). If the object is active, we'll free the private-data after
* deactivation.
**/
static int multipath_discard(list_anchor_t objects)
{
storage_object_t *object;
list_element_t itr;
multipath_t *mp;
LOG_ENTRY();
LIST_FOR_EACH(objects, itr, object) {
mp = object->private_data;
mp_modules[mp->type].discard(object);
if (!(object->flags & SOFLAG_ACTIVE)) {
EngFncs->engine_free(mp);
object->private_data = NULL;
} else {
mp->flags |= MP_FLAG_DELETE_PRIVATE_DATA;
}
EngFncs->free_segment(object);
}
LOG_EXIT_INT(0);
return 0;
}
/**
* multipath_delete
*
* Delete this segment. Erase all necessary metadata and free up the private
* data structures.
*
* Since we need part of the private data to properly deactivate, we should
* only free it if the object is not active (and hence doesn't need to be
* deactivated). If the object is active, we'll free the private-data after
* deactivation.
**/
static int multipath_delete(storage_object_t *object,
list_anchor_t child_objects)
{
multipath_t *mp = object->private_data;
LOG_ENTRY();
EngFncs->concatenate_lists(child_objects, object->child_objects);
mp_modules[mp->type].delete(object);
if (!(object->flags & SOFLAG_ACTIVE)) {
EngFncs->engine_free(mp);
object->private_data = NULL;
} else {
mp->flags |= MP_FLAG_DELETE_PRIVATE_DATA;
}
EngFncs->free_segment(object);
LOG_EXIT_INT(0);
return 0;
}
/**
* multipath_unassign
*
* Don't support unassign yet.
**/
static int multipath_unassign(storage_object_t *object)
{
LOG_ENTRY();
LOG_EXIT_INT(ENOSYS);
return ENOSYS;
}
/**
* multipath_add_sectors_to_kill_list
*
* Send the kill-sectors command to one of the child objects.
**/
static int multipath_add_sectors_to_kill_list(storage_object_t *object,
lsn_t lsn, sector_count_t count)
{
multipath_t *mp = object->private_data;
int rc = EIO;
LOG_ENTRY();
rc = mp_modules[mp->type].map(&object, &lsn, &count);
if (!rc) {
rc = KILL_SECTORS(object, lsn, count);
}
LOG_EXIT_INT(rc);
return rc;
}
/**
* multipath_commit_changes
*
* Nothing to do yet for commit, since we don't yet have any metadata.
**/
static int multipath_commit_changes(storage_object_t *object,
commit_phase_t phase)
{
LOG_ENTRY();
LOG_EXIT_INT(0);
return 0;
}
/**
* multipath_can_activate
*
* Multipath segments can always be activated.
**/
static int multipath_can_activate(storage_object_t *object)
{
LOG_ENTRY();
LOG_EXIT_INT(0);
return 0;
}
/**
* multipath_activate
*
* Activate this multipath segment using Device-Mapper.
**/
static int multipath_activate(storage_object_t *object)
{
int rc;
LOG_ENTRY();
rc = stop_daemon(object);
if (rc) {
goto out;
}
rc = activate_segment(object);
if (rc) {
goto out;
}
rc = start_daemon(object);
if (rc) {
goto out;
}
object->flags &= ~SOFLAG_NEEDS_ACTIVATE;
out:
LOG_EXIT_INT(rc);
return rc;
}
/**
* multipath_can_deactivate
*
* Multipath segments can always be deactivated.
**/
static int multipath_can_deactivate(storage_object_t *object)
{
LOG_ENTRY();
LOG_EXIT_INT(0);
return 0;
}
/**
* multipath_deactivate
*
* Deactivation will only happen when the segment has been deleted or
* discarded. Since we need part of the private-data to do the deactivation,
* we need to free that private-data once we're done with it.
**/
static int multipath_deactivate(storage_object_t *object)
{
multipath_t *mp = object->private_data;
int rc;
LOG_ENTRY();
stop_daemon(object);
rc = EngFncs->dm_deactivate(object);
if (!rc) {
object->flags &= ~SOFLAG_NEEDS_DEACTIVATE;
if (mp->flags & MP_FLAG_DELETE_PRIVATE_DATA) {
/* If this deactivate is due to deleting or discarding
* the segment, we need to delete the private data.
*/
EngFncs->engine_free(mp);
}
}
LOG_EXIT_INT(rc);
return rc;
}
/**
* multipath_get_info
*
* Return any additional information that you wish to provide about the object.
* The Engine provides an external API to get the information stored in the
* storage_object_t. This call is to get any other information about the object
* that is not specified in the storage_object_t. Any piece of information you
* wish to provide must be in an extended_info_t structure. Use the Engine's
* engine_alloc() to allocate the memory for the extended_info_t. Also use
* engine_alloc() to allocate any strings that may go into the extended_info_t.
* Then use engine_alloc() to allocate an extended_info_array_t with enough
* entries for the number of extended_info_t structures you are returning. Fill
* in the array and return it in *info.
*
* If you have extended_info_t descriptors that themselves may have more
* extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag in
* the extended_info_t flags field. If the caller wants more information about
* a particular extended_info_t item, this API will be called with a pointer to
* the storage_object_t and with a pointer to the name of the extended_info_t
* item. In that case, return an extended_info_array_t with further information
* about the item. Each of those items may have the
* EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your
* responsibility to give the items unique names so that you know which item the
* caller is asking additional information for. If info_name is NULL, the caller
* just wants top level information about the object.
*
* Return:
* - 0 for success.
* - Non-zero error-code for failure.
*
* OPTIONAL
**/
static int multipath_get_info(storage_object_t *object,
char *info_name,
extended_info_array_t **info)
{
LOG_ENTRY();
LOG_EXIT_INT(ENOSYS);
return ENOSYS;
}
/**
* multipath_get_plugin_info
*
* Return any additional information that you wish to provide about your plugin.
* The Engine provides an external API to get the information stored in the
* plugin_record_t. This call is to get any other information about the plugin
* that is not specified in the plugin_record_t. Any piece of information you
* wish to provide must be in an extended_info_t structure. Use the Engine's
* engine_alloc() to allocate the memory for the extended_info_t. Also use
* engine_alloc() to allocate any strings that may go into the extended_info_t.
* Then use engine_alloc() to allocate an extended_info_array_t with enough
* entries for the number of extended_info_t structures you are returning. Fill
* in the array and return it in *info.
*
* If you have extended_info_t descriptors that themselves may have more
* extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag in
* the extended_info_t flags field. If the caller wants more information about
* a particular extended_info_t item, this API will be called with a pointer to
* the name of the extended_info_t item. In that case, return an
* extended_info_array_t with further information about the item. Each of those
* items may have the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you
* desire. It is your responsibility to give the items unique names so that you
* know which item the caller is asking additional information for. If
* info_name is NULL, the caller just wants top level information about the
* plugin.
*
* Return:
* - 0 for success.
* - Non-zero error-code for failure.
*
* OPTIONAL
**/
static int multipath_get_plugin_info(char *info_name,
extended_info_array_t **info)
{
LOG_ENTRY();
LOG_EXIT_INT(ENOSYS);
return ENOSYS;
}
/**
* multipath_read
*
* Read from one of the child objects.
**/
static int multipath_read(storage_object_t *object, lsn_t lsn,
sector_count_t count, void *buffer)
{
multipath_t *mp = object->private_data;
int rc;
LOG_ENTRY();
rc = mp_modules[mp->type].map(&object, &lsn, &count);
if (!rc) {
rc = READ(object, lsn, count, buffer);
}
LOG_EXIT_INT(rc);
return rc;
}
/**
* multipath_write
*
* Write to one of the child objects.
**/
static int multipath_write(storage_object_t *object, lsn_t lsn,
sector_count_t count, void *buffer)
{
multipath_t *mp = object->private_data;
int rc;
LOG_ENTRY();
rc = mp_modules[mp->type].map(&object, &lsn, &count);
if (!rc) {
rc = WRITE(object, lsn, count, buffer);
}
LOG_EXIT_INT(rc);
return rc;
}
/**
* multipath_backup_metadata
*
* Nothing to do yet for backup, since we don't yet have any metadata.
**/
static int multipath_backup_metadata(storage_object_t *object)
{
LOG_ENTRY();
LOG_EXIT_INT(0);
return 0;
}
/* Plugin-Functions table for the Multipath plugin. */
static plugin_functions_t multipath_functions = {
.setup_evms_plugin = multipath_setup_evms_plugin,
.cleanup_evms_plugin = multipath_cleanup_evms_plugin,
.can_delete = multipath_can_delete,
.can_unassign = multipath_can_unassign,
.can_set_volume = multipath_can_set_volume,
.discover = multipath_discover,
.discard = multipath_discard,
.delete = multipath_delete,
.unassign = multipath_unassign,
.add_sectors_to_kill_list = multipath_add_sectors_to_kill_list,
.commit_changes = multipath_commit_changes,
.can_activate = multipath_can_activate,
.activate = multipath_activate,
.can_deactivate = multipath_can_deactivate,
.deactivate = multipath_deactivate,
.get_info = multipath_get_info,
.get_plugin_info = multipath_get_plugin_info,
.read = multipath_read,
.write = multipath_write,
.backup_metadata = multipath_backup_metadata,
};
/* Plugin-record for the Multipath plugin.*/
plugin_record_t multipath_plugin = {
.id = EVMS_MULTIPATH_PLUGIN_ID,
.version = {
.major = MAJOR_VERSION,
.minor = MINOR_VERSION,
.patchlevel = PATCH_LEVEL
},
.required_engine_api_version = {
.major = 15,
.minor = 0,
.patchlevel = 0
},
.required_plugin_api_version = {
.plugin = {
.major = 13,
.minor = 1,
.patchlevel = 0
}
},
.short_name = EVMS_MULTIPATH_PLUGIN_SHORT_NAME,
.long_name = EVMS_MULTIPATH_PLUGIN_LONG_NAME,
.oem_name = EVMS_IBM_OEM_NAME,
.functions = {
.plugin = &multipath_functions
},
};
plugin_record_t *evms_plugin_records[] = {
&multipath_plugin,
NULL
};