Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 115875 | Differences between
and this patch

Collapse All | Expand All

(-)evms-2.5.4/doc/evms.conf (+19 lines)
Lines 251-253 lvm2 { Link Here
251
	device_size_prompt = yes
251
	device_size_prompt = yes
252
}
252
}
253
253
254
# User devmapper section
255
# This allows us to use a device-mapper device directly as a disk
256
# without the need for loopback
257
# Be careful not to specify any targets that are created by evms
258
# This can be useful for any devices created via dmraid or other means
259
260
# In order for this to work "dm*" has to be in the list of includes
261
262
devmapper {
263
	# This needs to be set to yes to enable
264
	#dm_user = yes
265
	
266
	# List of targets to discover as disks
267
	# These are the target names as seen with "dmsetup ls"
268
	# only specific targets can be used
269
	# we need to avoid evms created targets
270
	#dm_user_targets = [ raid1_device raid0_device ]
271
}
272
(-)evms-2.5.4/doc/evms.conf.~1~ (+253 lines)
Line 0 Link Here
1
# EVMS Configuration file
2
3
# This file is a useable sample.
4
# Its location should be /etc/evms.conf
5
# It contains the default values which will be used in the absence of a
6
# configuration file or the absence of a configuration option being set.
7
8
# Global engine section
9
engine {
10
	mode		= readwrite
11
12
	# Possible values for debug_level in order are: critical, serious,
13
	# error, warning, default, details, entry_exit, debug, extra, everything
14
	#
15
	# The default value is "default".  Only log entries designated at the
16
	# debug_level or at a more severe level than the debug_level will be
17
	# printed to the log.  Thus, a debug_level of "default" will also log
18
	# critical, serious, error, and warning messages.  "critical" will
19
	# produce the smallest log, and "everything" will produce the largest
20
	# log.
21
22
	debug_level	= default
23
24
	log_file	= /var/log/evms-engine.log
25
26
	# Include microseconds in the log timestamps.  Default is "no".
27
28
#	log_usec	= yes
29
30
	# Include process IDs in the timestamps for log entries.  Default is
31
	# "no", unless the Engine is running in a clustered environment, in
32
	# which case PIDs are always included, since the Engine will have
33
	# several threads running.
34
35
#	log_pid		= yes
36
37
	# Open the log file with O_SYNC so that all writes to the log file
38
	# are guaranteed to be on the disk rather than just in cache.
39
	# Default is "no".
40
41
#	sync_log	= no
42
43
	# The directory where EVMS puts its metadata backup files.
44
45
	metadata_backup_dir	= /var/evms/metadata_backups
46
47
	# Save a backup of the metadata after each successful save of a
48
	# configuration change
49
50
#	auto_metadata_backup	= yes
51
}
52
53
# Settings if the Engine is opened in daemon mode
54
daemon {
55
	debug_level	= default	# Same settings as available for
56
					# engine.debug_level
57
58
	log_file	= /var/log/evms-daemon.log
59
60
	# Include microseconds in the log timestamps.  Default is "no".
61
62
#	log_usec	= yes
63
64
	# Include process IDs in the timestamps for log entries.  Default is
65
	# "no", unless the Engine is running in a clustered environment, in
66
	# which case PIDs are always included, since the Engine will have
67
	# several threads running.
68
69
#	log_pid		= yes
70
71
	# Open the log file with O_SYNC so that all writes to the log file
72
	# are guaranteed to be on the disk rather than just in cache.
73
	# Default is "no".
74
75
#	sync_log	= no
76
}
77
78
79
# Clustering section
80
81
clustering {
82
83
	# The number of seconds the engine/daemon should wait for a valid
84
	# cluster membership to show up.
85
86
	membership_timeout = 10
87
}
88
89
90
# Activation section
91
#
92
# Use this section to tell EVMS which volumes and objects should be activated.
93
94
activate {
95
96
	# Names of volumes and objects that should be activated.
97
	#
98
	# Names can be specified using "*", "?", and "[...]" notations.
99
100
	include = [ * ]
101
102
	# Names of volumes and objects that should not be activated.
103
	#
104
	# Names can be specified using "*", "?", and "[...]" notations.
105
106
	exclude = [ ]
107
}
108
109
110
# Local disk manager sections
111
112
# Use this section to tell EVMS where to look for devices and which devices to
113
# include or exclude on a system without sysfs (i.e., 2.4 kernels). If you are
114
# using a 2.6 kernel, you'll likely want to see the "sysfs_devices" section
115
# instead of this one.
116
117
legacy_devices {
118
119
	# "scan" is the location of the dev node tree.
120
121
	scan = /dev
122
123
	# "directories" is any directories under the "scan" directory you want
124
	# searched recursively. On systems running devfs without devfsd, the
125
	# default settings will find all IDE and SCSI disks.
126
127
	directories = [ ide scsi dasd ]
128
129
	# "include" are the block devices found in the dev tree that you want
130
	# EVMS to use as disks.  By default, this will search for traditional
131
	# style device names (e.g., hda, sdb).  If you know the exact disks that
132
	# your system uses, you can specify them here to cut down on unnecessary
133
	# searching.
134
	#
135
	# If you are running devfs with devfsd, the default settings will find
136
	# the old-style names (eg. hda). If you wish to use the new-style names
137
	# (eg. ide/host0/bus0/target0/lun0/disc), simply remove "sd?" and "hd?"
138
	# from the list below. If you are running devfs without devfsd, the
139
	# new-style names will be used.
140
	#
141
	# Block device names can be specified using "*", "?", and "[...]"
142
	# notations.
143
144
	include = [ hd? sd? dasd? disc ]
145
146
	# "exclude" are the block devices found in the dev tree that you don't
147
	# want EVMS to use as disks.  Entries here will override any possible
148
	# matches from the "include" setting.  Thus, if you specify "hd?" in
149
	# "include", and "hdc" in "exclude", EVMS will examine all IDE disks
150
	# except hdc.
151
	#
152
	# Block device names can be specified using "*", "?", and "[...]"
153
	# notations.
154
155
	exclude = [ ]
156
157
	# "max_open_disks" is the maximum number of disks that EVMS will have
158
	# open file-descriptors for while the engine is running. The allowable
159
	# range is 1 to 1024, and the default value is 64.
160
161
#	max_open_disks = 64
162
}
163
164
# Use this section to tell EVMS where to look for devices and which devices to
165
# include or exclude on a system with sysfs (i.e., 2.5 and later kernels).
166
167
sysfs_devices {
168
169
	# "include" are the block devices found in the /sys/block/
170
	# directory that you want EVMS to use as disks.
171
	#
172
	# Block device names can be specified using "*", "?", and "[...]"
173
	# notations.
174
175
	include = [ * ]
176
177
	# "exclude" are the block devices found in the /sys/block/
178
	# directory that you don't want EVMS to use as disks.  Entries here
179
	# will override any possible matches from the "include" setting.
180
	#
181
	# Block device names can be specified using "*", "?", and "[...]"
182
	# notations.
183
184
	exclude = [ ]
185
186
	# "max_open_disks" is the maximum number of disks that EVMS will have
187
	# open file-descriptors for while the engine is running. The allowable
188
	# range is 1 to 1024, and the default value is 64.
189
190
#	max_open_disks = 64
191
192
	# "ignore_sysfs" will tell the disk plugin to ignore the sysfs_devices
193
	# section, and fall back to the legacy_devices section, even if sysfs
194
	# is available. The default is "no", which should be fine for almost
195
	# all users.
196
197
#	ignore_sysfs = no
198
}
199
200
201
# Cluster Segment Manager (CSM) section
202
203
csm {
204
205
	# Set admin_mode to yes when you wish to force the CSM to discover
206
	# objects from all cluster containers, allowing you to perform
207
	# configuration and maintenance.  Setting admin_mode to yes will cause
208
	# the CSM to ignore container ownership which will allow you to
209
	# configure storage in a maintenance mode.
210
	#
211
	# The default is no.
212
213
#	admin_mode = yes
214
}
215
216
217
# Multipath section
218
#
219
# Use this section to tell EVMS which paths in a multipath device should be
220
# treated only as "backup" paths. These paths will be activated in the kernel
221
# in a separate priority-group, and will only be used when all of the "normal"
222
# paths have failed.
223
#
224
# Each entry in this section should be the name of a multipath device on your
225
# system. The value for each entry should be the names of the child objects
226
# which should be treated as "backup" paths. Child objects which should be
227
# treated as "active" paths should not be listed here.
228
#
229
# Do not use any wildcard characters in this section.
230
231
multipath {
232
#	md/md0 = [ hdc ]
233
#	mp/lvm/vg1-pv1 = [ hdd ]
234
}
235
236
237
# LVM2 plugin section.
238
239
lvm2 {
240
	# Should the LVM2 plugin prompt you for confirmation when it finds
241
	# LVM2 metadata on an object, but the object does not pass the
242
	# necessary size checks? If yes, it will ask you if the object is
243
	# really an LVM2 PV. If no, it will assume the object is not a PV.
244
	#
245
	# If you have used EVMS to create an LVM2 container on top of an
246
	# MD Software-RAID region, you'll most likely want to set this
247
	# parameter to no.
248
	#
249
	# The default is yes.
250
251
	device_size_prompt = yes
252
}
253
(-)evms-2.5.4/engine/dm-targets.c (-8 / +39 lines)
Lines 800-827 static int mirror_build_params(dm_target Link Here
800
 * Fill in a mirror target structure based on an ASCII table string of the form:
800
 * Fill in a mirror target structure based on an ASCII table string of the form:
801
 *   <log_type> <num_log_params> [<log_params>]* <num_mirrors> [<major>:<minor> <start_lba>]{2,}
801
 *   <log_type> <num_log_params> [<log_params>]* <num_mirrors> [<major>:<minor> <start_lba>]{2,}
802
 *
802
 *
803
 * Currently, log_type will always be "core", num_log_params is 1, and
803
 * Currently, log_type will always be "core", num_log_params is 1 or 2, and
804
 * log_params is chunk-size (in sectors).
804
 * log_params is chunk-size (in sectors).
805
 **/
805
 **/
806
static int mirror_translate_params(dm_target_t *target)
806
static int mirror_translate_params(dm_target_t *target)
807
{
807
{
808
	dm_target_mirror_t *mirror = target->data.mirror;
808
	dm_target_mirror_t *mirror = target->data.mirror;
809
	char *params = target->params;
809
	char *params = target->params;
810
	int i, rc;
810
	int i, rc, num_opts;
811
811
812
	LOG_PROC_ENTRY();
812
	LOG_PROC_ENTRY();
813
813
814
	/* Skip "core 1" at the start of the string. */
814
	/* Skip "core" at the start of the string. */
815
	params = next_token(params);
816
	params = next_token(params);
815
	params = next_token(params);
817
816
818
	rc = sscanf(params, "%u %u", &mirror->chunk_size, &mirror->num_mirrors);
817
	/* get the number of options for core and the chunk size */
818
	rc = sscanf(params, "%u %u", &num_opts, &mirror->chunk_size);
819
	if (rc != 2) {
819
	if (rc != 2) {
820
		rc = EINVAL;
820
		rc = EINVAL;
821
		goto out;
821
		goto out;
822
	}
822
	}
823
824
	params = next_token(params);
823
	params = next_token(params);
824
825
	/* skip the options for core based on num_opts */
826
	for (i = 0; i < num_opts; i++) {
827
		params = next_token(params);
828
	}
829
830
	/* get the number of mirrors */
831
	rc = sscanf(params, "%u", &mirror->num_mirrors);
832
	if (rc != 1) {
833
		rc = EINVAL;
834
		goto out;
835
	}
825
	params = next_token(params);
836
	params = next_token(params);
826
837
827
	for (i = 0; i < mirror->num_mirrors; i++) {
838
	for (i = 0; i < mirror->num_mirrors; i++) {
Lines 855-867 out: Link Here
855
static int mirror_pretranslate_params(char *params, u_int32_t *num_devs,
866
static int mirror_pretranslate_params(char *params, u_int32_t *num_devs,
856
				      u_int32_t *num_groups)
867
				      u_int32_t *num_groups)
857
{
868
{
858
	int rc;
869
	int rc, i, num_opts = 0;
870
	char *num_devs_point;
859
871
860
	LOG_PROC_ENTRY();
872
	LOG_PROC_ENTRY();
861
873
862
	rc = sscanf(params, "%*s %*d %*u %u", num_devs);
874
	/* The mirror target can have more than 1 option
875
	this affects the location of the number of member disks */
876
877
	rc = sscanf(params, "%*s %u", &num_opts);
878
	if (rc != 1) {
879
		rc = EINVAL;
880
		goto out;
881
	}
882
883
	/* skip "core <num_opts>" */
884
	num_devs_point = next_token(params);
885
	num_devs_point = next_token(params);
886
887
	/* skip the options for core based on num_opts */
888
	for (i = 0; i < num_opts; i++) {
889
		num_devs_point = next_token(params);
890
	}
891
892
	rc = sscanf(num_devs_point, "%u", num_devs);
863
	rc = (rc != 1) ? EINVAL : 0;
893
	rc = (rc != 1) ? EINVAL : 0;
864
894
895
out:
865
	LOG_PROC_EXIT_INT(rc);
896
	LOG_PROC_EXIT_INT(rc);
866
	return rc;
897
	return rc;
867
}
898
}
(-)evms-2.5.4/plugins/disk/localdskmgr.c (-1 / +102 lines)
Lines 1329-1341 static int check_multipath(storage_objec Link Here
1329
	rc = EngFncs->dm_get_targets(disk, &targets);
1329
	rc = EngFncs->dm_get_targets(disk, &targets);
1330
	if (rc) {
1330
	if (rc) {
1331
		LOG_ERROR("Error getting DM mapping for disk %s.\n", disk->name);
1331
		LOG_ERROR("Error getting DM mapping for disk %s.\n", disk->name);
1332
		rc=0;
1332
		goto out;
1333
		goto out;
1333
	}
1334
	}
1334
1335
1335
	/* Reject all non-multipath devices. */
1336
	/* Reject all non-multipath devices. */
1336
	if (targets->type != DM_TARGET_MULTIPATH) {
1337
	if (targets->type != DM_TARGET_MULTIPATH) {
1337
		LOG_DEBUG("Disk %s is not a multipath device.\n", disk->name);
1338
		LOG_DEBUG("Disk %s is not a multipath device.\n", disk->name);
1338
		rc = EINVAL;
1339
		//rc = EINVAL;
1339
		goto out;
1340
		goto out;
1340
	}
1341
	}
1341
1342
Lines 1396-1401 static void remove_multipath_children(li Link Here
1396
}
1397
}
1397
1398
1398
/**
1399
/**
1400
 * check_user_devicemapper
1401
 *
1402
 * Check if this disk is a User created DM device.
1403
 **/
1404
static int check_user_devicemapper(storage_object_t * disk)
1405
{
1406
	dm_device_list_t * dm_list, * dm_entry;
1407
	dm_target_t * targets = NULL;
1408
	local_disk_t * ld = disk->private_data;
1409
	int rc = 0, dm_user_targets_count = 0, i, dmup_len;
1410
	boolean user_dm_enable;
1411
	const char * const * dm_user_targets;
1412
	char * dm_user_prefix = "dm/";
1413
1414
	LOG_ENTRY();
1415
1416
	/* Get the list of active DM devices. */
1417
	dm_list = get_dm_device_list();
1418
	if (!dm_list) {
1419
		LOG_WARNING("Cannot get list of DM devices.\n");
1420
		goto out;
1421
	}
1422
1423
	/* Search the DM list for an entry that matches this disk. */
1424
	dm_entry = find_disk_in_dm_devices(disk, dm_list);
1425
	if (!dm_entry) {
1426
		LOG_DEBUG("Disk %s is not a DM device.\n", disk->name);
1427
		goto out;
1428
	}
1429
1430
	user_dm_enable = FALSE;
1431
	EngFncs->get_config_bool("devmapper.dm_user", &user_dm_enable);
1432
1433
	EngFncs->get_config_string_array("devmapper.dm_user_targets",
1434
					 &dm_user_targets_count, &dm_user_targets);
1435
1436
	if (user_dm_enable == FALSE) {
1437
		LOG_DEBUG("devmapper.dm_user not enabled.\n");
1438
		rc = EINVAL;
1439
		goto out;
1440
	}
1441
1442
	/* search the named targets in the config for the DM name*/
1443
	user_dm_enable = FALSE;
1444
	for (i = 0; i < dm_user_targets_count; i++) {		
1445
		if (strncmp(dm_user_targets[i], dm_entry->name, EVMS_NAME_SIZE) == 0) {
1446
			user_dm_enable = TRUE;
1447
		}
1448
	}
1449
1450
	if (user_dm_enable == FALSE) {
1451
		LOG_DEBUG("%s not found in devmapper.dm_user_targets.\n", dm_entry->name);
1452
		rc = EINVAL;
1453
		goto out;
1454
	}
1455
1456
	/* Get the DM mapping for this disk. */
1457
	/* we can use this in the future if we need to, and it's good to check */
1458
	strncpy(disk->name, dm_entry->name, EVMS_NAME_SIZE);
1459
	rc = EngFncs->dm_get_targets(disk, &targets);
1460
	if (rc) {
1461
		LOG_ERROR("Error getting DM mapping for disk %s.\n", disk->name);
1462
		goto out;
1463
	}
1464
1465
	/* Copy the DM name to this disk. */
1466
	dmup_len = strlen(dm_user_prefix);
1467
	LOG_DEBUG("Changing disk name from %s to %s%s.\n",
1468
		  disk->name, dm_user_prefix ,dm_entry->name);
1469
1470
	strncpy(disk->name, dm_user_prefix, dmup_len);
1471
	strncpy((disk->name)+dmup_len, dm_entry->name, EVMS_NAME_SIZE-dmup_len);
1472
1473
	/* Reject all multipath devices that
1474
	 * were created by other EVMS plugins.
1475
	 */
1476
	rc = check_multipath_name(disk);
1477
	if (rc) {
1478
		LOG_DEBUG("Multipath disk %s belongs to another EVMS plugin.\n",
1479
			  disk->name);
1480
		goto out;
1481
	}
1482
1483
	ld->flags |= LD_FLAG_USERDM;
1484
1485
out:
1486
	/*EngFncs->dm_deallocate_targets(targets); */
1487
	LOG_EXIT_INT(rc);
1488
	return rc;
1489
}
1490
1491
/**
1399
 * get_geometry
1492
 * get_geometry
1400
 *
1493
 *
1401
 * Use the HDIO_GETGEO_BIG or HDIO_GETGEO ioctl to get the disk's geometry.
1494
 * Use the HDIO_GETGEO_BIG or HDIO_GETGEO ioctl to get the disk's geometry.
Lines 1478-1483 static int get_fake_geometry(storage_obj Link Here
1478
	if (disk->dev_major == LOOP_MAJOR ||
1571
	if (disk->dev_major == LOOP_MAJOR ||
1479
	    disk->dev_major == NBD_MAJOR ||
1572
	    disk->dev_major == NBD_MAJOR ||
1480
	    disk->dev_major == DRBD_MAJOR ||
1573
	    disk->dev_major == DRBD_MAJOR ||
1574
		ld->flags & LD_FLAG_USERDM ||
1481
	    ld->flags & LD_FLAG_MULTIPATH) {
1575
	    ld->flags & LD_FLAG_MULTIPATH) {
1482
		LOG_DEBUG("Creating fake geometry for disk %s.\n", disk->name);
1576
		LOG_DEBUG("Creating fake geometry for disk %s.\n", disk->name);
1483
		disk->geometry.heads = 255;
1577
		disk->geometry.heads = 255;
Lines 1745-1750 static int LD_discover(list_anchor_t inp Link Here
1745
		/* Get the disk's hard-sector-size. */
1839
		/* Get the disk's hard-sector-size. */
1746
		get_hardsector_size(&working_disk);
1840
		get_hardsector_size(&working_disk);
1747
1841
1842
		/* Check for User created DM devices. */
1843
		rc = check_user_devicemapper(&working_disk);
1844
		if (rc) {
1845
			close_dev(&working_disk);
1846
			continue;
1847
		}
1848
1748
		/* Get the disk's geometry. */
1849
		/* Get the disk's geometry. */
1749
		rc = get_geometry(&working_disk);
1850
		rc = get_geometry(&working_disk);
1750
		if (rc) {
1851
		if (rc) {
(-)evms-2.5.4/plugins/disk/localdskmgr.c.~1~ (+2398 lines)
Line 0 Link Here
1
/*
2
 *   (C) Copyright IBM Corp. 2001, 2003
3
 *
4
 *   This program is free software;  you can redistribute it and/or modify
5
 *   it under the terms of the GNU General Public License as published by
6
 *   the Free Software Foundation; either version 2 of the License, or
7
 *   (at your option) any later version.
8
 *
9
 *   This program is distributed in the hope that it will be useful,
10
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12
 *   the GNU General Public License for more details.
13
 *
14
 *   You should have received a copy of the GNU General Public License
15
 *   along with this program;  if not, write to the Free Software
16
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
 *
18
 * Local Disk Manager plugin.
19
 */
20
21
#define _GNU_SOURCE
22
23
#include <stdlib.h>
24
#include <stdio.h>
25
#include <string.h>
26
#include <fcntl.h>
27
#include <mntent.h>
28
#include <dirent.h>
29
#include <unistd.h>
30
#include <sys/ioctl.h>
31
#include <sys/stat.h>
32
#include <sys/types.h>
33
#include <errno.h>
34
#include <glob.h>
35
#include <malloc.h>
36
#include <wait.h>
37
38
#include <plugin.h>
39
#include <ldm_funcs.h>
40
#include "localdskmgr.h"
41
#include "cache.h"
42
#include "info.h"
43
44
engine_functions_t * EngFncs = NULL;
45
46
char * base_directory = NULL;
47
int    base_directory_len;
48
char * sysfs_mount_point;
49
const char * scan;
50
const char * const * directories;
51
int directories_count;
52
const char * const * includes;
53
int include_count;
54
const char * const default_legacy_includes[] = {
55
	"sd?",
56
	"hd?",
57
	"dasd?"
58
};
59
const char * const default_sysfs_includes[] = {
60
	"*?",
61
};
62
const char * const * excludes;
63
int exclude_count;
64
glob_t dev_names_glob;
65
int glob_flags;
66
static char pattern[PATH_MAX];
67
68
static dm_device_list_t * dm_devices = NULL;
69
static list_anchor_t multipath_children = NULL;
70
71
/* Global list for keeping track of open file-handles. On systems with
72
 * a large number of disks, we don't want to keep open file-handles to
73
 * every disk, or the process may run out of available file-handles.
74
 */
75
static list_anchor_t file_handles = NULL;
76
u_int32_t num_file_handles = 0;
77
#define DEFAULT_FILE_HANDLES 64
78
#define MAX_FILE_HANDLES 1024
79
80
static void close_dev(storage_object_t * disk);
81
82
/**
83
 * round_down
84
 * @value:	Value (in sectors) to be rounded down.
85
 * @boundary:	Boundary (in bytes) to round-down to.
86
 *
87
 * Given a value, round it down to be a multiple of the specified boundary size.
88
 **/
89
static inline sector_count_t round_down(sector_count_t value,
90
					u_int32_t boundary)
91
{
92
	sector_count_t boundary_in_vsectors = ((sector_count_t)boundary) >>
93
					      EVMS_VSECTOR_SIZE_SHIFT;
94
	return (boundary > EVMS_VSECTOR_SIZE) ?
95
	       (value & ~(boundary_in_vsectors - 1)) : value;
96
}
97
98
/**
99
 * round_up
100
 * @value:	Value (in sectors) to be rounded up.
101
 * @boundary:	Boundary (in bytes) to round-up to.
102
 *
103
 * Given a value, round it up to be a multiple of the specified boundary size.
104
 **/
105
static inline sector_count_t round_up(sector_count_t value,
106
				      u_int32_t boundary)
107
{
108
	sector_count_t boundary_in_vsectors = ((sector_count_t)boundary) >>
109
					      EVMS_VSECTOR_SIZE_SHIFT;
110
	sector_count_t temp_value = value + boundary_in_vsectors - 1;
111
	return (boundary > EVMS_VSECTOR_SIZE) ?
112
	       (temp_value & ~(boundary_in_vsectors - 1)) : value;
113
}
114
115
/**
116
 * drbd_active
117
 *
118
 * Is the drbd driver running? If so, the nbd driver cannot also be running,
119
 * since they use the same major-number.
120
 **/
121
static int drbd_active = -1;
122
123
static boolean is_drbd_active(void)
124
{
125
	struct stat st;
126
	int rc;
127
128
	LOG_ENTRY();
129
130
	if (drbd_active == -1) {
131
		rc = stat("/proc/drbd", &st);
132
		if (rc) {
133
			drbd_active = FALSE;
134
		} else {
135
			drbd_active = TRUE;
136
		}
137
	}
138
139
	LOG_EXIT_BOOL(drbd_active);
140
	return drbd_active;
141
}
142
143
static boolean search_mount_records(FILE * records,
144
				    char * fs_name,
145
				    char ** mount_name)
146
{
147
	boolean found = FALSE;
148
	struct mntent * mount_entry;
149
150
	LOG_ENTRY();
151
152
	while (!found && (mount_entry = getmntent(records)) != NULL) {
153
		if (strcmp(mount_entry->mnt_type, fs_name) == 0) {
154
			found = TRUE;
155
			if (mount_name) {
156
				*mount_name = strdup(mount_entry->mnt_dir);
157
			}
158
		}
159
	}
160
161
	LOG_EXIT_BOOL(found);
162
	return found;
163
}
164
165
/**
166
 * where_is_sysfs
167
 *
168
 * Is sysfs mounted. If so, return the mount point. The caller must free the
169
 * returned string.
170
 **/
171
static boolean where_is_sysfs(char ** mount_name)
172
{
173
	boolean found = FALSE;
174
	FILE * mount_records;
175
176
	LOG_ENTRY();
177
178
	if (mount_name) {
179
		*mount_name = NULL;
180
	}
181
182
	mount_records = setmntent(MOUNTED, "r");
183
	if (mount_records) {
184
		LOG_DEBUG("Searching for sysfs in %s.\n", MOUNTED);
185
		found = search_mount_records(mount_records, "sysfs", mount_name);
186
		endmntent(mount_records);
187
	}
188
189
	if (!found) {
190
		mount_records = setmntent("/proc/mounts", "r");
191
		if (mount_records) {
192
			LOG_DEBUG("Searching for sysfs in /proc/mounts.\n");
193
			found = search_mount_records(mount_records, "sysfs", mount_name);
194
			endmntent(mount_records);
195
		}
196
	}
197
198
	LOG_EXIT_BOOL(found);
199
	return found;
200
}
201
202
static void get_legacy_config()
203
{
204
	LOG_ENTRY();
205
206
	scan = "/dev/";
207
	EngFncs->get_config_string("legacy_devices.scan", &scan);
208
209
	directories_count = 0;
210
	directories = NULL;
211
	EngFncs->get_config_string_array("legacy_devices.directories",
212
					 &directories_count, &directories);
213
	include_count = 0;
214
	includes = NULL;
215
	EngFncs->get_config_string_array("legacy_devices.include",
216
					 &include_count, &includes);
217
	if (includes == NULL) {
218
		includes = default_legacy_includes;
219
		include_count = sizeof(default_legacy_includes) /
220
				sizeof(default_legacy_includes[0]);
221
	}
222
223
	exclude_count = 0;
224
	excludes = NULL;
225
	EngFncs->get_config_string_array("legacy_devices.exclude",
226
					 &exclude_count, &excludes);
227
228
	EngFncs->get_config_uint32("legacy_devices.max_open_disks",
229
				   &num_file_handles);
230
231
	LOG_EXIT_VOID();
232
}
233
234
static void get_sysfs_config()
235
{
236
	boolean ignore_sysfs = FALSE;
237
238
	LOG_ENTRY();
239
240
	EngFncs->get_config_bool("sysfs_devices.ignore_sysfs", &ignore_sysfs);
241
	if (ignore_sysfs) {
242
		/* Fall back to the legacy_devices section
243
		 * if the config file says to ignore sysfs.
244
		 */
245
		free(sysfs_mount_point);
246
		sysfs_mount_point = NULL;
247
		get_legacy_config();
248
		LOG_EXIT_VOID();
249
		return;
250
	}
251
252
	include_count = 0;
253
	includes = NULL;
254
	EngFncs->get_config_string_array("sysfs_devices.include",
255
					 &include_count, &includes);
256
	if (includes == NULL) {
257
		includes = default_sysfs_includes;
258
		include_count = sizeof(default_sysfs_includes) /
259
				sizeof(default_sysfs_includes[0]);
260
	}
261
262
	exclude_count = 0;
263
	excludes = NULL;
264
	EngFncs->get_config_string_array("sysfs_devices.exclude",
265
					 &exclude_count, &excludes);
266
267
	EngFncs->get_config_uint32("sysfs_devices.max_open_disks",
268
				   &num_file_handles);
269
270
	LOG_EXIT_VOID();
271
}
272
273
/**
274
 * file_handle_cleanup
275
 *
276
 * Delete the list of file-handle tracking structures.
277
 **/
278
static void file_handle_cleanup(void)
279
{
280
	file_handle_t *handle;
281
	list_element_t iter;
282
283
	LOG_ENTRY();
284
285
	LIST_FOR_EACH(file_handles, iter, handle) {
286
		EngFncs->engine_free(handle);
287
	}
288
289
	EngFncs->destroy_list(file_handles);
290
	file_handles = NULL;
291
292
	LOG_EXIT_VOID();
293
}
294
295
/**
296
 * file_handle_setup
297
 *
298
 * Create and initialize MAX_FILE_HANDLES entries on the file_handles list.
299
 **/
300
static int file_handle_setup(void)
301
{
302
	file_handle_t *handle;
303
	u_int32_t i;
304
	int rc = 0;
305
306
	LOG_ENTRY();
307
308
	/* Make sure the number of entries in the
309
	 * file-handles list will be reasonable.
310
	 */
311
	if (num_file_handles == 0) {
312
		num_file_handles = DEFAULT_FILE_HANDLES;
313
	} else if (num_file_handles > MAX_FILE_HANDLES) {
314
		num_file_handles = MAX_FILE_HANDLES;
315
	}
316
317
	LOG_DEBUG("Allocating %u entries in the file-handles list.\n",
318
		  num_file_handles);
319
320
	file_handles = EngFncs->allocate_list();
321
	if (!file_handles) {
322
		rc = ENOMEM;
323
		goto out;
324
	}
325
326
	for (i = 0; i < num_file_handles; i++) {
327
		handle = EngFncs->engine_alloc(sizeof(*handle));
328
		if (!handle) {
329
			file_handle_cleanup();
330
			rc = ENOMEM;
331
			break;
332
		}
333
		handle->elem = EngFncs->insert_thing(file_handles, handle,
334
						     INSERT_AFTER, NULL);
335
	}
336
337
out:
338
	LOG_EXIT_INT(rc);
339
	return rc;
340
}
341
342
/**
343
 * file_handle_release
344
 *
345
 * Release this file-handle back to the pool of available handles. Move it
346
 * to the start of the list so it will be quicker to find on the next search.
347
 **/
348
static void file_handle_release(file_handle_t *handle)
349
{
350
	LOG_ENTRY();
351
352
	handle->disk = NULL;
353
	EngFncs->remove_element(handle->elem);
354
	EngFncs->insert_element(file_handles, handle->elem, INSERT_BEFORE, NULL);
355
356
	LOG_EXIT_VOID();
357
}
358
359
/**
360
 * file_handle_make_last
361
 *
362
 * Move this file-handle to the end of the list so it will be the least likely
363
 * to be "stolen".
364
 **/
365
static void file_handle_make_last(file_handle_t *handle)
366
{
367
	LOG_ENTRY();
368
369
	EngFncs->remove_element(handle->elem);
370
	EngFncs->insert_element(file_handles, handle->elem, INSERT_AFTER, NULL);
371
372
	LOG_EXIT_VOID();
373
}
374
375
/**
376
 * file_handle_find_free
377
 *
378
 * Search the file-handles list for an unused entry and assign it to this disk.
379
 **/
380
static file_handle_t *file_handle_find_free(void)
381
{
382
	file_handle_t *handle;
383
	list_element_t iter;
384
385
	LOG_ENTRY();
386
387
	LIST_FOR_EACH(file_handles, iter, handle) {
388
		if (!handle->disk) {
389
			break;
390
		}
391
	}
392
393
	LOG_EXIT_PTR(handle);
394
	return handle;
395
}
396
397
/**
398
 * file_handle_steal_first
399
 *
400
 * "Steal" the first file-handle on the list, forceably close the disk that
401
 * currently owns it, and assign it to the new disk.
402
 **/
403
static file_handle_t *file_handle_steal_first(void)
404
{
405
	file_handle_t *handle;
406
407
	LOG_ENTRY();
408
409
	handle = EngFncs->first_thing(file_handles, NULL);
410
	if (handle->disk) {
411
		LOG_DEBUG("Stealing file-handle from disk %s.\n",
412
			  handle->disk->name);
413
		close_dev(handle->disk);
414
	}
415
416
	LOG_EXIT_PTR(handle);
417
	return handle;
418
}
419
420
/**
421
 * file_handle_get
422
 *
423
 * Get a file-handle for this disk. First search the list for an used one. If
424
 * we can't find one, simply "steal" the first one on the list.
425
 **/
426
static file_handle_t *file_handle_get(void)
427
{
428
	file_handle_t *handle;
429
430
	LOG_ENTRY();
431
432
	handle = file_handle_find_free();
433
	if (!handle) {
434
		handle = file_handle_steal_first();
435
	}
436
437
	LOG_EXIT_PTR(handle);
438
	return handle;
439
}
440
441
static int LD_setup(engine_functions_t * engine_function_table)
442
{
443
	int rc;
444
445
	/* save info we get from the engine */
446
	EngFncs = engine_function_table;
447
448
	LOG_ENTRY();
449
450
	if (where_is_sysfs(&sysfs_mount_point)) {
451
		get_sysfs_config();
452
	} else {
453
		get_legacy_config();
454
	}
455
456
	rc = file_handle_setup();
457
458
	LOG_EXIT_INT(rc);
459
	return rc;
460
}
461
462
/**
463
 * open_dev
464
 *
465
 * Open the specified disk. Use O_DIRECT to avoid caching. Use O_SYNC in case
466
 * the kernel does not honor O_DIRECT. Use the Engine's service so we
467
 * automatically get a dev-node in the /dev/evms/.nodes/ tree. Record the
468
 * file handle in the disk's private data.
469
 **/
470
static int open_dev(storage_object_t * disk)
471
{
472
	local_disk_t * ld = disk->private_data;
473
	int rc = 0;
474
475
	LOG_ENTRY();
476
477
	if (ld->fd <= 0) {
478
		ld->file_handle = file_handle_get();
479
		ld->file_handle->disk = disk;
480
481
		ld->fd = EngFncs->open_object(disk, O_RDWR | O_DIRECT | O_SYNC);
482
		if (ld->fd < 0) {
483
			rc = - ld->fd;
484
			file_handle_release(ld->file_handle);
485
			ld->file_handle = NULL;
486
			LOG_DEBUG("Error opening disk %s: %d: %s\n",
487
				  disk->name, rc, strerror(rc));
488
		}
489
	}
490
491
	if (!rc) {
492
		file_handle_make_last(ld->file_handle);
493
	}
494
495
	LOG_EXIT_INT(rc);
496
	return rc;
497
}
498
499
/**
500
 * close_dev
501
 *
502
 * Close the disk and clear the file handle.
503
 **/
504
static void close_dev(storage_object_t * disk)
505
{
506
	local_disk_t * ld = disk->private_data;
507
	int rc;
508
509
	LOG_ENTRY();
510
511
	if (ld->fd >= 0) {
512
		rc = EngFncs->close_object(disk, ld->fd);
513
		file_handle_release(ld->file_handle);
514
		ld->file_handle = NULL;
515
		ld->fd = -1;
516
	}
517
518
	LOG_EXIT_VOID();
519
}
520
521
/**
522
 * LD_cleanup
523
 *
524
 * Find any disks and close the device that was opended during discovery.
525
 **/
526
static void LD_cleanup(void)
527
{
528
	storage_object_t * disk;
529
	list_anchor_t disk_list;
530
	list_element_t disk_list_itr;
531
	int rc;
532
533
	LOG_ENTRY();
534
535
	/* Get a list of disks that are managed by this plug-in. */
536
	rc = EngFncs->get_object_list(DISK, 0, my_plugin_record,
537
				      NULL, 0, &disk_list);
538
	if (!rc) {
539
		/* Close any dev handles that might be open. */
540
		LIST_FOR_EACH(disk_list, disk_list_itr, disk) {
541
			close_dev(disk);
542
			EngFncs->engine_free(disk->private_data);
543
		}
544
		EngFncs->destroy_list(disk_list);
545
	}
546
547
	destroy_cache();
548
	file_handle_cleanup();
549
550
	if (base_directory) {
551
		free(base_directory);
552
		base_directory = NULL;
553
	}
554
	if (sysfs_mount_point) {
555
		free(sysfs_mount_point);
556
		sysfs_mount_point = NULL;
557
	}
558
559
	LOG_EXIT_VOID();
560
}
561
562
static void filter_out_excludes(char * pattern, int path_len, int new_globs_index)
563
{
564
	int rc;
565
	int i;
566
	glob_t exclude_glob = {0};
567
568
	LOG_ENTRY();
569
570
	for (i = 0; i < exclude_count; i++) {
571
			
572
		strcpy(pattern + path_len, excludes[i]);
573
574
		rc = glob(pattern, glob_flags, NULL, &exclude_glob);
575
576
		if (rc == 0) {
577
			glob_flags |= GLOB_APPEND;
578
579
		} else {
580
			if (rc != GLOB_NOMATCH) {
581
				LOG_WARNING("glob() of pattern %s failed with error %s\n", pattern,
582
					    (rc == GLOB_NOSPACE) ? "GLOB_NOSPACE" :
583
					    (rc == GLOB_ABEND) ? "GLOB_ABEND" :
584
					    "(unknown)");
585
			}
586
		}
587
	}
588
589
	for (i = 0; i < exclude_glob.gl_pathc; i++) {
590
		int j;
591
592
		for (j = new_globs_index; j < dev_names_glob.gl_pathc; j++) {
593
			if (strcmp(exclude_glob.gl_pathv[i], dev_names_glob.gl_pathv[j]) == 0) {
594
				int k;
595
596
				LOG_DEBUG("Removing %s.\n", dev_names_glob.gl_pathv[j]);
597
				free(dev_names_glob.gl_pathv[j]);
598
599
				/* Scoot up all following entries. */
600
				for (k = j+1; k < dev_names_glob.gl_pathc; k++) {
601
					dev_names_glob.gl_pathv[k-1] = dev_names_glob.gl_pathv[k];
602
				}
603
				dev_names_glob.gl_pathc--;
604
605
				break;
606
			}
607
		}
608
	}
609
610
	if (exclude_glob.gl_pathc >= 0) {
611
		globfree(&exclude_glob);
612
	}
613
614
	LOG_EXIT_VOID();
615
}
616
617
static void filter_out_non_block_devices(int new_globs_index)
618
{
619
	int i;
620
	struct stat statbuf;
621
	int status;
622
623
	LOG_ENTRY();
624
625
	i = new_globs_index;
626
	while (i < dev_names_glob.gl_pathc) {
627
			
628
		status = stat(dev_names_glob.gl_pathv[i], &statbuf);
629
630
		if (status == 0) {
631
			if (!S_ISBLK(statbuf.st_mode)) {
632
				int j;
633
634
				LOG_DEBUG("Removing %s.\n", dev_names_glob.gl_pathv[i]);
635
				free(dev_names_glob.gl_pathv[i]);
636
637
				/* Scoot up all following entries. */
638
				for (j = i+1; j < dev_names_glob.gl_pathc; j++) {
639
					dev_names_glob.gl_pathv[j-1] = dev_names_glob.gl_pathv[j];
640
				}
641
				dev_names_glob.gl_pathc--;
642
				dev_names_glob.gl_pathv[dev_names_glob.gl_pathc] = NULL;
643
644
				/* Leave "i" as it is so we check the new
645
				 * entry at the current index.
646
				 */
647
				continue;
648
			}
649
650
		} else {
651
			LOG_WARNING("stat(%s) failed with error code %d: %s\n", dev_names_glob.gl_pathv[i], errno, strerror(errno));
652
		}
653
654
		i++;
655
	}
656
657
	LOG_EXIT_VOID();
658
}
659
660
static void get_dev_names(const char * dir)
661
{
662
	int rc;
663
	int i;
664
	int path_len;
665
	int new_globs_index;
666
667
	LOG_ENTRY();
668
	LOG_DEBUG("Get device names in directory %s\n", dir);
669
670
	strcpy(pattern, dir);
671
	path_len = strlen(pattern);
672
	if (pattern[path_len-1] != '/') {
673
		pattern[path_len] = '/';
674
		pattern[path_len+1] = '\0';
675
		path_len++;
676
	}
677
678
	new_globs_index = dev_names_glob.gl_pathc;
679
680
	for (i = 0; i < include_count; i++) {
681
			
682
		strcpy(pattern + path_len, includes[i]);
683
684
		rc = glob(pattern, glob_flags, NULL, &dev_names_glob);
685
686
		if (rc == 0) {
687
			glob_flags |= GLOB_APPEND;
688
689
		} else {
690
			if (rc != GLOB_NOMATCH) {
691
				LOG_WARNING("glob() of pattern %s failed with error %s\n", pattern,
692
					    (rc == GLOB_NOSPACE) ? "GLOB_NOSPACE" :
693
					    (rc == GLOB_ABEND) ? "GLOB_ABEND" :
694
					    "(unknown)");
695
			}
696
		}
697
	}
698
699
	filter_out_excludes(pattern, path_len, new_globs_index);
700
701
	if (sysfs_mount_point == NULL) {
702
		filter_out_non_block_devices(new_globs_index);
703
	}
704
705
	LOG_EXIT_VOID();
706
}
707
708
static char dir_pattern[PATH_MAX];
709
710
static void process_dir(char * name)
711
{
712
	int i;
713
	glob_t dirs_glob;
714
715
	LOG_ENTRY();
716
717
	/* Process entries in this directory. */
718
	get_dev_names(name);
719
720
	/* Get a list of this directory's subdirectories. */
721
	strcpy(dir_pattern, name);
722
	strcat(dir_pattern, "*/");
723
724
	if (glob(dir_pattern, 0, NULL, &dirs_glob) == 0) {
725
726
		/* Process the subdirectories. */
727
		for (i = 0; i < dirs_glob.gl_pathc; i++) {
728
			int status;
729
			struct stat statbuf;
730
731
			status = stat(dirs_glob.gl_pathv[i], &statbuf);
732
			if (status == 0) {
733
				if (S_ISDIR(statbuf.st_mode)) {
734
					process_dir(dirs_glob.gl_pathv[i]);
735
				}
736
			}
737
		}
738
739
		globfree(&dirs_glob);
740
	}
741
742
	LOG_EXIT_VOID();
743
}
744
745
static char dir_path[PATH_MAX];
746
747
static void get_legacy_devs()
748
{
749
	int base_len, i;
750
	char * pch;
751
752
	LOG_ENTRY();
753
754
	memset(&dev_names_glob, 0, sizeof(dev_names_glob));
755
	glob_flags = 0;
756
757
	/* Make sure the user-specified directory ends with a '/'. */
758
	base_len = strlen(scan);
759
	if (scan[base_len-1] != '/') {
760
		pch = malloc(base_len + 2);
761
		if (pch) {
762
			strcpy(pch, scan);
763
			strcpy(pch + base_len, "/");
764
			scan = pch;
765
			base_len += 2;
766
		}
767
	}
768
769
	base_directory = strdup(scan);
770
	base_directory_len = strlen(base_directory);
771
772
	/* Always find devices in the base directory. */
773
	get_dev_names(base_directory);
774
775
	/* Recursively search any subdirectories the user specified. */
776
	strcpy(dir_path, base_directory);
777
	for (i = 0; i < directories_count; i++) {
778
		int len;
779
780
		strcpy(dir_path + base_directory_len, directories[i]);
781
782
		len = strlen(dir_path);
783
		if (dir_path[len-1] != '/') {
784
			strcpy(dir_path + len, "/");
785
		}
786
787
		process_dir(dir_path);
788
	}
789
790
	LOG_EXIT_VOID();
791
}
792
793
static void get_sysfs_devs()
794
{
795
	LOG_ENTRY();
796
797
	memset(&dev_names_glob, 0, sizeof(dev_names_glob));
798
	glob_flags = 0;
799
800
	strcpy(dir_path, sysfs_mount_point);
801
	strcat(dir_path, "/block/");
802
803
	base_directory = strdup(dir_path);
804
	base_directory_len = strlen(base_directory);
805
806
	LOG_DEBUG("Scanning %s\n", dir_path);
807
	get_dev_names(dir_path);
808
809
	LOG_EXIT_VOID();
810
}
811
812
/**
813
 * get_sysfs_size
814
 * @full_name:	Full path-name to the disk device-node.
815
 * @p_size:	Return pointer to the disk's size (in sectors).
816
 *
817
 * Use sysfs to get the size (in sectors) of the specified disk.
818
 **/
819
static int get_sysfs_size(char * full_name, u_int64_t * p_size)
820
{
821
	int rc = 0;
822
	int fd;
823
	char * size_file = malloc(strlen(full_name) + 6);
824
	char size_str[24];
825
826
	LOG_ENTRY();
827
828
	if (size_file != NULL) {
829
		strcpy(size_file, full_name);
830
		strcat(size_file, "/size");
831
		fd = open(size_file, O_RDONLY);
832
		if (fd > 0) {
833
			int bytes_read;
834
835
			bytes_read = read(fd, size_str, 24);
836
837
			if (bytes_read > 0) {
838
				/* Size is already in sectors. */
839
				*p_size = strtoull(size_str, NULL, 10);
840
841
			} else {
842
				if (bytes_read == 0) {
843
					LOG_ERROR("No bytes read from %s.\n", size_file);
844
				}
845
846
				rc = errno;
847
				LOG_ERROR("read() returned error %d: %s\n", rc, strerror(rc));
848
			}
849
850
			close(fd);
851
852
		} else {
853
			rc = errno;
854
			LOG_ERROR("open(%s) returned error %d: %s\n", size_file, rc, strerror(rc));
855
		}
856
857
		free(size_file);
858
	}
859
860
	LOG_EXIT_INT(rc);
861
	return rc;
862
}
863
864
/**
865
 * get_legacy_size
866
 * @full_name:	Full path-name to the disk device-node.
867
 * @p_size:	Return pointer to the disk's size (in sectors).
868
 *
869
 * Use the BLKGETSIZE64 ioctl to get the size (in sectors) of the
870
 * specified disk.
871
 **/
872
static int get_legacy_size(char * full_name, u_int64_t * p_size)
873
{
874
	int rc = 0;
875
	int fd;
876
877
	LOG_ENTRY();
878
879
	fd = open(full_name, O_RDONLY);
880
881
	if (fd > 0) {
882
883
		/* Ioctl to get size. (returns bytes) */
884
		rc = ioctl(fd, BLKGETSIZE64, p_size);
885
		if (rc == 0) {
886
			*p_size >>= EVMS_VSECTOR_SIZE_SHIFT;
887
			*p_size &= ~1;
888
		} else {
889
			rc = errno;
890
			LOG_DETAILS("ioctl to get the size returned error code "
891
				    "%d: %s.\n", rc, strerror(rc));
892
		}
893
894
		close(fd);
895
896
	} else {
897
		rc = errno;
898
		LOG_DETAILS("open(%s) returned error %d: %s\n",
899
			    full_name, rc, strerror(rc));
900
	}
901
902
	LOG_EXIT_INT(rc);
903
	return rc;
904
}
905
906
/**
907
 * get_disk_size
908
 * @full_name:	Full path-name to the device node.
909
 * @disk:	Pointer to the disk object.
910
 *
911
 * Get the size of the disk, and check that it is non-zero.
912
 **/
913
static int get_disk_size(char * full_name, storage_object_t * disk)
914
{
915
	int rc;
916
	LOG_ENTRY();
917
918
	if (sysfs_mount_point) {
919
		rc = get_sysfs_size(full_name, &disk->size);
920
	} else {
921
		rc = get_legacy_size(full_name, &disk->size);
922
	}
923
924
	if (disk->size == 0) {
925
		LOG_DEBUG("Disk %s has zero-size. Not a valid disk.\n",
926
			  disk->name);
927
		rc = EINVAL;
928
	} else if (disk->dev_major == NBD_MAJOR &&
929
		   ! is_drbd_active()) {
930
931
		/* YUCK!!! Uninitialized NBD devices report a size anyway.
932
		 * DRBD (which shares the same major) behaves correctly.
933
		 */
934
		if (EngFncs->is_2_4_kernel()) {
935
			if (disk->size == NBD_DEF_SIZE_2_4) {
936
				LOG_DEBUG("Disk %s appears to be an uninitialized NBD "
937
					  "device.\n", disk->name);
938
				rc = EINVAL;
939
			}
940
941
		} else {
942
			if (disk->size == NBD_DEF_SIZE_2_6) {
943
				LOG_DEBUG("Disk %s appears to be an uninitialized NBD "
944
					  "device.\n", disk->name);
945
				rc = EINVAL;
946
			}
947
		}
948
	}
949
950
	LOG_EXIT_INT(rc);
951
	return rc;
952
}
953
954
/**
955
 * get_sysfs_major_minor
956
 * @full_name:	Full path-name to the disk device-node.
957
 * @p_major:	Return pointer to the disk's major-number.
958
 * @p_minor:	Return pointer to the disk's minor-number.
959
 *
960
 * Use sysfs to get the device-number for the specified disk.
961
 **/
962
static int get_sysfs_major_minor(char * full_name,
963
				 u_int32_t * p_major,
964
				 u_int32_t * p_minor)
965
{
966
	int rc = 0;
967
	int fd;
968
	char * dev_file = malloc(strlen(full_name) + 5);
969
	char dev_str[16];
970
	dev_t dev;
971
972
	LOG_ENTRY();
973
974
	if (dev_file != NULL) {
975
		strcpy(dev_file, full_name);
976
		strcat(dev_file, "/dev");
977
		fd = open(dev_file, O_RDONLY);
978
		if (fd > 0) {
979
			int bytes_read;
980
981
			bytes_read = read(fd, dev_str, 16);
982
983
			if (bytes_read > 0) {
984
				rc = sscanf(dev_str, "%u:%u", p_major, p_minor);
985
				if (rc != 2) {
986
					dev = strtoul(dev_str, NULL, 16);
987
					*p_major = major(dev);
988
					*p_minor = minor(dev);
989
				}
990
				rc = 0;
991
			} else {
992
				if (bytes_read == 0) {
993
					LOG_ERROR("No bytes read from %s.\n", dev_file);
994
				}
995
996
				rc = errno;
997
				LOG_ERROR("read() returned error %d: %s\n", rc, strerror(rc));
998
			}
999
1000
			close(fd);
1001
1002
		} else {
1003
			rc = errno;
1004
			LOG_ERROR("open(%s) returned error %d: %s\n", dev_file, rc, strerror(rc));
1005
		}
1006
	}
1007
1008
	LOG_EXIT_INT(rc);
1009
	return rc;
1010
}
1011
1012
/**
1013
 * get_legacy_major_minor
1014
 * @full_name:	Full path-name to the disk device-node.
1015
 * @p_major:	Return pointer to the disk's major-number.
1016
 * @p_minor:	Return pointer to the disk's minor-number.
1017
 *
1018
 * Use stat to get the device-number for the specified disk.
1019
 **/
1020
static int get_legacy_major_minor(char * full_name,
1021
				  u_int32_t * p_major,
1022
				  u_int32_t * p_minor)
1023
{
1024
	int rc = 0;
1025
	struct stat statbuf;
1026
1027
	LOG_ENTRY();
1028
1029
	rc = stat(full_name, &statbuf);
1030
	if (rc == 0) {
1031
		*p_major = major(statbuf.st_rdev);
1032
		*p_minor = minor(statbuf.st_rdev);
1033
1034
	} else {
1035
		rc = errno;
1036
		LOG_ERROR("stat(%s) returned error code %d: %s\n",
1037
			  full_name, rc, strerror(rc));
1038
	}
1039
1040
	LOG_EXIT_INT(rc);
1041
	return rc;
1042
}
1043
1044
/**
1045
 * check_for_duplicate_dev
1046
 *
1047
 * Search the current output list for the device-number of the specified disk.
1048
 * Each device-number should only be discovered once.
1049
 **/
1050
static int check_for_duplicate_dev(storage_object_t * new_disk,
1051
				   list_anchor_t output_list)
1052
{
1053
	storage_object_t * disk;
1054
	list_element_t itr;
1055
1056
	LOG_ENTRY();
1057
1058
	LIST_FOR_EACH(output_list, itr, disk) {
1059
		if (disk->dev_major == new_disk->dev_major &&
1060
		    disk->dev_minor == new_disk->dev_minor) {
1061
			LOG_WARNING("Current disk %s has device-number %x:%x, which"
1062
				    "is a duplicate of disk %s. Ignoring %s.\n",
1063
				    new_disk->name, new_disk->dev_major,
1064
				    new_disk->dev_minor, disk->name, new_disk->name);
1065
			LOG_EXIT_INT(EINVAL);
1066
			return EINVAL;
1067
		}
1068
	}
1069
1070
	LOG_EXIT_INT(0);
1071
	return 0;
1072
}
1073
1074
/**
1075
 * get_disk_devnum
1076
 * @full_name:	Full path-name to the disk device-node.
1077
 * @disk:	Pointer to the disk object.
1078
 * @output_list:Current list of discovered disks.
1079
 *
1080
 * Get the device-number for the specified disk. Check that the device-number
1081
 * is allowed, and that it isn't a duplicate of an already-discovered disk.
1082
 **/
1083
static int get_disk_devnum(char * full_name,
1084
			   storage_object_t * disk,
1085
			   list_anchor_t output_list)
1086
{
1087
	int rc;
1088
	LOG_ENTRY();
1089
1090
	if (sysfs_mount_point) {
1091
		rc = get_sysfs_major_minor(full_name, &disk->dev_major,
1092
					   &disk->dev_minor);
1093
	} else {
1094
		rc = get_legacy_major_minor(full_name, &disk->dev_major,
1095
					    &disk->dev_minor);
1096
	}
1097
	if (rc) {
1098
		goto out;
1099
	}
1100
1101
	/* Exclude floppy, md, and lvm1 devices. */
1102
	if (disk->dev_major == FLOPPY_MAJOR ||
1103
	    disk->dev_major == MD_MAJOR ||
1104
	    disk->dev_major == LVM_MAJOR) {
1105
		LOG_DEBUG("Disk %s has a disallowed major number: %d.\n",
1106
			  disk->name, disk->dev_major);
1107
		rc = EINVAL;
1108
		goto out;
1109
	}
1110
1111
	/* Only discover a given device-number once. */
1112
	rc = check_for_duplicate_dev(disk, output_list);
1113
1114
out:
1115
	LOG_EXIT_INT(rc);
1116
	return rc;
1117
}
1118
1119
/**
1120
 * get_dm_device_list
1121
 *
1122
 * Get the list of current DM devices (if we haven't gotten it previously).
1123
 **/
1124
static dm_device_list_t * get_dm_device_list(void)
1125
{
1126
	int rc;
1127
1128
	LOG_ENTRY();
1129
1130
	if (!dm_devices) {
1131
		rc = EngFncs->dm_get_devices(&dm_devices);
1132
		if (rc) {
1133
			LOG_ERROR("Error calling dm_get_devices.\n");
1134
		}
1135
	}
1136
1137
	LOG_EXIT_PTR(dm_devices);
1138
	return dm_devices;
1139
}
1140
1141
/**
1142
 * find_disk_in_dm_devices
1143
 *
1144
 * Search the DM devices list for an entry with the same major:minor
1145
 * as this disk.
1146
 **/
1147
static dm_device_list_t * find_disk_in_dm_devices(storage_object_t * disk,
1148
						  dm_device_list_t * dm_list)
1149
{
1150
	dm_device_list_t * dm_entry;
1151
1152
	LOG_ENTRY();
1153
1154
	for (dm_entry = dm_list; dm_entry; dm_entry = dm_entry->next) {
1155
		if (dm_entry->dev_major == disk->dev_major &&
1156
		    dm_entry->dev_minor == disk->dev_minor) {
1157
			goto out;
1158
		}
1159
	}
1160
1161
out:
1162
	LOG_EXIT_PTR(dm_entry);
1163
	return dm_entry;
1164
}
1165
1166
/**
1167
 * check_multipath_name
1168
 *
1169
 * Other EVMS plugins can create multipath devices. We *don't* want to
1170
 * recognize those devices as disks. So check the name that we got from
1171
 * DM to see if it uses the naming format of the EVMS multipath plugins.
1172
 **/
1173
static int check_multipath_name(storage_object_t *disk)
1174
{
1175
	int rc;
1176
1177
	LOG_ENTRY();
1178
1179
	/* Multipath-segment-manager devices start with "mp/". */
1180
	rc = strncmp(disk->name, "mp/", 3);
1181
	if (rc) {
1182
		/* MD-multipath devices start with "md/". */
1183
		rc = strncmp(disk->name, "md/", 3);
1184
	}
1185
1186
	rc = rc ? 0 : EINVAL;
1187
1188
	LOG_EXIT_INT(rc);
1189
	return rc;
1190
}
1191
1192
/**
1193
 * update_multipath_child_list
1194
 *
1195
 * Search the multipath target info for all the child devices. Add these
1196
 * devices to the global list so we can filter these out at the end of
1197
 * discovery. That way we won't discover both the multipath devices and
1198
 * their component disks, which would lead to duplicate discoveries in the
1199
 * higher levels.
1200
 *
1201
 * Use a temporary list to build up the list of children for this multipath.
1202
 * Then append this list to the global one once we've collected all the
1203
 * children. This will prevent hitting an error part way through processing
1204
 * the list of child devices, which could leave the global list in an
1205
 * inconsistent state.
1206
 **/
1207
static int update_multipath_child_list(dm_target_t * targets)
1208
{
1209
	dm_target_multipath_t * mp = targets->data.multipath;
1210
	dm_priority_group_t * pg;
1211
	dm_path_t * path;
1212
	dm_device_t * device;
1213
	list_anchor_t children = NULL;
1214
	list_element_t itr1, itr2;
1215
	int i, j, rc = 0;
1216
1217
	LOG_ENTRY();
1218
1219
	/* Allocate the global child list if it doesn't exist yet. */
1220
	if (!multipath_children) {
1221
		multipath_children = EngFncs->allocate_list();
1222
		if (!multipath_children) {
1223
			LOG_ERROR("Error allocating multipath_children list.\n");
1224
			rc = ENOMEM;
1225
			goto out;
1226
		}
1227
	}
1228
1229
	/* Allocate a temporary list. */
1230
	children = EngFncs->allocate_list();
1231
	if (!children) {
1232
		LOG_ERROR("Error allocating temporary child list.\n");
1233
		rc = ENOMEM;
1234
		goto out;
1235
	}
1236
1237
	/* For each priority group in the multipath. */
1238
	for (i = 0; i < mp->num_groups; i++) {
1239
		pg = mp->group + i;
1240
		/* For each path in the priority group. */
1241
		for (j = 0; j < pg->num_paths; j++) {
1242
			path = pg->path + j;
1243
			device = EngFncs->engine_alloc(sizeof(*device));
1244
			if (!device) {
1245
				LOG_ERROR("Error allocating device structure "
1246
					  "for path %d:%d.\n",
1247
					  path->device.major, path->device.minor);
1248
				rc = ENOMEM;
1249
				goto out;
1250
			}
1251
			device->major = path->device.major;
1252
			device->minor = path->device.minor;
1253
1254
			/* Add this path's device to the temporary list. */
1255
			itr1 = EngFncs->insert_thing(children, device,
1256
						     INSERT_AFTER, NULL);
1257
			if (!itr1) {
1258
				LOG_ERROR("Error adding device %d:%d to the "
1259
					  "temporary child list.\n",
1260
					  device->major, device->minor);
1261
				rc = ENOMEM;
1262
				goto out;
1263
			}
1264
		}
1265
	}
1266
1267
out:
1268
	if (!rc) {
1269
		/* Success. Append the temporary list to the global list. */
1270
		rc = EngFncs->merge_lists(multipath_children, children, NULL, NULL);
1271
		if (rc) {
1272
			LOG_ERROR("Error merging temporary list with "
1273
				  "multipath_children list.\n");
1274
		}
1275
	}
1276
	if (rc) {
1277
		/* Some error occurred. Delete the temporary
1278
		 * list and all of it's devices.
1279
		 */
1280
		if (children) {
1281
			LIST_FOR_EACH_SAFE(children, itr1, itr2, device) {
1282
				EngFncs->delete_element(itr1);
1283
				EngFncs->engine_free(device);
1284
			}
1285
		}
1286
	}
1287
	if (children) {
1288
		EngFncs->destroy_list(children);
1289
	}
1290
1291
	LOG_EXIT_INT(rc);
1292
	return rc;
1293
}
1294
1295
/**
1296
 * check_multipath
1297
 *
1298
 * Check if this disk is a DM multipath device.
1299
 **/
1300
static int check_multipath(storage_object_t * disk)
1301
{
1302
	dm_device_list_t * dm_list, * dm_entry;
1303
	dm_target_t * targets = NULL;
1304
	local_disk_t * ld = disk->private_data;
1305
	int rc = 0;
1306
1307
	LOG_ENTRY();
1308
1309
	/* Get the list of active DM devices. */
1310
	dm_list = get_dm_device_list();
1311
	if (!dm_list) {
1312
		LOG_WARNING("Cannot get list of DM devices.\n");
1313
		goto out;
1314
	}
1315
1316
	/* Search the DM list for an entry that matches this disk. */
1317
	dm_entry = find_disk_in_dm_devices(disk, dm_list);
1318
	if (!dm_entry) {
1319
		LOG_DEBUG("Disk %s is not a DM device.\n", disk->name);
1320
		goto out;
1321
	}
1322
1323
	/* Copy the DM name to this disk. */
1324
	LOG_DEBUG("Changing disk name from %s to %s.\n",
1325
		  disk->name, dm_entry->name);
1326
	strncpy(disk->name, dm_entry->name, EVMS_NAME_SIZE);
1327
1328
	/* Get the DM mapping for this disk. */
1329
	rc = EngFncs->dm_get_targets(disk, &targets);
1330
	if (rc) {
1331
		LOG_ERROR("Error getting DM mapping for disk %s.\n", disk->name);
1332
		goto out;
1333
	}
1334
1335
	/* Reject all non-multipath devices. */
1336
	if (targets->type != DM_TARGET_MULTIPATH) {
1337
		LOG_DEBUG("Disk %s is not a multipath device.\n", disk->name);
1338
		rc = EINVAL;
1339
		goto out;
1340
	}
1341
1342
	/* Reject all multipath devices that
1343
	 * were created by other EVMS plugins.
1344
	 */
1345
	rc = check_multipath_name(disk);
1346
	if (rc) {
1347
		LOG_DEBUG("Multipath disk %s belongs to another EVMS plugin.\n",
1348
			  disk->name);
1349
		goto out;
1350
	}
1351
1352
	rc = update_multipath_child_list(targets);
1353
	if (rc) {
1354
		LOG_DEBUG("Error building list of children of "
1355
			  "multipath disk %s.\n", disk->name);
1356
		goto out;
1357
	}
1358
1359
	ld->flags |= LD_FLAG_MULTIPATH;
1360
1361
out:
1362
	EngFncs->dm_deallocate_targets(targets);
1363
	LOG_EXIT_INT(rc);
1364
	return rc;
1365
}
1366
1367
/**
1368
 * remove_multipath_children
1369
 *
1370
 * Compare the multipath_children list with the discovery output list. Any
1371
 * disks on the multipath_children list must be removed from the output list.
1372
 **/
1373
static void remove_multipath_children(list_anchor_t multipath_children,
1374
				      list_anchor_t output_list)
1375
{
1376
	list_element_t itr1, itr2, itr3;
1377
	storage_object_t * disk;
1378
	dm_device_t * child;
1379
1380
	LOG_ENTRY();
1381
1382
	LIST_FOR_EACH(multipath_children, itr3, child) {
1383
		LIST_FOR_EACH_SAFE(output_list, itr1, itr2, disk) {
1384
			if (child->major == disk->dev_major &&
1385
			    child->minor == disk->dev_minor) {
1386
				EngFncs->delete_element(itr1);
1387
				close_dev(disk);
1388
				EngFncs->engine_free(disk->private_data);
1389
				disk->flags &= ~SOFLAG_ACTIVE;
1390
				EngFncs->free_logical_disk(disk);
1391
			}
1392
		}
1393
	}
1394
1395
	LOG_EXIT_VOID();
1396
}
1397
1398
/**
1399
 * get_geometry
1400
 *
1401
 * Use the HDIO_GETGEO_BIG or HDIO_GETGEO ioctl to get the disk's geometry.
1402
 * Check that the geometry is valid for a disk.
1403
 **/
1404
static int get_geometry(storage_object_t * disk)
1405
{
1406
	struct hd_big_geometry big_geometry;
1407
	struct hd_geometry geometry;
1408
	local_disk_t * ld = disk->private_data;
1409
	int rc;
1410
1411
	LOG_ENTRY();
1412
1413
	rc = ioctl(ld->fd, HDIO_GETGEO, &geometry);
1414
	if (rc) {
1415
		rc = ioctl(ld->fd, HDIO_GETGEO_BIG, &big_geometry);
1416
		if (rc) {
1417
			rc = errno;
1418
			LOG_DEBUG("Error getting geometry for disk %s: %d: "
1419
				  "%s.\n", disk->name, rc, strerror(rc));
1420
		} else if (big_geometry.start != 0) {
1421
			/* A disk's geometry must start at offset 0. */
1422
			LOG_DEBUG("Geometry for disk %s reports a non-zero starting "
1423
				  "offset. Not a valid disk.\n", disk->name);
1424
			rc = EINVAL;
1425
		} else {
1426
			disk->geometry.cylinders = big_geometry.cylinders;
1427
			disk->geometry.heads = big_geometry.heads;
1428
			disk->geometry.sectors_per_track = big_geometry.sectors;
1429
		}
1430
	} else {
1431
		if (geometry.start != 0) {
1432
			/* A disk's geometry must start at offset 0. */
1433
			LOG_DEBUG("Geometry for disk %s reports a non-zero starting "
1434
				  "offset. Not a valid disk.\n", disk->name);
1435
			rc = EINVAL;
1436
		} else {
1437
			/* ala fdisk: never use geometry.cylinders - it is truncated */
1438
			// disk->geometry.cylinders = geometry.cylinders;
1439
			disk->geometry.heads = geometry.heads;
1440
			disk->geometry.sectors_per_track = geometry.sectors;
1441
		}
1442
	}
1443
1444
	/*
1445
	 * If the driver answered the ioctl but didn't supply a geometry,
1446
	 * fill in a default geometry.  This is what fdisk does.
1447
	 */
1448
	if (rc == 0) {
1449
		if (disk->geometry.heads == 0) {
1450
			disk->geometry.heads = 255;
1451
		}
1452
		if (disk->geometry.sectors_per_track == 0) {
1453
			disk->geometry.sectors_per_track = 63;
1454
		}
1455
		if (disk->geometry.cylinders == 0) {
1456
			disk->geometry.cylinders = disk->size / (255 * 63 *
1457
								 (disk->geometry.bytes_per_sector / 512));
1458
		}
1459
	}
1460
1461
	LOG_EXIT_INT(rc);
1462
	return rc;
1463
}
1464
1465
/**
1466
 * get_fake_geometry
1467
 *
1468
 * Some drivers (notably loop, nbd, and drbd) don't
1469
 * support geometry, so we need to fake it.
1470
 **/
1471
static int get_fake_geometry(storage_object_t * disk)
1472
{
1473
	local_disk_t * ld = disk->private_data;
1474
	int rc = EINVAL;
1475
1476
	LOG_ENTRY();
1477
1478
	if (disk->dev_major == LOOP_MAJOR ||
1479
	    disk->dev_major == NBD_MAJOR ||
1480
	    disk->dev_major == DRBD_MAJOR ||
1481
	    ld->flags & LD_FLAG_MULTIPATH) {
1482
		LOG_DEBUG("Creating fake geometry for disk %s.\n", disk->name);
1483
		disk->geometry.heads = 255;
1484
		disk->geometry.sectors_per_track = 63;
1485
		disk->geometry.cylinders = disk->size / (255 * 63);
1486
		rc = 0;
1487
	}
1488
1489
	LOG_EXIT_INT(rc);
1490
	return rc;
1491
}
1492
1493
/**
1494
 * get_block_size
1495
 *
1496
 * Use the BLKBSZGET ioctl to get the block-size for the specified disk.
1497
 **/
1498
static int get_block_size(storage_object_t * disk)
1499
{
1500
	local_disk_t * ld = disk->private_data;
1501
	int rc, block_size;
1502
1503
	LOG_ENTRY();
1504
1505
	rc = ioctl(ld->fd, BLKBSZGET, &block_size);
1506
	if (rc) {
1507
		rc = errno;
1508
		LOG_ERROR("Error getting block size for disk %s: %d: %s.\n",
1509
			  disk->name, rc, strerror(rc));
1510
	} else {
1511
		LOG_DEBUG("Disk %s has block-size %d.\n",
1512
			  disk->name, block_size);
1513
		disk->geometry.block_size = block_size;
1514
	}
1515
1516
	LOG_EXIT_INT(rc);
1517
	return rc;
1518
}
1519
1520
/**
1521
 * set_block_size
1522
 *
1523
 * Use the BLKBSZSET ioctl to set the disk's block-size.
1524
 **/
1525
static int set_block_size(storage_object_t * disk, int block_size)
1526
{
1527
	local_disk_t * ld = disk->private_data;
1528
	int rc;
1529
1530
	LOG_ENTRY();
1531
1532
	rc = ioctl(ld->fd, BLKBSZSET, &block_size);
1533
	if (rc) {
1534
		rc = errno;
1535
		LOG_ERROR("Error setting block size (%d) for disk %s: %d: "
1536
			  "%s.\n", block_size, disk->name, rc, strerror(rc));
1537
	} else {
1538
		LOG_DEBUG("Setting disk %s block-size to %d.\n",
1539
			  disk->name, block_size);
1540
		disk->geometry.block_size = block_size;
1541
	}
1542
1543
	LOG_EXIT_INT(rc);
1544
	return rc;
1545
}
1546
1547
/**
1548
 * get_hardsector_size
1549
 *
1550
 * Use the BLKSSZGET ioctl to get the disk's hard-sector-size. If the ioctl
1551
 * returns an error (some drivers don't support it yet), fall back on the
1552
 * default sector-size (which is the same default used in the kernel - see
1553
 * include/linux/blkdev.h::get_hardsect_size).
1554
 **/
1555
static void get_hardsector_size(storage_object_t * disk)
1556
{
1557
	u_int32_t hardsector_size;
1558
	local_disk_t * ld = disk->private_data;
1559
	int rc;
1560
1561
	LOG_ENTRY();
1562
1563
	rc = ioctl(ld->fd, BLKSSZGET, &hardsector_size);
1564
	if (rc) {
1565
		rc = errno;
1566
		LOG_DEBUG("Error getting hardsector size for disk %s: %d: "
1567
			  "%s.\n", disk->name, rc, strerror(rc));
1568
		hardsector_size = EVMS_VSECTOR_SIZE;
1569
	}
1570
	disk->geometry.bytes_per_sector = hardsector_size;
1571
1572
	LOG_EXIT_VOID();
1573
}
1574
1575
/**
1576
 * find_disk_type
1577
 *
1578
 * Determine if this disk is IDE, SCSI, or something else. This is done by
1579
 * examining the name of the disk. Names starting with "hd" or that contain
1580
 * "ide" will be marked as IDE. Names starting with "sd" or that contain
1581
 * "scsi" will be marked as SCSI.
1582
 **/
1583
static void find_disk_type(storage_object_t * disk)
1584
{
1585
	local_disk_t * ld = disk->private_data;
1586
1587
	LOG_ENTRY();
1588
1589
	if (!strncmp(disk->name, "hd", 2) ||
1590
	    strstr(disk->name, "ide")) {
1591
		ld->flags |= LD_FLAG_IDE;
1592
	} else if (!strncmp(disk->name, "sd", 2) ||
1593
		   strstr(disk->name, "scsi")) {
1594
		ld->flags |= LD_FLAG_SCSI;
1595
	}
1596
1597
	LOG_DEBUG("Type of disk %s is %s\n", disk->name,
1598
		  (ld->flags & LD_FLAG_IDE) ? "IDE" :
1599
		  (ld->flags & LD_FLAG_SCSI) ? "SCSI" : "Unknown");
1600
1601
	LOG_EXIT_VOID();
1602
}
1603
1604
/**
1605
 * create_logical_disk
1606
 *
1607
 * Allocate a new disk and initialize all fields.
1608
 **/
1609
static storage_object_t * create_logical_disk(storage_object_t * working_disk)
1610
{
1611
	storage_object_t * disk = NULL;
1612
	local_disk_t * working_ld = working_disk->private_data;
1613
	local_disk_t * ld;
1614
	char *name;
1615
	int rc;
1616
1617
	LOG_ENTRY();
1618
1619
	/* Replace exclaimation marks with slashes in the disk name. */
1620
	for (name = working_disk->name; *name; name++) {
1621
		if (*name == '!') *name = '/';
1622
	}
1623
1624
	rc = EngFncs->allocate_logical_disk(working_disk->name, &disk);
1625
	if (rc) {
1626
		LOG_SERIOUS("Error allocating new disk object for disk %s: %d: "
1627
			    "%s.\n", working_disk->name, rc, EngFncs->strerror(rc));
1628
		goto out;
1629
	}
1630
1631
	disk->private_data = EngFncs->engine_alloc(sizeof(local_disk_t));
1632
	if (!disk->private_data) {
1633
		LOG_SERIOUS("Error allocating private data for disk %s.\n",
1634
			    disk->name);
1635
		EngFncs->free_logical_disk(disk);
1636
		disk = NULL;
1637
		goto out;
1638
	}
1639
	ld = disk->private_data;
1640
1641
	/* Initialize the logical disk structure */
1642
	disk->data_type			= DATA_TYPE;
1643
	disk->dev_major			= working_disk->dev_major;
1644
	disk->dev_minor			= working_disk->dev_minor;
1645
	disk->plugin			= my_plugin_record;
1646
	disk->flags			= SOFLAG_ACTIVE;
1647
	disk->size			= working_disk->size;
1648
	disk->geometry.cylinders	= working_disk->geometry.cylinders;
1649
	disk->geometry.heads		= working_disk->geometry.heads;
1650
	disk->geometry.sectors_per_track= working_disk->geometry.sectors_per_track;
1651
	disk->geometry.bytes_per_sector	= working_disk->geometry.bytes_per_sector;
1652
	disk->geometry.block_size	= working_disk->geometry.block_size;
1653
1654
	/* Fill in the boot cylinder limit (LBA of 1st sector above boot
1655
	 * cylinder) for this drive. If the drive is too small then the limit
1656
	 * is the size of the drive. Otherwise the limit is calculated.
1657
	 */
1658
	disk->geometry.boot_cylinder_limit = (disk->geometry.cylinders < 1024) ?
1659
		disk->size :
1660
		(disk->geometry.heads * disk->geometry.sectors_per_track * 1023);
1661
1662
	*ld = *working_ld;
1663
	ld->file_handle->disk = disk;
1664
1665
	find_disk_type(disk);
1666
1667
	LOG_DETAILS("New Logical Disk:\n");
1668
	LOG_DETAILS("  name:            %s\n", disk->name);
1669
	LOG_DETAILS("  size:            %"PRIu64"\n", disk->size);
1670
	LOG_DETAILS("  device-number:   %x:%x\n", disk->dev_major, disk->dev_minor);
1671
	LOG_DETAILS("  file-descriptor: %d\n", ld->fd);
1672
	LOG_DETAILS("  geometry:\n");
1673
	LOG_DETAILS("    cylinders:     %"PRIu64"\n", disk->geometry.cylinders);
1674
	LOG_DETAILS("    heads:         %d\n", disk->geometry.heads);
1675
	LOG_DETAILS("    sectors:       %d\n", disk->geometry.sectors_per_track);
1676
	LOG_DETAILS("    sector size:   %d (bytes)\n", disk->geometry.bytes_per_sector);
1677
	LOG_DETAILS("    block size:    %"PRIu64" (bytes)\n", disk->geometry.block_size);
1678
1679
out:
1680
	LOG_EXIT_PTR(disk);
1681
	return disk;
1682
}
1683
1684
/**
1685
 * LD_discover
1686
 **/
1687
static int LD_discover(list_anchor_t input_list,
1688
		       list_anchor_t output_list,
1689
		       boolean final_call)
1690
{
1691
	storage_object_t working_disk;
1692
	storage_object_t * disk;
1693
	local_disk_t working_ld;
1694
	list_element_t itr;
1695
	char * full_node_path;
1696
	uint count;
1697
	int rc, i;
1698
1699
	LOG_ENTRY();
1700
1701
	/* Get the list of devices to examine. */
1702
	if (sysfs_mount_point) {
1703
		get_sysfs_devs();
1704
	} else {
1705
		get_legacy_devs();
1706
	}
1707
1708
	for (i = 0; i < dev_names_glob.gl_pathc; i++) {
1709
		full_node_path = dev_names_glob.gl_pathv[i];
1710
		LOG_DEBUG("Examining disk %s\n", full_node_path);
1711
1712
		/* Initialize the working disk object. */
1713
		memset(&working_disk, 0, sizeof(working_disk));
1714
		memset(&working_ld, 0, sizeof(working_ld));
1715
		working_disk.private_data = &working_ld;
1716
		working_ld.fd = -1;
1717
		strncpy(working_disk.name, full_node_path + base_directory_len,
1718
			EVMS_NAME_SIZE);
1719
1720
		/* Get the device-number of the disk. */
1721
		rc = get_disk_devnum(full_node_path, &working_disk, output_list);
1722
		if (rc) {
1723
			continue;
1724
		}
1725
1726
		/* Get the size of the disk. */
1727
		rc = get_disk_size(full_node_path, &working_disk);
1728
		if (rc) {
1729
			continue;
1730
		}
1731
1732
		/* Open the disk. */
1733
		rc = open_dev(&working_disk);
1734
		if (rc) {
1735
			continue;
1736
		}
1737
1738
		/* Check for DM-multipath devices. */
1739
		rc = check_multipath(&working_disk);
1740
		if (rc) {
1741
			close_dev(&working_disk);
1742
			continue;
1743
		}
1744
1745
		/* Get the disk's hard-sector-size. */
1746
		get_hardsector_size(&working_disk);
1747
1748
		/* Get the disk's geometry. */
1749
		rc = get_geometry(&working_disk);
1750
		if (rc) {
1751
			rc = get_fake_geometry(&working_disk);
1752
			if (rc) {
1753
				close_dev(&working_disk);
1754
				continue;
1755
			}
1756
		}
1757
1758
		/* Get the disk's block-size. */
1759
		rc = get_block_size(&working_disk);
1760
		if (rc) {
1761
			close_dev(&working_disk);
1762
			continue;
1763
		}
1764
1765
		/* Passed all checks. Create a new disk. */
1766
		disk = create_logical_disk(&working_disk);
1767
		if (!disk) {
1768
			close_dev(&working_disk);
1769
			continue;
1770
		}
1771
1772
		/* Insert the new disk into ouput list. */
1773
		itr = EngFncs->insert_thing(output_list, disk,
1774
					    INSERT_AFTER, NULL);
1775
		if (!itr) {
1776
			LOG_SERIOUS("Error adding new disk %s to output list. "
1777
				    "Deleting the disk.\n", disk->name);
1778
			EngFncs->engine_free(disk->private_data);
1779
			EngFncs->free_logical_disk(disk);
1780
			close_dev(&working_disk);
1781
			continue;
1782
		}
1783
	}
1784
1785
	remove_multipath_children(multipath_children, output_list);
1786
1787
	EngFncs->dm_deallocate_device_list(dm_devices);
1788
	EngFncs->destroy_list(multipath_children);
1789
1790
	count = EngFncs->list_count(output_list);
1791
	LOG_DEBUG("Discovered %d disks.\n", count);
1792
	LOG_EXIT_INT(0);
1793
	return 0;
1794
}
1795
1796
/**
1797
 * get_alignment_size
1798
 *
1799
 * Return the size (in bytes) of the alignment restrictions for O_DIRECT. On
1800
 * 2.5 kernels, this will be the disk's hard-sector-size. On 2.4 kernels, this
1801
 * will be the disk's block-size. Since block-size can change at run-time,
1802
 * always check the current block-size. Also, since we want access to as much
1803
 * of the disk as possible, try to set the block-size to 1k if it isn't
1804
 * already.
1805
 **/
1806
static int get_alignment_size(storage_object_t * disk)
1807
{
1808
	int size;
1809
	int min_block_size = max(disk->geometry.bytes_per_sector, 1024);
1810
1811
	LOG_ENTRY();
1812
1813
	if (EngFncs->is_2_4_kernel()) {
1814
		get_block_size(disk);
1815
		size = disk->geometry.block_size;
1816
		if (size > min_block_size) {
1817
			set_block_size(disk, min_block_size);
1818
			size = disk->geometry.block_size;
1819
		}
1820
	} else {
1821
		size = disk->geometry.bytes_per_sector;
1822
	}
1823
1824
	LOG_EXIT_INT(size);
1825
	return size;
1826
}
1827
1828
/**
1829
 * check_alignment
1830
 * @align_size:
1831
 * @offset:
1832
 * @count:
1833
 * @buffer:
1834
 *
1835
 * Check whether the specified offset, count, and buffer are valid for the
1836
 * specified alignment restriction.
1837
 **/
1838
static int check_alignment(int align_size,
1839
			   lsn_t offset,
1840
			   sector_count_t count,
1841
			   void * buffer)
1842
{
1843
	int align_sectors = align_size >> EVMS_VSECTOR_SIZE_SHIFT;
1844
	int align_mask = align_size - 1;
1845
	int rc = 0;
1846
1847
	LOG_ENTRY();
1848
	LOG_EXTRA("Checking alignment.\n");
1849
	LOG_EXTRA("\tAlignment Size: %d bytes\n", align_size);
1850
	LOG_EXTRA("\tBuffer:         0x%p\n", buffer);
1851
	LOG_EXTRA("\tSector Offset:  %"PRIu64"\n", offset);
1852
	LOG_EXTRA("\tSector Count:   %"PRIu64"\n", count);
1853
1854
	if ((unsigned long)buffer & align_mask) {
1855
		rc = EINVAL;
1856
	} else if (offset % align_sectors) {
1857
		rc = EINVAL;
1858
	} else if (count % align_sectors) {
1859
		rc = EINVAL;
1860
	}
1861
1862
	LOG_EXIT_INT(rc);
1863
	return rc;
1864
}
1865
1866
/**
1867
 * get_aligned_buffer
1868
 * @offset:	Starting offset (in sectors) of engine I/O request.
1869
 * @count:	Size (in sectors) of engine I/O request.
1870
 * @align_size:	Size (in bytes) that the I/O must be aligned on.
1871
 * @local_offset:	Aligned starting offset (in sectors).
1872
 * @local_count:	Aligned I/O size (in sectors).
1873
 * @buffer:	Aligned data buffer.
1874
 *
1875
 * To use O_DIRECT, the buffer passed to read() or write() must be aligned on
1876
 * the device's block/sector size. The size and starting offset of the I/O must
1877
 * also be a multiple of the block/sector size.
1878
 **/
1879
static int get_aligned_buffer(lsn_t offset,
1880
			      sector_count_t count,
1881
			      int align_size,
1882
			      lsn_t * local_offset,
1883
			      sector_count_t * local_count,
1884
			      void ** buffer)
1885
{
1886
	u_int32_t offset_diff;
1887
	int rc = 0;
1888
1889
	LOG_ENTRY();
1890
1891
	/* Round down starting offset to the alignment size. */
1892
	*local_offset = round_down(offset, align_size);
1893
1894
	/* Difference between real offset and local offset. */
1895
	offset_diff = offset - *local_offset;
1896
1897
	/* Round up total count of sectors to alignment size. */
1898
	*local_count = round_up(count + offset_diff, align_size);
1899
1900
	/* Allocate the buffer that will actually perform the I/O. The
1901
	 * memalign call guarantees that the allocated buffer is
1902
	 * aligned on the desired alignment-size.
1903
	 */
1904
	*buffer = memalign(align_size, *local_count << EVMS_VSECTOR_SIZE_SHIFT);
1905
	if (!*buffer) {
1906
		rc = ENOMEM;
1907
	}
1908
1909
	LOG_EXIT_INT(rc);
1910
	return rc;
1911
}
1912
1913
/**
1914
 * LD_read
1915
 **/
1916
static int LD_read(storage_object_t * disk,
1917
		   lsn_t offset,
1918
		   sector_count_t count,
1919
		   void * buffer)
1920
{
1921
	void * local_buffer = NULL;
1922
	lsn_t local_offset;
1923
	sector_count_t local_count;
1924
	local_disk_t * ld = disk->private_data;
1925
	int rc, align_size, aligned = FALSE;
1926
1927
	LOG_ENTRY();
1928
	LOG_DEBUG("Read disk:%s offset:%"PRIu64" count:%"PRIu64"\n",
1929
		  disk->name, offset, count);
1930
1931
        if (offset + count > disk->size) {
1932
		LOG_ERROR("Read request past end of disk.\n");
1933
		rc = EINVAL;
1934
		goto out;
1935
	}
1936
1937
	rc = read_from_cache(disk, offset, count, buffer);
1938
	if (!rc) {
1939
		/* Found in the cache. */
1940
		goto out;
1941
	}
1942
1943
	/* Make sure the disk is open. */
1944
	rc = open_dev(disk);
1945
	if (rc) {
1946
		goto out;
1947
	}
1948
1949
	/* Get the alignment restriction for O_DIRECT. */
1950
	align_size = get_alignment_size(disk);
1951
1952
	/* Check if the supplied buffer, offset, and count
1953
	 * are valid for the alignment restrictions.
1954
	 */
1955
	rc = check_alignment(align_size, offset, count, buffer);
1956
	if (rc) {
1957
		/* Get a data buffer aligned with this restriction. */
1958
		rc = get_aligned_buffer(offset, count, align_size, &local_offset,
1959
					&local_count, &local_buffer);
1960
		if (rc) {
1961
			goto out;
1962
		}
1963
	} else {
1964
		aligned = TRUE;
1965
		local_offset = offset;
1966
		local_count = count;
1967
		local_buffer = buffer;
1968
	}
1969
1970
	/* Send the read to the engine. */
1971
	rc = EngFncs->read_object(disk, ld->fd, local_buffer,
1972
				  local_count << EVMS_VSECTOR_SIZE_SHIFT,
1973
				  local_offset << EVMS_VSECTOR_SIZE_SHIFT);
1974
	if (rc < 0) {
1975
		rc = -rc;
1976
		goto out;
1977
	}
1978
1979
	/* Copy the data back to the caller's buffer. */
1980
	if (!aligned) {
1981
		memcpy(buffer, local_buffer +
1982
			       ((offset - local_offset) << EVMS_VSECTOR_SIZE_SHIFT),
1983
		       count << EVMS_VSECTOR_SIZE_SHIFT);
1984
	}
1985
1986
	/* Record this I/O in the cache. */
1987
	write_to_cache(disk, offset, count, buffer);
1988
	rc = 0;
1989
1990
out:
1991
	if (!aligned) {
1992
		free(local_buffer);
1993
	}
1994
	LOG_EXIT_INT(rc);
1995
	return rc;
1996
}
1997
1998
/**
1999
 * LD_write
2000
 **/
2001
static int LD_write(storage_object_t * disk,
2002
		    lsn_t offset,
2003
		    sector_count_t count,
2004
		    void * buffer)
2005
{
2006
	void * local_buffer = NULL;
2007
	lsn_t local_offset;
2008
	sector_count_t local_count;
2009
	local_disk_t * ld = disk->private_data;
2010
	int rc, align_size, aligned = FALSE;
2011
2012
	LOG_ENTRY();
2013
	LOG_DEBUG("Write disk:%s offset:%"PRIu64" count:%"PRIu64"\n",
2014
		  disk->name, offset, count);
2015
2016
	if (offset + count > disk->size) {
2017
		LOG_ERROR("Write request past end of disk.\n");
2018
		rc = EINVAL;
2019
		goto out;
2020
	}
2021
2022
	/* Make sure the disk is open. */
2023
	rc = open_dev(disk);
2024
	if (rc) {
2025
		goto out;
2026
	}
2027
2028
	/* Get the alignment restriction for O_DIRECT. */
2029
	align_size = get_alignment_size(disk);
2030
2031
	/* Check if the supplied buffer, offset, and count
2032
	 * are valid for the alignment restrictions.
2033
	 */
2034
	rc = check_alignment(align_size, offset, count, buffer);
2035
	if (rc) {
2036
		/* Get a data buffer aligned with this restriction. */
2037
		rc = get_aligned_buffer(offset, count, align_size, &local_offset,
2038
					&local_count, &local_buffer);
2039
		if (rc) {
2040
			goto out;
2041
		}
2042
	} else {
2043
		aligned = TRUE;
2044
		local_offset = offset;
2045
		local_count = count;
2046
		local_buffer = buffer;
2047
	}
2048
2049
	if (local_count != count) {
2050
		rc = EngFncs->read_object(disk, ld->fd, local_buffer,
2051
					  local_count << EVMS_VSECTOR_SIZE_SHIFT,
2052
					  local_offset << EVMS_VSECTOR_SIZE_SHIFT);
2053
		if (rc < 0) {
2054
			rc = -rc;
2055
			goto out;
2056
		}
2057
	}
2058
	
2059
	/* Put user data at the right place in the buffer */
2060
	if (!aligned) {
2061
		memcpy(local_buffer +
2062
		       ((offset - local_offset) << EVMS_VSECTOR_SIZE_SHIFT),
2063
		       buffer, count << EVMS_VSECTOR_SIZE_SHIFT);
2064
	}
2065
	
2066
	/* Send the write to the engine. */
2067
	rc = EngFncs->write_object(disk, ld->fd, local_buffer,
2068
				   local_count << EVMS_VSECTOR_SIZE_SHIFT,
2069
				   local_offset << EVMS_VSECTOR_SIZE_SHIFT);
2070
	if (rc < 0) {
2071
		rc = -rc;
2072
		goto out;
2073
	}
2074
2075
	/* The cache is too simple to do real caching.  It's really only a read
2076
	 * cache.  A write, which should not happen during discovery, means the
2077
	 * contents of the cache may not be up to date.  Purge the cache and
2078
	 * start caching all over again.
2079
	 */
2080
	purge_cache();
2081
	rc = 0;
2082
2083
out:
2084
	if (!aligned) {
2085
		free(local_buffer);
2086
	}
2087
	LOG_EXIT_INT(rc);
2088
	return rc;
2089
}
2090
2091
/**
2092
 * LD_discard
2093
 *
2094
 * We don't expect to get called on this API. Just like commit.
2095
 **/
2096
static int LD_discard(list_anchor_t disks)
2097
{
2098
	LOG_ENTRY();
2099
	LOG_EXIT_INT(0);
2100
	return 0;
2101
}
2102
2103
/**
2104
 * LD_add_sectors_to_kill_list
2105
 **/
2106
static int LD_add_sectors_to_kill_list(storage_object_t * disk,
2107
				       lsn_t lsn,
2108
				       sector_count_t count)
2109
{
2110
	int rc;
2111
	LOG_ENTRY();
2112
2113
	if (lsn + count > disk->size) {
2114
		LOG_ERROR("Kill-sectors request past end of disk %s.\n",
2115
			  disk->name);
2116
		rc = EINVAL;
2117
	} else {
2118
		rc = EngFncs->add_sectors_to_kill_list(disk, lsn, count);
2119
	}
2120
2121
	LOG_EXIT_INT(rc);
2122
	return rc;
2123
}
2124
2125
/**
2126
 * LD_commit_changes
2127
 *
2128
 * Disk manager doesn't do anything during commit. Just return success.
2129
 **/
2130
static int LD_commit_changes(storage_object_t * disk, commit_phase_t phase)
2131
{
2132
	LOG_ENTRY();
2133
	LOG_EXIT_INT(0);
2134
	return 0;
2135
}
2136
2137
/**
2138
 * LD_get_info
2139
 *
2140
 * Return information about this disk to display to the user.
2141
 **/
2142
static int LD_get_info(storage_object_t * disk,
2143
		       char * name,
2144
		       extended_info_array_t ** info)
2145
{
2146
	local_disk_t * ld = disk->private_data;
2147
	int rc = EINVAL;
2148
2149
	LOG_ENTRY();
2150
2151
	*info = NULL;
2152
	
2153
	if (!name) {
2154
		rc = get_basic_info(disk, info);
2155
	} else if (!strncasecmp(name, "Type", 4)) {
2156
		if (ld->flags & LD_FLAG_IDE) {
2157
			rc = get_ide_info(disk, info);
2158
		} else if (ld->flags & LD_FLAG_SCSI) {
2159
			rc = get_scsi_info(disk, info);
2160
		}
2161
	}
2162
2163
	LOG_EXIT_INT(rc);
2164
	return rc;
2165
}
2166
2167
/**
2168
 * LD_get_plugin_info
2169
 *
2170
 * Returns plug-in specific information
2171
 **/
2172
static int LD_get_plugin_info(char * descriptor_name,
2173
			      extended_info_array_t ** info)
2174
{
2175
	int rc = EINVAL;
2176
	extended_info_array_t * Info;
2177
	char version_string[64];
2178
	char required_engine_api_version_string[64];
2179
	char required_plugin_api_version_string[64];
2180
2181
	LOG_ENTRY();
2182
2183
	if (!info) {
2184
		goto out;
2185
	}
2186
	*info = NULL;
2187
2188
	if (descriptor_name) {
2189
		goto out;
2190
	}
2191
2192
	Info = EngFncs->engine_alloc(sizeof(extended_info_array_t) +
2193
				     6 * sizeof(extended_info_t));
2194
	if (!Info) {
2195
		rc = ENOMEM;
2196
		goto out;
2197
	}
2198
2199
	Info->count = 6;
2200
2201
	sprintf(version_string, "%d.%d.%d",
2202
		MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL);
2203
2204
	sprintf(required_engine_api_version_string, "%d.%d.%d",
2205
		my_plugin_record->required_engine_api_version.major,
2206
		my_plugin_record->required_engine_api_version.minor,
2207
		my_plugin_record->required_engine_api_version.patchlevel);
2208
2209
	sprintf(required_plugin_api_version_string, "%d.%d.%d",
2210
		my_plugin_record->required_plugin_api_version.plugin.major,
2211
		my_plugin_record->required_plugin_api_version.plugin.minor,
2212
		my_plugin_record->required_plugin_api_version.plugin.patchlevel);
2213
2214
	Info->info[0].name = EngFncs->engine_strdup("Short Name");
2215
	Info->info[0].title = EngFncs->engine_strdup(_("Short Name"));
2216
	Info->info[0].desc = EngFncs->engine_strdup(_("A short name given to this plug-in"));
2217
	Info->info[0].type = EVMS_Type_String;
2218
	Info->info[0].value.s = EngFncs->engine_strdup(my_plugin_record->short_name);
2219
2220
	Info->info[1].name = EngFncs->engine_strdup("Long Name");
2221
	Info->info[1].title = EngFncs->engine_strdup(_("Long Name"));
2222
	Info->info[1].desc = EngFncs->engine_strdup(_("A longer, more descriptive name for this plug-in"));
2223
	Info->info[1].type = EVMS_Type_String;
2224
	Info->info[1].value.s = EngFncs->engine_strdup(my_plugin_record->long_name);
2225
2226
	Info->info[2].name = EngFncs->engine_strdup("Type");
2227
	Info->info[2].title = EngFncs->engine_strdup(_("Plug-in Type"));
2228
	Info->info[2].desc = EngFncs->engine_strdup(_("There are various types of plug-ins, each responsible for some kind of storage object or logical volume."));
2229
	Info->info[2].type = EVMS_Type_String;
2230
	Info->info[2].value.s = EngFncs->engine_strdup(_("Device Manager"));
2231
2232
	Info->info[3].name = EngFncs->engine_strdup("Version");
2233
	Info->info[3].title = EngFncs->engine_strdup(_("Plug-in Version"));
2234
	Info->info[3].desc = EngFncs->engine_strdup(_("Version number of this plug-in"));
2235
	Info->info[3].type = EVMS_Type_String;
2236
	Info->info[3].value.s = EngFncs->engine_strdup(version_string);
2237
2238
	Info->info[4].name = EngFncs->engine_strdup("Required Engine Services Version");
2239
	Info->info[4].title = EngFncs->engine_strdup(_("Required Engine Services Version"));
2240
	Info->info[4].desc = EngFncs->engine_strdup(_("Version of the Engine services that this plug-in requires.  "
2241
						      "It will not run on older versions of the Engine services."));
2242
	Info->info[4].type = EVMS_Type_String;
2243
	Info->info[4].value.s = EngFncs->engine_strdup(required_engine_api_version_string);
2244
2245
	Info->info[5].name = EngFncs->engine_strdup("Required Plug-in API Version");
2246
	Info->info[5].title = EngFncs->engine_strdup(_("Required Plug-in API Version"));
2247
	Info->info[5].desc = EngFncs->engine_strdup(_("Version of the Engine plug-in API that this plug-in requires.  "
2248
						      "It will not run on older versions of the Engine plug-in API."));
2249
	Info->info[5].type = EVMS_Type_String;
2250
	Info->info[5].value.s = EngFncs->engine_strdup(required_plugin_api_version_string);
2251
2252
	*info = Info;
2253
	rc = 0;
2254
2255
out:
2256
	LOG_EXIT_INT(rc);
2257
	return rc;
2258
}
2259
2260
2261
static int LD_get_plugin_functions(storage_object_t        * object,
2262
				   function_info_array_t * * actions)
2263
{
2264
	LOG_ENTRY();
2265
2266
	/*
2267
	 * The Local Disk Manager has plug-in functions, but they are not
2268
	 * available for the asking.  Those who want to use them must know
2269
	 * what they are and call the plug-in function directly which will
2270
	 * be processed by LD_plugin_function() below.
2271
	 */
2272
2273
	LOG_EXIT_INT(ENOSYS);
2274
	return ENOSYS;
2275
}
2276
2277
static int LD_plugin_function(storage_object_t * object,
2278
			      task_action_t      action,
2279
			      list_anchor_t      objects,
2280
			      option_array_t   * options)
2281
{
2282
	int rc = 0;
2283
2284
	LOG_ENTRY();
2285
2286
	switch (action) {
2287
		case LDM_Start_Caching:
2288
			LOG_DEBUG("Start caching\n");
2289
			initialize_cache();
2290
			break;
2291
2292
		case LDM_Stop_Caching:
2293
			LOG_DEBUG("Stop caching\n");
2294
			destroy_cache();
2295
			break;
2296
2297
		case LDM_Open_Disk:
2298
			if (object->plugin == my_plugin_record) {
2299
				LOG_DEBUG("Open disk %s\n", object->name);
2300
				rc = open_dev(object);
2301
2302
			} else {
2303
				LOG_ERROR("%s is not managed by %s.\n",
2304
					  object->name, my_plugin_record->short_name);
2305
				rc = EINVAL;
2306
			}
2307
			break;
2308
2309
		case LDM_Close_Disk:
2310
			if (object->plugin == my_plugin_record) {
2311
				LOG_DEBUG("Close disk %s\n", object->name);
2312
				close_dev(object);
2313
2314
			} else {
2315
				LOG_ERROR("%s is not managed by %s.\n",
2316
					  object->name, my_plugin_record->short_name);
2317
				rc = EINVAL;
2318
			}
2319
			break;
2320
2321
		default:
2322
			LOG_ERROR("%d is not a valid function code.\n", action);
2323
			rc = EINVAL;
2324
	}
2325
2326
	LOG_EXIT_INT(rc);
2327
	return rc;
2328
}
2329
2330
2331
static int LD_backup_metadata(storage_object_t * disk) {
2332
2333
	int rc;
2334
2335
	LOG_ENTRY();
2336
2337
	if (disk->plugin->id != EVMS_DISK_PLUGIN_ID) {
2338
		LOG_ERROR("I don't own object %s.\n", disk->name);
2339
		LOG_EXIT_INT(EINVAL);
2340
		return EINVAL;
2341
        }
2342
2343
	rc = EngFncs->save_metadata(disk->name, NULL, 0, 0, NULL);
2344
2345
	LOG_EXIT_INT(rc);
2346
	return rc;
2347
}
2348
2349
2350
static plugin_functions_t ft_sysfs = {
2351
	.setup_evms_plugin		= LD_setup,
2352
	.cleanup_evms_plugin		= LD_cleanup,
2353
	.discover			= LD_discover,
2354
	.discard			= LD_discard,
2355
	.add_sectors_to_kill_list	= LD_add_sectors_to_kill_list,
2356
	.commit_changes			= LD_commit_changes,
2357
	.get_info			= LD_get_info,
2358
	.get_plugin_info		= LD_get_plugin_info,
2359
	.read				= LD_read,
2360
	.write				= LD_write,
2361
	.get_plugin_functions		= LD_get_plugin_functions,
2362
	.plugin_function		= LD_plugin_function,
2363
	.backup_metadata		= LD_backup_metadata
2364
};
2365
2366
plugin_record_t LD_Plugin = {
2367
	.id = EVMS_DISK_PLUGIN_ID,
2368
	.version = {
2369
		.major		= MAJOR_VERSION,
2370
		.minor		= MINOR_VERSION,
2371
		.patchlevel	= PATCH_LEVEL
2372
	},
2373
	.required_engine_api_version = {
2374
		.major		= 15,
2375
		.minor		= 0,
2376
		.patchlevel	= 0
2377
	},
2378
	.required_plugin_api_version = {
2379
		.plugin = {
2380
			.major		= 13,
2381
			.minor		= 1,
2382
			.patchlevel	= 0
2383
		}
2384
	},
2385
	.short_name = EVMS_DISK_PLUGIN_SHORT_NAME,
2386
	.long_name = EVMS_DISK_PLUGIN_LONG_NAME,
2387
	.oem_name = EVMS_IBM_OEM_NAME,
2388
	.functions = {
2389
		.plugin = &ft_sysfs
2390
	},
2391
	.container_functions = NULL
2392
};
2393
2394
plugin_record_t * my_plugin_record = &LD_Plugin;
2395
2396
plugin_record_t * evms_plugin_records[] = { &LD_Plugin,
2397
					    NULL };
2398
(-)evms-2.5.4/plugins/disk/localdskmgr.h (+1 lines)
Lines 80-85 typedef struct local_disk { Link Here
80
#define LD_FLAG_MULTIPATH	(1 << 0)
80
#define LD_FLAG_MULTIPATH	(1 << 0)
81
#define LD_FLAG_IDE		(1 << 1)
81
#define LD_FLAG_IDE		(1 << 1)
82
#define LD_FLAG_SCSI		(1 << 2)
82
#define LD_FLAG_SCSI		(1 << 2)
83
#define LD_FLAG_USERDM		(1 << 3)
83
84
84
extern engine_functions_t *EngFncs;
85
extern engine_functions_t *EngFncs;
85
extern plugin_record_t    *my_plugin_record;
86
extern plugin_record_t    *my_plugin_record;

Return to bug 115875