diff -urN multipath-tools-0.1.5/ChangeLog multipath-tools-0.1.6/ChangeLog --- multipath-tools-0.1.5/ChangeLog 2004-03-25 17:51:57.000000000 +0100 +++ multipath-tools-0.1.6/ChangeLog 2004-04-25 18:44:40.000000000 +0200 @@ -1,3 +1,7 @@ +2004-04-25 multipath-tools-0.1.6 + * add the dmadm WIP tool (read MD superblocks and create + corresponding devmaps when possible) + * plug fd leak in TUR path checker 2004-03-25 multipath-tools-0.1.5 * kpartx to manage the nested bdevs as /dev/cciss/c0d0. parts are named sysfs style : cciss!c0d0p* diff -urN multipath-tools-0.1.5/VERSION multipath-tools-0.1.6/VERSION --- multipath-tools-0.1.5/VERSION 2004-02-19 19:38:35.000000000 +0100 +++ multipath-tools-0.1.6/VERSION 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -0.0.5 diff -urN multipath-tools-0.1.5/dmadm/Makefile multipath-tools-0.1.6/dmadm/Makefile --- multipath-tools-0.1.5/dmadm/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/Makefile 2004-03-29 15:47:29.000000000 +0200 @@ -0,0 +1,46 @@ +EXEC = dmadm + +prefix = +exec_prefix = ${prefix} +bindir = ${exec_prefix}/sbin +udevdir = ../../.. +klibcdir = $(udevdir)/klibc +sysfsdir = $(udevdir)/libsysfs +arch = i386 +klibcarch = $(klibcdir)/klibc/arch/$(arch)/include + +CC = gcc +GCCINCDIR := ${shell $(CC) -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp"} +KERNEL_DIR = /lib/modules/${shell uname -r}/build +CFLAGS = -pipe -g -O2 -Wall -Wunused -Wstrict-prototypes -nostdinc \ + -I$(klibcdir)/klibc/include -I$(klibcdir)/klibc/include/bits32 \ + -I$(GCCINCDIR) -I$(KERNEL_DIR)/include -I. -I$(klibcarch) -I$(sysfsdir) + +OBJS = util.o dmadm.o +CRT0 = $(udevdir)/klibc/klibc/crt0.o +LIB = $(udevdir)/klibc/klibc/libc.a +LIBGCC := $(shell $(CC) -print-libgcc-file-name ) + +SYSFSOBJS = $(sysfsdir)/dlist.o $(sysfsdir)/sysfs_bus.o \ + $(sysfsdir)/sysfs_class.o $(sysfsdir)/sysfs_device.o \ + $(sysfsdir)/sysfs_dir.o $(sysfsdir)/sysfs_driver.o \ + $(sysfsdir)/sysfs_utils.o + +DMOBJS = ../libdevmapper/libdm-common.o \ + ../libdevmapper/ioctl/libdevmapper.o + +$(EXEC): $(OBJS) + $(LD) -o $(EXEC) $(CRT0) $(OBJS) $(SYSFSOBJS) $(DMOBJS) $(LIB) $(LIBGCC) + strip $(EXEC) + +clean: + rm -f $(OBJS) *.o $(EXEC) *~ + +install: + install -d $(DESTDIR)$(bindir) + install -m 755 $(EXEC) $(DESTDIR)$(bindir)/ + +uninstall: + rm $(DESTDIR)$(bindir)/$(EXEC) + +$(OBJS): mdadm.h diff -urN multipath-tools-0.1.5/dmadm/README multipath-tools-0.1.6/dmadm/README --- multipath-tools-0.1.5/dmadm/README 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/README 2004-04-25 18:46:57.000000000 +0200 @@ -0,0 +1,6 @@ +dmadm is a WIP tool. +It reads MD superblocks and creates corresponding devmaps when possible + +Comments and contributions welcome + +christophe.varoqui@free.fr Binary files multipath-tools-0.1.5/dmadm/dmadm and multipath-tools-0.1.6/dmadm/dmadm differ diff -urN multipath-tools-0.1.5/dmadm/dmadm.c multipath-tools-0.1.6/dmadm/dmadm.c --- multipath-tools-0.1.5/dmadm/dmadm.c 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/dmadm.c 2004-04-01 17:45:31.000000000 +0200 @@ -0,0 +1,407 @@ +/* + * mdadm - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2001-2002 Neil Brown + * + * + * 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 + * + * Author: Neil Brown + * Email: + * Paper: Neil Brown + * School of Computer Science and Engineering + * The University of New South Wales + * Sydney, 2052 + * Australia + */ + +#include "mdadm.h" +#include "../libdevmapper/libdevmapper.h" +#include +#include +#include + +#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN) +#error no endian defined +#endif +#include "md_u.h" +#include "md_p.h" + +#define DEBUG 1 +#define LOG(x, y, z...) if (DEBUG >= x) fprintf (stderr, y, ##z) + +#define LINEAR -1 +#define STRIPED 0 +#define RAID1 1 + +struct device { + char devname[FILE_NAME_SIZE]; + unsigned long long size; + mdp_super_t super; +}; + +static int +blacklist (char * dev) { + int i; + static struct { + char * headstr; + int lengh; + } blist[] = { + {"md", 2}, + {"dm", 2}, + {"sr", 2}, + {"scd", 3}, + {"ram", 3}, + {"raw", 3}, + {NULL, 0}, + }; + + for (i = 0; blist[i].lengh; i++) { + if (strncmp (dev, blist[i].headstr, blist[i].lengh) == 0) + return 1; + } + + return 0; +} + +static struct device * +sort_by_disknum (struct device * a, struct device * b) +{ + return (a->super.this_disk.number < b->super.this_disk.number ? a : b); +} + +unsigned long long +get_disk_size (char * sysfs_path, char * devname) { + unsigned long long size; + char attr_path[FILE_NAME_SIZE]; + char buff[FILE_NAME_SIZE]; + + sprintf(attr_path, "%s/%s/size", sysfs_path, devname); + + if (0 > sysfs_read_attribute_value(attr_path, buff, + FILE_NAME_SIZE * sizeof(char))) + return -1; + + size = atoi(buff); + return size; +} + +static int +linear_target (struct dlist * mddevs) +{ + char mapname[FILE_NAME_SIZE]; + char params[DM_PARAMS_SIZE]; + struct device * dev = NULL; + unsigned long long start = 0; + struct dm_task *dmt = NULL; + + dlist_for_each_data (mddevs, dev, struct device) { + memset (¶ms, 0x0, DM_PARAMS_SIZE); + + if (!start) { + /* do only on first iteration */ + sprintf (mapname, "%x:%x:%x:%x", + dev->super.set_uuid0, + dev->super.set_uuid1, + dev->super.set_uuid2, + dev->super.set_uuid3); + + if (!(dmt = dm_task_create (DM_DEVICE_CREATE))) + return 1; + + if (!dm_task_set_name (dmt, mapname)) + goto out; + } + + sprintf (params, " %i:%i 0", + dev->super.this_disk.major, + dev->super.this_disk.minor); + + LOG (1, "%llu %llu linear %s\n", start, + MD_NEW_SIZE_SECTORS(dev->size), params); + + if (!dm_task_add_target (dmt, start, + MD_NEW_SIZE_SECTORS(dev->size), + "linear", params)) + goto out; + + start += MD_NEW_SIZE_SECTORS(dev->size); + } + + if (!dm_task_run (dmt)) + goto out; + + out: + dm_task_destroy (dmt); + return 0; +} + +static int +striped_target (struct dlist * mddevs) +{ + char * p; + char params[DM_PARAMS_SIZE]; + char mapname[FILE_NAME_SIZE]; + struct device * dev = NULL; + unsigned long long size = 0; + struct dm_task *dmt = NULL; + + p = ¶ms[0]; + + dlist_for_each_data (mddevs, dev, struct device) { + + if (!size) { + /* do only on first iteration */ + sprintf (mapname, "%x:%x:%x:%x", + dev->super.set_uuid0, + dev->super.set_uuid1, + dev->super.set_uuid2, + dev->super.set_uuid3); + + size = dev->super.size * 2; + p += sprintf (p, "%i", dev->super.nr_disks); + p += sprintf (p, " %i", dev->super.chunk_size / 1024); + } + + p += sprintf (p, " %i:%i 0", + dev->super.this_disk.major, + dev->super.this_disk.minor); + } + + LOG (1, "0 %llu striped %s\n", size, params); + + if (!(dmt = dm_task_create (DM_DEVICE_CREATE))) + return 1; + + if (!dm_task_set_name (dmt, mapname)) + goto out; + + if (!dm_task_add_target (dmt, 0, size, "striped", params)) + goto out; + + if (!dm_task_run (dmt)) + goto out; + + out: + dm_task_destroy (dmt); + return 0; +} + +static int +raid1_target (struct dlist * mddevs) +{ + char * p; + char params[DM_PARAMS_SIZE]; + char mapname[FILE_NAME_SIZE]; + struct device * dev = NULL; + unsigned long long size = 0; + struct dm_task *dmt = NULL; + + p = ¶ms[0]; + + dlist_for_each_data (mddevs, dev, struct device) { + + if (!size) { + /* do only on first iteration */ + sprintf (mapname, "%x:%x:%x:%x", + dev->super.set_uuid0, + dev->super.set_uuid1, + dev->super.set_uuid2, + dev->super.set_uuid3); + + size = dev->super.size * 2; + p += sprintf (p, "core 1 1024 %i", dev->super.nr_disks); + } + + p += sprintf (p, " %i:%i 0", + dev->super.this_disk.major, + dev->super.this_disk.minor); + } + + LOG (1, "0 %llu mirror %s\n", size, params); + + if (!(dmt = dm_task_create (DM_DEVICE_CREATE))) + return 1; + + if (!dm_task_set_name (dmt, mapname)) + goto out; + + if (!dm_task_add_target (dmt, 0, size, "mirror", params)) + goto out; + + if (!dm_task_run (dmt)) + goto out; + + out: + dm_task_destroy (dmt); + return 0; +} + +int main (int argc, char **argv) +{ + struct sysfs_directory * sdir; + struct sysfs_directory * devp; + char sysfs_path[FILE_NAME_SIZE]; + char devname[FILE_NAME_SIZE]; + struct device * dev = NULL; + struct device * refdev = NULL; + struct dlist * devlist = NULL; + struct dlist * mddevs = NULL; + int fd, err; + int level; + + /* + * store every block device listed in sysfs in a dlist + * if it has a MD superblock + */ + if (sysfs_get_mnt_path (sysfs_path, FILE_NAME_SIZE)) { + LOG (0, "need sysfs\n"); + exit (1); + } + + sprintf (devname, "%s/block", sysfs_path); + strncpy (sysfs_path, devname, FILE_NAME_SIZE); + sdir = sysfs_open_directory (sysfs_path); + sysfs_read_directory (sdir); + + dlist_for_each_data (sdir->subdirs, devp, struct sysfs_directory) { + + if (blacklist (devp->name)) + continue; + + LOG (2, "%s\n", devp->name); + sprintf (devname, "/dev/%s", devp->name); + fd = open(devname, O_RDONLY); + + if (fd < 0) { + LOG (0, "Can't open %s\n", devname); + close (fd); + continue; + } + + dev = malloc (sizeof (struct device)); + + if (dev == NULL) { + LOG (0, "can't allocate memory for device\n"); + exit (1); + } + + err = load_super(fd, &dev->super); + close (fd); + + switch(err) { + case 1: + LOG (2, "cannot find device size for %s: %s\n", + devname, strerror(errno)); + free (dev); + continue; + case 2: + LOG (2, "%s is too small for md\n", + devname); + free (dev); + continue; + case 3: + LOG (2, "Cannot seek to superblock on %s: %s\n", + devname, strerror(errno)); + free (dev); + continue; + case 4: + LOG (2, "Cannot read superblock on %s\n", + devname); + free (dev); + continue; + case 5: + LOG (2, "No super block found on %s " + "(Expected magic %08x, got %08x)\n", + devname, MD_SB_MAGIC, dev->super.md_magic); + free (dev); + continue; + case 6: + LOG (2, "Cannot interpret superblock on %s - " + "version is %d\n", + devname, dev->super.major_version); + free (dev); + continue; + } + + /* here we got a valid raid member, store */ + LOG (1, "%s is part of a raid array\n", devname); + + if (devlist == NULL) { + LOG (2, "First super detected : create dlist\n"); + devlist = dlist_new (sizeof (struct device)); + } + + strcpy (dev->devname, devname); + dev->size = get_disk_size (sysfs_path, devp->name); + dlist_push (devlist, dev); + } + + sysfs_close_directory (sdir); + + /* + * coalesce by MD UUID + */ + dlist_start (devlist); + while (dlist_next (devlist)) { + refdev = dlist_pop (devlist); + mddevs = dlist_new (sizeof (struct device)); + dlist_push (mddevs, refdev); + level = refdev->super.level; + + LOG (1, "raid found : %d:%d", + refdev->super.this_disk.major, + refdev->super.this_disk.minor); + + dlist_for_each_data (devlist, dev, struct device) { + if (0 == compare_super (&refdev->super, &dev->super)) { + LOG (1, " %d:%d", + dev->super.this_disk.major, + dev->super.this_disk.minor); + dlist_insert_sorted (mddevs, dev, + (void *)sort_by_disknum); + dlist_pop (devlist); + continue; + } + } + + LOG (1, "\n"); + + /* + * here we have an array in mddevs. + * do sanity checks and create devmap + */ + switch (level) { + case LINEAR: + linear_target (mddevs); + break; + + case STRIPED: + striped_target (mddevs); + break; + + case RAID1: + raid1_target (mddevs); + break; + + default: + LOG (1, "unsupported raid level : skip\n"); + } + + dlist_destroy (mddevs); + } + + return 0; +} Binary files multipath-tools-0.1.5/dmadm/dmadm.o and multipath-tools-0.1.6/dmadm/dmadm.o differ diff -urN multipath-tools-0.1.5/dmadm/md_p.h multipath-tools-0.1.6/dmadm/md_p.h --- multipath-tools-0.1.5/dmadm/md_p.h 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/md_p.h 2004-03-29 09:20:52.000000000 +0200 @@ -0,0 +1,176 @@ +/* + md_p.h : physical layout of Linux RAID devices + Copyright (C) 1996-98 Ingo Molnar, Gadi Oxman + + 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, or (at your option) + any later version. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _MD_P_H +#define _MD_P_H + +/* + * RAID superblock. + * + * The RAID superblock maintains some statistics on each RAID configuration. + * Each real device in the RAID set contains it near the end of the device. + * Some of the ideas are copied from the ext2fs implementation. + * + * We currently use 4096 bytes as follows: + * + * word offset function + * + * 0 - 31 Constant generic RAID device information. + * 32 - 63 Generic state information. + * 64 - 127 Personality specific information. + * 128 - 511 12 32-words descriptors of the disks in the raid set. + * 512 - 911 Reserved. + * 912 - 1023 Disk specific descriptor. + */ + +/* + * If x is the real device size in bytes, we return an apparent size of: + * + * y = (x & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES + * + * and place the 4kB superblock at offset y. + */ +#define MD_RESERVED_BYTES (64 * 1024) +#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) +#define MD_RESERVED_BLOCKS (MD_RESERVED_BYTES / BLOCK_SIZE) + +#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS) +#define MD_NEW_SIZE_BLOCKS(x) ((x & ~(MD_RESERVED_BLOCKS - 1)) - MD_RESERVED_BLOCKS) + +#define MD_SB_BYTES 4096 +#define MD_SB_WORDS (MD_SB_BYTES / 4) +#define MD_SB_BLOCKS (MD_SB_BYTES / BLOCK_SIZE) +#define MD_SB_SECTORS (MD_SB_BYTES / 512) + +/* + * The following are counted in 32-bit words + */ +#define MD_SB_GENERIC_OFFSET 0 +#define MD_SB_PERSONALITY_OFFSET 64 +#define MD_SB_DISKS_OFFSET 128 +#define MD_SB_DESCRIPTOR_OFFSET 992 + +#define MD_SB_GENERIC_CONSTANT_WORDS 32 +#define MD_SB_GENERIC_STATE_WORDS 32 +#define MD_SB_GENERIC_WORDS (MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS) +#define MD_SB_PERSONALITY_WORDS 64 +#define MD_SB_DESCRIPTOR_WORDS 32 +#define MD_SB_DISKS 27 +#define MD_SB_DISKS_WORDS (MD_SB_DISKS*MD_SB_DESCRIPTOR_WORDS) +#define MD_SB_RESERVED_WORDS (1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS) +#define MD_SB_EQUAL_WORDS (MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS) + +/* + * Device "operational" state bits + */ +#define MD_DISK_FAULTY 0 /* disk is faulty / operational */ +#define MD_DISK_ACTIVE 1 /* disk is running or spare disk */ +#define MD_DISK_SYNC 2 /* disk is in sync with the raid set */ +#define MD_DISK_REMOVED 3 /* disk is in sync with the raid set */ + +typedef struct mdp_device_descriptor_s { + __u32 number; /* 0 Device number in the entire set */ + __u32 major; /* 1 Device major number */ + __u32 minor; /* 2 Device minor number */ + __u32 raid_disk; /* 3 The role of the device in the raid set */ + __u32 state; /* 4 Operational state */ + __u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5]; +} mdp_disk_t; + +#define MD_SB_MAGIC 0xa92b4efc + +/* + * Superblock state bits + */ +#define MD_SB_CLEAN 0 +#define MD_SB_ERRORS 1 + +typedef struct mdp_superblock_s { + /* + * Constant generic information + */ + __u32 md_magic; /* 0 MD identifier */ + __u32 major_version; /* 1 major version to which the set conforms */ + __u32 minor_version; /* 2 minor version ... */ + __u32 patch_version; /* 3 patchlevel version ... */ + __u32 gvalid_words; /* 4 Number of used words in this section */ + __u32 set_uuid0; /* 5 Raid set identifier */ + __u32 ctime; /* 6 Creation time */ + __u32 level; /* 7 Raid personality */ + __u32 size; /* 8 Apparent size of each individual disk */ + __u32 nr_disks; /* 9 total disks in the raid set */ + __u32 raid_disks; /* 10 disks in a fully functional raid set */ + __u32 md_minor; /* 11 preferred MD minor device number */ + __u32 not_persistent; /* 12 does it have a persistent superblock */ + __u32 set_uuid1; /* 13 Raid set identifier #2 */ + __u32 set_uuid2; /* 14 Raid set identifier #3 */ + __u32 set_uuid3; /* 15 Raid set identifier #4 */ + __u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 16]; + + /* + * Generic state information + */ + __u32 utime; /* 0 Superblock update time */ + __u32 state; /* 1 State bits (clean, ...) */ + __u32 active_disks; /* 2 Number of currently active disks */ + __u32 working_disks; /* 3 Number of working disks */ + __u32 failed_disks; /* 4 Number of failed disks */ + __u32 spare_disks; /* 5 Number of spare disks */ + __u32 sb_csum; /* 6 checksum of the whole superblock */ +#if __BYTE_ORDER == __BIG_ENDIAN + __u32 events_hi; /* 7 high-order of superblock update count */ + __u32 events_lo; /* 8 low-order of superblock update count */ +#else + __u32 events_lo; /* 7 low-order of superblock update count */ + __u32 events_hi; /* 8 high-order of superblock update count */ +#endif + __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 9]; + + /* + * Personality information + */ + __u32 layout; /* 0 the array's physical layout */ + __u32 chunk_size; /* 1 chunk size in bytes */ + __u32 root_pv; /* 2 LV root PV */ + __u32 root_block; /* 3 LV root block */ + __u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 4]; + + /* + * Disks information + */ + mdp_disk_t disks[MD_SB_DISKS]; + + /* + * Reserved + */ + __u32 reserved[MD_SB_RESERVED_WORDS]; + + /* + * Active descriptor + */ + mdp_disk_t this_disk; + +} mdp_super_t; + +#ifdef __TINYC__ +typedef unsigned long long __u64; +#endif + +static inline __u64 md_event(mdp_super_t *sb) { + __u64 ev = sb->events_hi; + return (ev<<32)| sb->events_lo; +} + +#endif + diff -urN multipath-tools-0.1.5/dmadm/md_u.h multipath-tools-0.1.6/dmadm/md_u.h --- multipath-tools-0.1.5/dmadm/md_u.h 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/md_u.h 2004-03-29 09:33:01.000000000 +0200 @@ -0,0 +1,116 @@ +/* + md_u.h : user <=> kernel API between Linux raidtools and RAID drivers + Copyright (C) 1998 Ingo Molnar + + 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, or (at your option) + any later version. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _MD_U_H +#define _MD_U_H + +/* ioctls */ + +/* status */ +#define RAID_VERSION _IOR (MD_MAJOR, 0x10, mdu_version_t) +#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, mdu_array_info_t) +#define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t) +#define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13) +#define RAID_AUTORUN _IO (MD_MAJOR, 0x14) + +/* configuration */ +#define CLEAR_ARRAY _IO (MD_MAJOR, 0x20) +#define ADD_NEW_DISK _IOW (MD_MAJOR, 0x21, mdu_disk_info_t) +#define HOT_REMOVE_DISK _IO (MD_MAJOR, 0x22) +#define SET_ARRAY_INFO _IOW (MD_MAJOR, 0x23, mdu_array_info_t) +#define SET_DISK_INFO _IO (MD_MAJOR, 0x24) +#define WRITE_RAID_INFO _IO (MD_MAJOR, 0x25) +#define UNPROTECT_ARRAY _IO (MD_MAJOR, 0x26) +#define PROTECT_ARRAY _IO (MD_MAJOR, 0x27) +#define HOT_ADD_DISK _IO (MD_MAJOR, 0x28) +#define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29) + +/* usage */ +#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t) +#define START_ARRAY _IO (MD_MAJOR, 0x31) +#define STOP_ARRAY _IO (MD_MAJOR, 0x32) +#define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33) +#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) + +typedef struct mdu_version_s { + int major; + int minor; + int patchlevel; +} mdu_version_t; + +typedef struct mdu_array_info_s { + /* + * Generic constant information + */ + int major_version; + int minor_version; + int patch_version; + int ctime; + int level; + int size; + int nr_disks; + int raid_disks; + int md_minor; + int not_persistent; + + /* + * Generic state information + */ + int utime; /* 0 Superblock update time */ + int state; /* 1 State bits (clean, ...) */ + int active_disks; /* 2 Number of currently active disks */ + int working_disks; /* 3 Number of working disks */ + int failed_disks; /* 4 Number of failed disks */ + int spare_disks; /* 5 Number of spare disks */ + + /* + * Personality information + */ + int layout; /* 0 the array's physical layout */ + int chunk_size; /* 1 chunk size in bytes */ + +} mdu_array_info_t; + +typedef struct mdu_disk_info_s { + /* + * configuration/status of one particular disk + */ + int number; + int major; + int minor; + int raid_disk; + int state; + +} mdu_disk_info_t; + +typedef struct mdu_start_info_s { + /* + * configuration/status of one particular disk + */ + int major; + int minor; + int raid_disk; + int state; + +} mdu_start_info_t; + +typedef struct mdu_param_s +{ + int personality; /* 1,2,3,4 */ + int chunk_size; /* in bytes */ + int max_fault; /* unused for now */ +} mdu_param_t; + +#endif + diff -urN multipath-tools-0.1.5/dmadm/mdadm.h multipath-tools-0.1.6/dmadm/mdadm.h --- multipath-tools-0.1.5/dmadm/mdadm.h 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/mdadm.h 2004-03-29 18:12:33.000000000 +0200 @@ -0,0 +1,221 @@ +/* + * mdadm - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2001-2002 Neil Brown + * + * + * 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 + * + * Author: Neil Brown + * Email: + * Paper: Neil Brown + * School of Computer Science and Engineering + * The University of New South Wales + * Sydney, 2052 + * Australia + */ + +#define __USE_LARGEFILE64 +#define MD_MAJOR 9 +#define FILE_NAME_SIZE 255 +#define DM_PARAMS_SIZE 2048 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef BLKGETSIZE +#define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */ +#endif + +#ifndef BLKSSZGET +#define BLKSSZGET _IO(0x12,104) /* get block device sector size */ +#endif + +#ifndef BLKFLSBUF +#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ +#endif + +#ifndef BLKGETSIZE64 +#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ +#endif + +#include "md_u.h" +#include "md_p.h" + +//extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); +#define lseek64 llseek + +#define Name "dmadm" + +enum mode { + ASSEMBLE=1, + BUILD, + CREATE, + MANAGE, + MISC, + MONITOR, +}; + +extern char short_options[]; +extern struct option long_options[]; +extern char Version[], Usage[], Help[], OptionHelp[], + Help_create[], Help_build[], Help_assemble[], + Help_manage[], Help_misc[], Help_monitor[], Help_config[]; + +/* structures read from config file */ +/* List of mddevice names and identifiers + * Identifiers can be: + * uuid=128-hex-uuid + * super-minor=decimal-minor-number-from-superblock + * devices=comma,separated,list,of,device,names,with,wildcards + * + * If multiple fields are present, the intersection of all matching + * devices is considered + */ +#define UnSet (0xfffe) +typedef struct mddev_ident_s { + char *devname; + + int uuid_set; + __u32 uuid[4]; + + unsigned int super_minor; + + char *devices; /* comma separated list of device + * names with wild cards + */ + int level; + unsigned int raid_disks; + unsigned int spare_disks; + char *spare_group; + struct mddev_ident_s *next; +} *mddev_ident_t; + +/* List of device names - wildcards expanded */ +typedef struct mddev_dev_s { + char *devname; + char disposition; /* 'a' for add, 'r' for remove, 'f' for fail. + * Not set for names read from .config + */ + struct mddev_dev_s *next; +} *mddev_dev_t; + +typedef struct mapping { + char *name; + int num; +} mapping_t; + + +struct mdstat_ent { + char *dev; + int devnum; + int active; + char *level; + char *pattern; /* U or up, _ for down */ + int percent; /* -1 if no resync */ + struct mdstat_ent *next; +}; + +extern struct mdstat_ent *mdstat_read(void); +extern void free_mdstat(struct mdstat_ent *ms); + +#ifndef Sendmail +#define Sendmail "/usr/lib/sendmail -t" +#endif + +extern char *map_num(mapping_t *map, int num); +extern int map_name(mapping_t *map, char *name); +extern mapping_t r5layout[], pers[], modes[]; + +extern char *map_dev(int major, int minor); + + +extern int Manage_ro(char *devname, int fd, int readonly); +extern int Manage_runstop(char *devname, int fd, int runstop); +extern int Manage_subdevs(char *devname, int fd, + mddev_dev_t devlist); + + +extern int Assemble(char *mddev, int mdfd, + mddev_ident_t ident, + char *conffile, + mddev_dev_t devlist, + int readonly, int runstop, + char *update, + int verbose, int force); + +extern int Build(char *mddev, int mdfd, int chunk, int level, + int raiddisks, + mddev_dev_t devlist); + + +extern int Create(char *mddev, int mdfd, + int chunk, int level, int layout, unsigned long size, int raiddisks, int sparedisks, + int subdevs, mddev_dev_t devlist, + int runstop, int verbose, int force); + +extern int Detail(char *dev, int brief, int test); +extern int Query(char *dev); +extern int Examine(mddev_dev_t devlist, int brief, int scan, int SparcAdjust); +extern int Monitor(mddev_dev_t devlist, + char *mailaddr, char *alert_cmd, + int period, int daemonise, int scan, int oneshot, + char *config, int test); + +extern int Kill(char *dev, int force); + +extern int md_get_version(int fd); +extern int get_linux_version(void); +extern int parse_uuid(char *str, int uuid[4]); +extern int check_ext2(int fd, char *name); +extern int check_reiser(int fd, char *name); +extern int check_raid(int fd, char *name); + +extern mddev_ident_t conf_get_ident(char *conffile, char *dev); +extern mddev_dev_t conf_get_devs(char *conffile); +extern char *conf_get_mailaddr(char *conffile); +extern char *conf_get_program(char *conffile); +extern char *conf_line(FILE *file); +extern char *conf_word(FILE *file, int allow_key); +extern void free_line(char *line); +extern int match_oneof(char *devices, char *devname); +extern int load_super(int fd, mdp_super_t *super); +extern void uuid_from_super(int uuid[4], mdp_super_t *super); +extern int same_uuid(int a[4], int b[4]); +extern int compare_super(mdp_super_t *first, mdp_super_t *second); +extern unsigned long calc_sb_csum(mdp_super_t *super); +extern int store_super(int fd, mdp_super_t *super); +extern int enough(int level, int raid_disks, int avail_disks); +extern int ask(char *mesg); + + +extern char *human_size(long long bytes); +char *human_size_brief(long long bytes); + +extern void put_md_name(char *name); +extern char *get_md_name(int dev); + +extern char DefaultConfFile[]; diff -urN multipath-tools-0.1.5/dmadm/util.c multipath-tools-0.1.6/dmadm/util.c --- multipath-tools-0.1.5/dmadm/util.c 1970-01-01 01:00:00.000000000 +0100 +++ multipath-tools-0.1.6/dmadm/util.c 2004-03-29 10:29:01.000000000 +0200 @@ -0,0 +1,437 @@ +/* + * mdadm - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2001-2002 Neil Brown + * + * + * 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 + * + * Author: Neil Brown + * Email: + * Paper: Neil Brown + * School of Computer Science and Engineering + * The University of New South Wales + * Sydney, 2052 + * Australia + */ + +#include "mdadm.h" +#include "md_p.h" +#include +#include + +/* + * Parse a 128 bit uuid in 4 integers + * format is 32 hexx nibbles with options :. separator + * If not exactly 32 hex digits are found, return 0 + * else return 1 + */ +int parse_uuid(char *str, int uuid[4]) +{ + int hit = 0; /* number of Hex digIT */ + int i; + char c; + for (i=0; i<4; i++) uuid[i]=0; + + while ((c= *str++)) { + int n; + if (c>='0' && c<='9') + n = c-'0'; + else if (c>='a' && c <= 'f') + n = 10 + c - 'a'; + else if (c>='A' && c <= 'F') + n = 10 + c - 'A'; + else if (strchr(":. -", c)) + continue; + else return 0; + + if (hit<32) { + uuid[hit/8] <<= 4; + uuid[hit/8] += n; + } + hit++; + } + if (hit == 32) + return 1; + return 0; + +} + + +/* + * Get the md version number. + * We use the RAID_VERSION ioctl if it is supported + * If not, but we have a block device with major '9', we assume + * 0.36.0 + * + * Return version number as 24 but number - assume version parts + * always < 255 + */ + +int md_get_version(int fd) +{ + struct stat stb; + mdu_version_t vers; + + if (fstat(fd, &stb)<0) + return -1; + if ((S_IFMT&stb.st_mode) != S_IFBLK) + return -1; + + if (ioctl(fd, RAID_VERSION, &vers) == 0) + return (vers.major*10000) + (vers.minor*100) + vers.patchlevel; + if (errno == EACCES) + return -1; + if (MAJOR(stb.st_rdev) == MD_MAJOR) + return (3600); + return -1; +} + + +int get_linux_version() +{ + struct utsname name; + char *cp; + int a,b,c; + if (uname(&name) <0) + return -1; + + cp = name.release; + a = strtoul(cp, &cp, 10); + if (*cp != '.') return -1; + b = strtoul(cp+1, &cp, 10); + if (*cp != '.') return -1; + c = strtoul(cp+1, NULL, 10); + + return (a*1000000)+(b*1000)+c; +} + +int enough(int level, int raid_disks, int avail_disks) +{ + switch (level) { + case -4: + return avail_disks>= 1; + case -1: + case 0: + return avail_disks == raid_disks; + case 1: + return avail_disks >= 1; + case 4: + case 5: + return avail_disks >= raid_disks-1; + case 6: + return avail_disks >= raid_disks-2; + default: + return 0; + } +} + +int same_uuid(int a[4], int b[4]) +{ + if (a[0]==b[0] && + a[1]==b[1] && + a[2]==b[2] && + a[3]==b[3]) + return 1; + return 0; +} + +void uuid_from_super(int uuid[4], mdp_super_t *super) +{ + uuid[0] = super->set_uuid0; + if (super->minor_version >= 90) { + uuid[1] = super->set_uuid1; + uuid[2] = super->set_uuid2; + uuid[3] = super->set_uuid3; + } else { + uuid[1] = 0; + uuid[2] = 0; + uuid[3] = 0; + } +} + +int compare_super(mdp_super_t *first, mdp_super_t *second) +{ + /* + * return: + * 0 same, or first was empty, and second was copied + * 1 second had wrong number + * 2 wrong uuid + * 3 wrong other info + */ + int uuid1[4], uuid2[4]; + if (second->md_magic != MD_SB_MAGIC) + return 1; + if (first-> md_magic != MD_SB_MAGIC) { + memcpy(first, second, sizeof(*first)); + return 0; + } + + uuid_from_super(uuid1, first); + uuid_from_super(uuid2, second); + if (!same_uuid(uuid1, uuid2)) + return 2; + if (first->major_version != second->major_version || + first->minor_version != second->minor_version || + first->patch_version != second->patch_version || + first->gvalid_words != second->gvalid_words || + first->ctime != second->ctime || + first->level != second->level || + first->size != second->size || + first->raid_disks != second->raid_disks ) + return 3; + + return 0; +} + +int load_super(int fd, mdp_super_t *super) +{ + /* try to read in the superblock + * + * return + * 0 - success + * 1 - no block size + * 2 - too small + * 3 - no seek + * 4 - no read + * 5 - no magic + * 6 - wrong major version + */ + unsigned long size; + unsigned long long offset; + + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + + if (size < MD_RESERVED_SECTORS*2) + return 2; + + offset = MD_NEW_SIZE_SECTORS(size); + + offset *= 512; + + ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ + + if (lseek64(fd, offset, 0)< 0LL) + return 3; + + if (read(fd, super, sizeof(*super)) != sizeof(*super)) + return 4; + + if (super->md_magic != MD_SB_MAGIC) + return 5; + + if (super->major_version != 0) + return 6; + return 0; +} + +int store_super(int fd, mdp_super_t *super) +{ + long size; + long long offset; + + if (ioctl(fd, BLKGETSIZE, &size)) + return 1; + + if (size < MD_RESERVED_SECTORS*2) + return 2; + + offset = MD_NEW_SIZE_SECTORS(size); + + offset *= 512; + + if (lseek64(fd, offset, 0)< 0LL) + return 3; + + if (write(fd, super, sizeof(*super)) != sizeof(*super)) + return 4; + + return 0; +} + + + +int check_raid(int fd, char *name) +{ + mdp_super_t super; + time_t crtime; + if (load_super(fd, &super)) + return 0; + /* Looks like a raid array .. */ + fprintf(stderr, Name ": %s appears to be part of a raid array:\n", + name); + crtime = super.ctime; + return 1; +} + +char *map_num(mapping_t *map, int num) +{ + while (map->name) { + if (map->num == num) + return map->name; + map++; + } + return NULL; +} + +int map_name(mapping_t *map, char *name) +{ + while (map->name) { + if (strcmp(map->name, name)==0) + return map->num; + map++; + } + return UnSet; +} + +unsigned long calc_sb_csum(mdp_super_t *super) +{ + unsigned int oldcsum = super->sb_csum; + unsigned long long newcsum = 0; + unsigned long csum; + int i; + unsigned int *superc = (int*) super; + super->sb_csum = 0; + + for(i=0; i>32); + super->sb_csum = oldcsum; + return csum; +} + +char *human_size(long long bytes) +{ + static char buf[30]; + + + if (bytes < 5000*1024) + buf[0]=0; + else if (bytes < 2*1024LL*1024LL*1024LL) + sprintf(buf, " (%ld.%02ld MiB %ld.%02ld MB)", + (long)(bytes>>20), + (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100), + (long)(bytes/1000/1000), + (long)(((bytes%1000000)+5000)/10000) + ); + else + sprintf(buf, " (%ld.%02ld GiB %ld.%02ld GB)", + (long)(bytes>>30), + (long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100), + (long)(bytes/1000LL/1000LL/1000LL), + (long)((((bytes/1000)%1000000)+5000)/10000) + ); + return buf; +} + +char *human_size_brief(long long bytes) +{ + static char buf[30]; + + + if (bytes < 5000*1024) + sprintf(buf, "%ld.%02ldKiB", + (long)(bytes>>10), (long)(((bytes&1023)*100+512)/1024) + ); + else if (bytes < 2*1024LL*1024LL*1024LL) + sprintf(buf, "%ld.%02ldMiB", + (long)(bytes>>20), + (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100) + ); + else + sprintf(buf, "%ld.%02ldGiB", + (long)(bytes>>30), + (long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100) + ); + return buf; +} + +static int mdp_major = -1; +/* +void get_mdp_major(void) +{ + FILE *fl = fopen("/proc/devices", "r"); + char *w; + int have_block = 0; + int have_devices = 0; + int last_num = -1; + if (!fl) + return; + while ((w = conf_word(fl, 1))) { + if (have_block && strcmp(w, "devices:")==0) + have_devices = 1; + have_block = (strcmp(w, "Block")==0); + if (isdigit(w[0])) + last_num = atoi(w); + if (have_devices && strcmp(w, "mdp")==0) + mdp_major = last_num; + free(w); + } + fclose(fl); +} + +char *get_md_name(int dev) +{ +*/ + /* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */ + /* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */ +/* + static char devname[50]; + struct stat stb; + dev_t rdev; + + if (dev < 0) { + + if (mdp_major < 0) get_mdp_major(); + if (mdp_major < 0) return NULL; + rdev = MKDEV(mdp_major, (-1-dev)<<6); + sprintf(devname, "/dev/md/d%d", -1-dev); + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + } else { + rdev = MKDEV(MD_MAJOR, dev); + sprintf(devname, "/dev/md%d", dev); + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + + sprintf(devname, "/dev/md/%d", dev); + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + } + sprintf(devname, "/dev/.tmp.md%d", dev); + if (mknod(devname, S_IFBLK | 0600, rdev) == -1) + return NULL; + + if (stat(devname, &stb) == 0 + && (S_IFMT&stb.st_mode) == S_IFBLK + && (stb.st_rdev == rdev)) + return devname; + unlink(devname); + return NULL; +} + +void put_md_name(char *name) +{ + if (strncmp(name, "/dev/.tmp.md", 12)==0) + unlink(name); +} +*/ Binary files multipath-tools-0.1.5/dmadm/util.o and multipath-tools-0.1.6/dmadm/util.o differ diff -urN multipath-tools-0.1.5/multipathd/checkers.c multipath-tools-0.1.6/multipathd/checkers.c --- multipath-tools-0.1.5/multipathd/checkers.c 2004-02-29 10:39:25.000000000 +0100 +++ multipath-tools-0.1.6/multipathd/checkers.c 2004-04-01 15:36:38.000000000 +0200 @@ -23,6 +23,10 @@ char buf; fd = open (devnode, O_RDONLY); + + if (fd <= 0) + return fd; + if (read (fd, &buf, 1) != 1) r = 0; else @@ -52,11 +56,13 @@ io_hdr.timeout = 20000; io_hdr.pack_id = 0; if (ioctl(fd, SG_IO, &io_hdr) < 0) { - close(fd); + close (fd); return 0; } if (io_hdr.info & SG_INFO_OK_MASK) { + close (fd); return 0; } + close (fd); return 1; }