Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 262061 Details for
Bug 331971
[patch] sys-kernel/genkernel-3.4.10.907 - upgrade busybox
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
1.18.1-mdadm.diff
1.18.1-mdadm.diff (text/plain), 166.24 KB, created by
Denis Kaganovich
on 2011-02-10 16:46:31 UTC
(
hide
)
Description:
1.18.1-mdadm.diff
Filename:
MIME Type:
Creator:
Denis Kaganovich
Created:
2011-02-10 16:46:31 UTC
Size:
166.24 KB
patch
obsolete
>Based on: > >> Forward-port the mdadm tool from the Gentoo Busybox-1.1.3. >> Should handle all types of metadata 0.90, 1.0, 1.1, 1.2. >> If /etc/mdadm.conf does not exist in the initrd, it is created first, by >> scanning devices, and then it is used. > >> Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> > >--- a/Config.in 2010-12-21 06:31:04.000000000 +0200 >+++ mdadm/Config.in 2011-01-12 21:33:01.000000000 +0200 >@@ -749,6 +749,7 @@ source findutils/Config.in > source init/Config.in > source loginutils/Config.in > source e2fsprogs/Config.in >+source mdadm/Config.in > source modutils/Config.in > source util-linux/Config.in > source miscutils/Config.in >--- a/include/applets.src.h 2010-12-21 06:31:04.000000000 +0200 >+++ mdadm/include/applets.src.h 2011-01-12 21:33:01.000000000 +0200 >@@ -206,6 +206,7 @@ IF_KILLALL5(APPLET_ODDNAME(killall5, kil > IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) > IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) > IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) >+IF_MDADM(APPLET(mdadm, _BB_DIR_SBIN, _BB_SUID_DROP)) > IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) > IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux32)) > IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux64)) >--- a/include/usage.src.h 2010-12-21 06:29:45.000000000 +0200 >+++ mdadm/include/usage.src.h 2011-01-12 21:33:01.000000000 +0200 >@@ -2404,6 +2404,11 @@ INSERT > "\n -w Warn about improperly formatted checksum lines" \ > ) > >+#define mdadm_trivial_usage \ >+ "" >+#define mdadm_full_usage \ >+ "Assemble or Examine the mdadm arrays." >+ > #define mdev_trivial_usage \ > "[-s]" > #define mdev_full_usage "\n\n" \ >--- a/Makefile 2010-12-21 06:31:43.000000000 +0200 >+++ mdadm/Makefile 2011-01-12 21:33:01.000000000 +0200 >@@ -478,6 +478,7 @@ libs-y := \ > loginutils/ \ > mailutils/ \ > miscutils/ \ >+ mdadm/ \ > modutils/ \ > networking/ \ > networking/libiproute/ \ >--- a/mdadm/bitmap.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/bitmap.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,287 @@ >+/* >+ * bitmap.h: Copyright (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003 >+ * >+ * additions: Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc. >+ */ >+#ifndef BITMAP_H >+#define BITMAP_H 1 >+ >+#define BITMAP_MAJOR_LO 3 >+/* version 4 insists the bitmap is in little-endian order >+ * with version 3, it is host-endian which is non-portable >+ */ >+#define BITMAP_MAJOR_HI 4 >+#define BITMAP_MAJOR_HOSTENDIAN 3 >+ >+#define BITMAP_MINOR 39 >+ >+/* >+ * in-memory bitmap: >+ * >+ * Use 16 bit block counters to track pending writes to each "chunk". >+ * The 2 high order bits are special-purpose, the first is a flag indicating >+ * whether a resync is needed. The second is a flag indicating whether a >+ * resync is active. >+ * This means that the counter is actually 14 bits: >+ * >+ * +--------+--------+------------------------------------------------+ >+ * | resync | resync | counter | >+ * | needed | active | | >+ * | (0-1) | (0-1) | (0-16383) | >+ * +--------+--------+------------------------------------------------+ >+ * >+ * The "resync needed" bit is set when: >+ * a '1' bit is read from storage at startup. >+ * a write request fails on some drives >+ * a resync is aborted on a chunk with 'resync active' set >+ * It is cleared (and resync-active set) when a resync starts across all drives >+ * of the chunk. >+ * >+ * >+ * The "resync active" bit is set when: >+ * a resync is started on all drives, and resync_needed is set. >+ * resync_needed will be cleared (as long as resync_active wasn't already set). >+ * It is cleared when a resync completes. >+ * >+ * The counter counts pending write requests, plus the on-disk bit. >+ * When the counter is '1' and the resync bits are clear, the on-disk >+ * bit can be cleared aswell, thus setting the counter to 0. >+ * When we set a bit, or in the counter (to start a write), if the fields is >+ * 0, we first set the disk bit and set the counter to 1. >+ * >+ * If the counter is 0, the on-disk bit is clear and the stipe is clean >+ * Anything that dirties the stipe pushes the counter to 2 (at least) >+ * and sets the on-disk bit (lazily). >+ * If a periodic sweep find the counter at 2, it is decremented to 1. >+ * If the sweep find the counter at 1, the on-disk bit is cleared and the >+ * counter goes to zero. >+ * >+ * Also, we'll hijack the "map" pointer itself and use it as two 16 bit block >+ * counters as a fallback when "page" memory cannot be allocated: >+ * >+ * Normal case (page memory allocated): >+ * >+ * page pointer (32-bit) >+ * >+ * [ ] ------+ >+ * | >+ * +-------> [ ][ ]..[ ] (4096 byte page == 2048 counters) >+ * c1 c2 c2048 >+ * >+ * Hijacked case (page memory allocation failed): >+ * >+ * hijacked page pointer (32-bit) >+ * >+ * [ ][ ] (no page memory allocated) >+ * counter #1 (16-bit) counter #2 (16-bit) >+ * >+ */ >+ >+#ifdef __KERNEL__ >+ >+#define PAGE_BITS (PAGE_SIZE << 3) >+#define PAGE_BIT_SHIFT (PAGE_SHIFT + 3) >+ >+typedef __u16 bitmap_counter_t; >+#define COUNTER_BITS 16 >+#define COUNTER_BIT_SHIFT 4 >+#define COUNTER_BYTE_RATIO (COUNTER_BITS / 8) >+#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3) >+ >+#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1))) >+#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2))) >+#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1) >+#define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK) >+#define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK) >+#define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX) >+ >+/* how many counters per page? */ >+#define PAGE_COUNTER_RATIO (PAGE_BITS / COUNTER_BITS) >+/* same, except a shift value for more efficient bitops */ >+#define PAGE_COUNTER_SHIFT (PAGE_BIT_SHIFT - COUNTER_BIT_SHIFT) >+/* same, except a mask value for more efficient bitops */ >+#define PAGE_COUNTER_MASK (PAGE_COUNTER_RATIO - 1) >+ >+#define BITMAP_BLOCK_SIZE 512 >+#define BITMAP_BLOCK_SHIFT 9 >+ >+/* how many blocks per chunk? (this is variable) */ >+#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->chunksize >> BITMAP_BLOCK_SHIFT) >+#define CHUNK_BLOCK_SHIFT(bitmap) ((bitmap)->chunkshift - BITMAP_BLOCK_SHIFT) >+#define CHUNK_BLOCK_MASK(bitmap) (CHUNK_BLOCK_RATIO(bitmap) - 1) >+ >+/* when hijacked, the counters and bits represent even larger "chunks" */ >+/* there will be 1024 chunks represented by each counter in the page pointers */ >+#define PAGEPTR_BLOCK_RATIO(bitmap) \ >+ (CHUNK_BLOCK_RATIO(bitmap) << PAGE_COUNTER_SHIFT >> 1) >+#define PAGEPTR_BLOCK_SHIFT(bitmap) \ >+ (CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1) >+#define PAGEPTR_BLOCK_MASK(bitmap) (PAGEPTR_BLOCK_RATIO(bitmap) - 1) >+ >+/* >+ * on-disk bitmap: >+ * >+ * Use one bit per "chunk" (block set). We do the disk I/O on the bitmap >+ * file a page at a time. There's a superblock at the start of the file. >+ */ >+ >+/* map chunks (bits) to file pages - offset by the size of the superblock */ >+#define CHUNK_BIT_OFFSET(chunk) ((chunk) + (sizeof(bitmap_super_t) << 3)) >+ >+#endif >+ >+/* >+ * bitmap structures: >+ */ >+ >+#define BITMAP_MAGIC 0x6d746962 >+ >+/* use these for bitmap->flags and bitmap->sb->state bit-fields */ >+enum bitmap_state { >+ BITMAP_ACTIVE = 0x001, /* the bitmap is in use */ >+ BITMAP_STALE = 0x002 /* the bitmap file is out of date or had -EIO */ >+}; >+ >+/* the superblock at the front of the bitmap file -- little endian */ >+typedef struct bitmap_super_s { >+ __u32 magic; /* 0 BITMAP_MAGIC */ >+ __u32 version; /* 4 the bitmap major for now, could change... */ >+ __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */ >+ __u64 events; /* 24 event counter for the bitmap (1)*/ >+ __u64 events_cleared;/*32 event counter when last bit cleared (2) */ >+ __u64 sync_size; /* 40 the size of the md device's sync range(3) */ >+ __u32 state; /* 48 bitmap state information */ >+ __u32 chunksize; /* 52 the bitmap chunk size in bytes */ >+ __u32 daemon_sleep; /* 56 seconds between disk flushes */ >+ __u32 write_behind; /* 60 number of outstanding write-behind writes */ >+ >+ __u8 pad[256 - 64]; /* set to zero */ >+} bitmap_super_t; >+ >+/* notes: >+ * (1) This event counter is updated before the eventcounter in the md superblock >+ * When a bitmap is loaded, it is only accepted if this event counter is equal >+ * to, or one greater than, the event counter in the superblock. >+ * (2) This event counter is updated when the other one is *if*and*only*if* the >+ * array is not degraded. As bits are not cleared when the array is degraded, >+ * this represents the last time that any bits were cleared. >+ * If a device is being added that has an event count with this value or >+ * higher, it is accepted as conforming to the bitmap. >+ * (3)This is the number of sectors represented by the bitmap, and is the range that >+ * resync happens across. For raid1 and raid5/6 it is the size of individual >+ * devices. For raid10 it is the size of the array. >+ */ >+ >+#ifdef __KERNEL__ >+ >+/* the in-memory bitmap is represented by bitmap_pages */ >+struct bitmap_page { >+ /* >+ * map points to the actual memory page >+ */ >+ char *map; >+ /* >+ * in emergencies (when map cannot be alloced), hijack the map >+ * pointer and use it as two counters itself >+ */ >+ unsigned int hijacked; >+ /* >+ * count of dirty bits on the page >+ */ >+ int count; >+}; >+ >+/* keep track of bitmap file pages that have pending writes on them */ >+struct page_list { >+ struct list_head list; >+ struct page *page; >+}; >+ >+/* the main bitmap structure - one per mddev */ >+struct bitmap { >+ struct bitmap_page *bp; >+ unsigned long pages; /* total number of pages in the bitmap */ >+ unsigned long missing_pages; /* number of pages not yet allocated */ >+ >+ mddev_t *mddev; /* the md device that the bitmap is for */ >+ >+ int counter_bits; /* how many bits per block counter */ >+ >+ /* bitmap chunksize -- how much data does each bit represent? */ >+ unsigned long chunksize; >+ unsigned long chunkshift; /* chunksize = 2^chunkshift (for bitops) */ >+ unsigned long chunks; /* total number of data chunks for the array */ >+ >+ /* We hold a count on the chunk currently being synced, and drop >+ * it when the last block is started. If the resync is aborted >+ * midway, we need to be able to drop that count, so we remember >+ * the counted chunk.. >+ */ >+ unsigned long syncchunk; >+ >+ __u64 events_cleared; >+ >+ /* bitmap spinlock */ >+ spinlock_t lock; >+ >+ struct file *file; /* backing disk file */ >+ struct page *sb_page; /* cached copy of the bitmap file superblock */ >+ struct page **filemap; /* list of cache pages for the file */ >+ unsigned long *filemap_attr; /* attributes associated w/ filemap pages */ >+ unsigned long file_pages; /* number of pages in the file */ >+ >+ unsigned long flags; >+ >+ /* >+ * the bitmap daemon - periodically wakes up and sweeps the bitmap >+ * file, cleaning up bits and flushing out pages to disk as necessary >+ */ >+ mdk_thread_t *daemon; >+ unsigned long daemon_sleep; /* how many seconds between updates? */ >+ >+ /* >+ * bitmap write daemon - this daemon performs writes to the bitmap file >+ * this thread is only needed because of a limitation in ext3 (jbd) >+ * that does not allow a task to have two journal transactions ongoing >+ * simultaneously (even if the transactions are for two different >+ * filesystems) -- in the case of bitmap, that would be the filesystem >+ * that the bitmap file resides on and the filesystem that is mounted >+ * on the md device -- see current->journal_info in jbd/transaction.c >+ */ >+ mdk_thread_t *write_daemon; >+ mdk_thread_t *writeback_daemon; >+ spinlock_t write_lock; >+ struct semaphore write_ready; >+ struct semaphore write_done; >+ unsigned long writes_pending; >+ wait_queue_head_t write_wait; >+ struct list_head write_pages; >+ struct list_head complete_pages; >+ mempool_t *write_pool; >+}; >+ >+/* the bitmap API */ >+ >+/* these are used only by md/bitmap */ >+int bitmap_create(mddev_t *mddev); >+void bitmap_destroy(mddev_t *mddev); >+int bitmap_active(struct bitmap *bitmap); >+ >+char *file_path(struct file *file, char *buf, int count); >+void bitmap_print_sb(struct bitmap *bitmap); >+int bitmap_update_sb(struct bitmap *bitmap); >+ >+int bitmap_setallbits(struct bitmap *bitmap); >+ >+/* these are exported */ >+void bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors); >+void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, >+ int success); >+int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks); >+void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); >+void bitmap_close_sync(struct bitmap *bitmap); >+ >+int bitmap_unplug(struct bitmap *bitmap); >+#endif >+ >+#endif >diff -pruN a/mdadm/config.c mdadm/mdadm/config.c >--- a/mdadm/config.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/config.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,824 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * Paper: Neil Brown >+ * School of Computer Science and Engineering >+ * The University of New South Wales >+ * Sydney, 2052 >+ * Australia >+ */ >+ >+#include "mdadm.h" >+#include "dlink.h" >+#include <sys/dir.h> >+#include <glob.h> >+#include <fnmatch.h> >+#include <ctype.h> >+#include <pwd.h> >+#include <grp.h> >+ >+mapping_t r5layout[] = { >+ { "left-asymmetric", 0}, >+ { "right-asymmetric", 1}, >+ { "left-symmetric", 2}, >+ { "right-symmetric", 3}, >+ >+ { "default", 2}, >+ { "la", 0}, >+ { "ra", 1}, >+ { "ls", 2}, >+ { "rs", 3}, >+ { NULL, 0} >+}; >+ >+mapping_t pers[] = { >+ { "linear", -1}, >+ { "raid0", 0}, >+ { "0", 0}, >+ { "stripe", 0}, >+ { "raid1", 1}, >+ { "1", 1}, >+ { "mirror", 1}, >+ { "raid4", 4}, >+ { "4", 4}, >+ { "raid5", 5}, >+ { "5", 5}, >+ { "multipath", -4}, >+ { "mp", -4}, >+ { "raid6", 6}, >+ { "6", 6}, >+ { "raid10", 10}, >+ { "10", 10}, >+ { "faulty", -5}, >+ { NULL, 0} >+}; >+/* >+ * Read the config file >+ * >+ * conf_get_uuids gets a list of devicename+uuid pairs >+ * conf_get_devs gets device names after expanding wildcards >+ * >+ * Each keeps the returned list and frees it when asked to make >+ * a new list. >+ * >+ * The format of the config file needs to be fairly extensible. >+ * Now, arrays only have names and uuids and devices merely are. >+ * But later arrays might want names, and devices might want superblock >+ * versions, and who knows what else. >+ * I like free format, abhore backslash line continuation, adore >+ * indentation for structure and am ok about # comments. >+ * >+ * So, each line that isn't blank or a #comment must either start >+ * with a key word, and not be indented, or must start with a >+ * non-key-word and must be indented. >+ * >+ * Keywords are DEVICE and ARRAY >+ * DEV{ICE} introduces some devices that might contain raid components. >+ * e.g. >+ * DEV style=0 /dev/sda* /dev/hd* >+ * DEV style=1 /dev/sd[b-f]* >+ * ARR{AY} describes an array giving md device and attributes like uuid=whatever >+ * e.g. >+ * ARRAY /dev/md0 uuid=whatever name=something >+ * Spaces separate words on each line. Quoting, with "" or '' protects them, >+ * but may not wrap over lines >+ * >+ */ >+ >+#ifndef CONFFILE >+#define CONFFILE "/etc/mdadm.conf" >+#endif >+#ifndef CONFFILE2 >+/* for Debian compatibility .... */ >+#define CONFFILE2 "/etc/mdadm/mdadm.conf" >+#endif >+char DefaultConfFile[] = CONFFILE; >+char DefaultAltConfFile[] = CONFFILE2; >+ >+enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev, Homehost, LTEnd }; >+char *keywords[] = { >+ [Devices] = "devices", >+ [Array] = "array", >+ [Mailaddr] = "mailaddr", >+ [Mailfrom] = "mailfrom", >+ [Program] = "program", >+ [CreateDev]= "create", >+ [Homehost] = "homehost", >+ [LTEnd] = NULL >+}; >+ >+/* >+ * match_keyword returns an index into the keywords array, or -1 for no match >+ * case is ignored, and at least three characters must be given >+ */ >+ >+int match_keyword(char *word) >+{ >+ int len = strlen(word); >+ int n; >+ >+ if (len < 3) return -1; >+ for (n=0; keywords[n]; n++) { >+ if (strncasecmp(word, keywords[n], len)==0) >+ return n; >+ } >+ return -1; >+} >+ >+/* conf_word gets one word from the conf file. >+ * if "allow_key", then accept words at the start of a line, >+ * otherwise stop when such a word is found. >+ * We assume that the file pointer is at the end of a word, so the >+ * next character is a space, or a newline. If not, it is the start of a line. >+ */ >+ >+char *conf_word(FILE *file, int allow_key) >+{ >+ int wsize = 100; >+ int len = 0; >+ int c; >+ int quote; >+ int wordfound = 0; >+ char *word = malloc(wsize); >+ >+ if (!word) abort(); >+ >+ while (wordfound==0) { >+ /* at the end of a word.. */ >+ c = getc(file); >+ if (c == '#') >+ while (c != EOF && c != '\n') >+ c = getc(file); >+ if (c == EOF) break; >+ if (c == '\n') continue; >+ >+ if (c != ' ' && c != '\t' && ! allow_key) { >+ ungetc(c, file); >+ break; >+ } >+ /* looks like it is safe to get a word here, if there is one */ >+ quote = 0; >+ /* first, skip any spaces */ >+ while (c == ' ' || c == '\t') >+ c = getc(file); >+ if (c != EOF && c != '\n' && c != '#') { >+ /* we really have a character of a word, so start saving it */ >+ while (c != EOF && c != '\n' && (quote || (c!=' ' && c != '\t'))) { >+ wordfound = 1; >+ if (quote && c == quote) quote = 0; >+ else if (quote == 0 && (c == '\'' || c == '"')) >+ quote = c; >+ else { >+ if (len == wsize-1) { >+ wsize += 100; >+ word = realloc(word, wsize); >+ if (!word) abort(); >+ } >+ word[len++] = c; >+ } >+ c = getc(file); >+ } >+ } >+ if (c != EOF) ungetc(c, file); >+ } >+ word[len] = 0; >+/* printf("word is <%s>\n", word); */ >+ if (!wordfound) { >+ free(word); >+ word = NULL; >+ } >+ return word; >+} >+ >+/* >+ * conf_line reads one logical line from the conffile. >+ * It skips comments and continues until it finds a line that starts >+ * with a non blank/comment. This character is pushed back for the next call >+ * A doubly linked list of words is returned. >+ * the first word will be a keyword. Other words will have had quotes removed. >+ */ >+ >+char *conf_line(FILE *file) >+{ >+ char *w; >+ char *list; >+ >+ w = conf_word(file, 1); >+ if (w == NULL) return NULL; >+ >+ list = dl_strdup(w); >+ free(w); >+ dl_init(list); >+ >+ while ((w = conf_word(file,0))){ >+ char *w2 = dl_strdup(w); >+ free(w); >+ dl_add(list, w2); >+ } >+/* printf("got a line\n");*/ >+ return list; >+} >+ >+void free_line(char *line) >+{ >+ char *w; >+ for (w=dl_next(line); w != line; w=dl_next(line)) { >+ dl_del(w); >+ dl_free(w); >+ } >+ dl_free(line); >+} >+ >+ >+struct conf_dev { >+ struct conf_dev *next; >+ char *name; >+} *cdevlist = NULL; >+ >+mddev_dev_t load_partitions(void) >+{ >+ FILE *f = fopen("/proc/partitions", "r"); >+ char buf[1024]; >+ mddev_dev_t rv = NULL; >+ if (f == NULL) { >+ fprintf(stderr, Name ": cannot open /proc/partitions\n"); >+ return NULL; >+ } >+ while (fgets(buf, 1024, f)) { >+ int major, minor; >+ char *name, *mp; >+ mddev_dev_t d; >+ >+ buf[1023] = '\0'; >+ if (buf[0] != ' ') >+ continue; >+ major = strtoul(buf, &mp, 10); >+ if (mp == buf || *mp != ' ') >+ continue; >+ minor = strtoul(mp, NULL, 10); >+ >+ name = map_dev(major, minor, 1); >+ if (!name) >+ continue; >+ d = malloc(sizeof(*d)); >+ d->devname = strdup(name); >+ d->next = rv; >+ d->used = 0; >+ rv = d; >+ } >+ fclose(f); >+ return rv; >+} >+ >+struct createinfo createinfo = { >+ .autof = 2, /* by default, create devices with standard names */ >+ .symlinks = 1, >+#ifdef DEBIAN >+ .gid = 6, /* disk */ >+ .mode = 0660, >+#else >+ .mode = 0600, >+#endif >+}; >+ >+int parse_auto(char *str, char *msg, int config) >+{ >+ int autof; >+ if (str == NULL || *str == 0) >+ autof = 2; >+ else if (strcasecmp(str,"no")==0) >+ autof = 1; >+ else if (strcasecmp(str,"yes")==0) >+ autof = 2; >+ else if (strcasecmp(str,"md")==0) >+ autof = config?5:3; >+ else { >+ /* There might be digits, and maybe a hypen, at the end */ >+ char *e = str + strlen(str); >+ int num = 4; >+ int len; >+ while (e > str && isdigit(e[-1])) >+ e--; >+ if (*e) { >+ num = atoi(e); >+ if (num <= 0) num = 1; >+ } >+ if (e > str && e[-1] == '-') >+ e--; >+ len = e - str; >+ if ((len == 2 && strncasecmp(str,"md",2)==0)) { >+ autof = config ? 5 : 3; >+ } else if ((len == 3 && strncasecmp(str,"yes",3)==0)) { >+ autof = 2; >+ } else if ((len == 3 && strncasecmp(str,"mdp",3)==0)) { >+ autof = config ? 6 : 4; >+ } else if ((len == 1 && strncasecmp(str,"p",1)==0) || >+ (len >= 4 && strncasecmp(str,"part",4)==0)) { >+ autof = 6; >+ } else { >+ fprintf(stderr, Name ": %s arg of \"%s\" unrecognised: use no,yes,md,mdp,part\n" >+ " optionally followed by a number.\n", >+ msg, str); >+ exit(2); >+ } >+ autof |= num << 3; >+ } >+ return autof; >+} >+ >+static void createline(char *line) >+{ >+ char *w; >+ char *ep; >+ >+ for (w=dl_next(line); w!=line; w=dl_next(w)) { >+ if (strncasecmp(w, "auto=", 5) == 0) >+ createinfo.autof = parse_auto(w+5, "auto=", 1); >+ else if (strncasecmp(w, "owner=", 6) == 0) { >+ if (w[6] == 0) { >+ fprintf(stderr, Name ": missing owner name\n"); >+ continue; >+ } >+ createinfo.uid = strtoul(w+6, &ep, 10); >+ if (*ep != 0) { >+ struct passwd *pw; >+ /* must be a name */ >+ pw = getpwnam(w+6); >+ if (pw) >+ createinfo.uid = pw->pw_uid; >+ else >+ fprintf(stderr, Name ": CREATE user %s not found\n", w+6); >+ } >+ } else if (strncasecmp(w, "group=", 6) == 0) { >+ if (w[6] == 0) { >+ fprintf(stderr, Name ": missing group name\n"); >+ continue; >+ } >+ createinfo.gid = strtoul(w+6, &ep, 10); >+ if (*ep != 0) { >+ struct group *gr; >+ /* must be a name */ >+ gr = getgrnam(w+6); >+ if (gr) >+ createinfo.gid = gr->gr_gid; >+ else >+ fprintf(stderr, Name ": CREATE group %s not found\n", w+6); >+ } >+ } else if (strncasecmp(w, "mode=", 5) == 0) { >+ if (w[5] == 0) { >+ fprintf(stderr, Name ": missing CREATE mode\n"); >+ continue; >+ } >+ createinfo.mode = strtoul(w+5, &ep, 8); >+ if (*ep != 0) { >+ createinfo.mode = 0600; >+ fprintf(stderr, Name ": unrecognised CREATE mode %s\n", >+ w+5); >+ } >+ } else if (strncasecmp(w, "metadata=", 9) == 0) { >+ /* style of metadata to use by default */ >+ int i; >+ for (i=0; superlist[i] && !createinfo.supertype; i++) >+ createinfo.supertype = >+ superlist[i]->match_metadata_desc(w+9); >+ if (!createinfo.supertype) >+ fprintf(stderr, Name ": metadata format %s unknown, ignoring\n", >+ w+9); >+ } else if (strncasecmp(w, "symlinks=yes", 12) == 0) >+ createinfo.symlinks = 1; >+ else if (strncasecmp(w, "symlinks=no", 11) == 0) >+ createinfo.symlinks = 0; >+ else { >+ fprintf(stderr, Name ": unrecognised word on CREATE line: %s\n", >+ w); >+ } >+ } >+} >+ >+void devline(char *line) >+{ >+ char *w; >+ struct conf_dev *cd; >+ >+ for (w=dl_next(line); w != line; w=dl_next(w)) { >+ if (w[0] == '/' || strcasecmp(w, "partitions") == 0) { >+ cd = malloc(sizeof(*cd)); >+ cd->name = strdup(w); >+ cd->next = cdevlist; >+ cdevlist = cd; >+ } else { >+ fprintf(stderr, Name ": unreconised word on DEVICE line: %s\n", >+ w); >+ } >+ } >+} >+ >+mddev_ident_t mddevlist = NULL; >+mddev_ident_t *mddevlp = &mddevlist; >+ >+void arrayline(char *line) >+{ >+ char *w; >+ >+ struct mddev_ident_s mis; >+ mddev_ident_t mi; >+ >+ mis.uuid_set = 0; >+ mis.super_minor = UnSet; >+ mis.level = UnSet; >+ mis.raid_disks = UnSet; >+ mis.spare_disks = 0; >+ mis.devices = NULL; >+ mis.devname = NULL; >+ mis.spare_group = NULL; >+ mis.autof = 0; >+ mis.next = NULL; >+ mis.st = NULL; >+ mis.bitmap_fd = -1; >+ mis.bitmap_file = NULL; >+ mis.name[0] = 0; >+ >+ for (w=dl_next(line); w!=line; w=dl_next(w)) { >+ if (w[0] == '/') { >+ if (mis.devname) >+ fprintf(stderr, Name ": only give one device per ARRAY line: %s and %s\n", >+ mis.devname, w); >+ else mis.devname = w; >+ } else if (strncasecmp(w, "uuid=", 5)==0 ) { >+ if (mis.uuid_set) >+ fprintf(stderr, Name ": only specify uuid once, %s ignored.\n", >+ w); >+ else { >+ if (parse_uuid(w+5, mis.uuid)) >+ mis.uuid_set = 1; >+ else >+ fprintf(stderr, Name ": bad uuid: %s\n", w); >+ } >+ } else if (strncasecmp(w, "super-minor=", 12)==0 ) { >+ if (mis.super_minor != UnSet) >+ fprintf(stderr, Name ": only specify super-minor once, %s ignored.\n", >+ w); >+ else { >+ char *endptr; >+ mis.super_minor= strtol(w+12, &endptr, 10); >+ if (w[12]==0 || endptr[0]!=0 || mis.super_minor < 0) { >+ fprintf(stderr, Name ": invalid super-minor number: %s\n", >+ w); >+ mis.super_minor = UnSet; >+ } >+ } >+ } else if (strncasecmp(w, "name=", 5)==0) { >+ if (mis.name[0]) >+ fprintf(stderr, Name ": only specify name once, %s ignored.\n", >+ w); >+ else if (strlen(w+5) > 32) >+ fprintf(stderr, Name ": name too long, ignoring %s\n", w); >+ else >+ strcpy(mis.name, w+5); >+ >+ } else if (strncasecmp(w, "bitmap=", 7) == 0) { >+ if (mis.bitmap_file) >+ fprintf(stderr, Name ": only specify bitmap file once. %s ignored\n", >+ w); >+ else >+ mis.bitmap_file = strdup(w+7); >+ >+ } else if (strncasecmp(w, "devices=", 8 ) == 0 ) { >+ if (mis.devices) >+ fprintf(stderr, Name ": only specify devices once (use a comma separated list). %s ignored\n", >+ w); >+ else >+ mis.devices = strdup(w+8); >+ } else if (strncasecmp(w, "spare-group=", 12) == 0 ) { >+ if (mis.spare_group) >+ fprintf(stderr, Name ": only specify one spare group per array. %s ignored.\n", >+ w); >+ else >+ mis.spare_group = strdup(w+12); >+ } else if (strncasecmp(w, "level=", 6) == 0 ) { >+ /* this is mainly for compatability with --brief output */ >+ mis.level = map_name(pers, w+6); >+ } else if (strncasecmp(w, "disks=", 6) == 0 ) { >+ /* again, for compat */ >+ mis.raid_disks = atoi(w+6); >+ } else if (strncasecmp(w, "num-devices=", 12) == 0 ) { >+ /* again, for compat */ >+ mis.raid_disks = atoi(w+12); >+ } else if (strncasecmp(w, "spares=", 7) == 0 ) { >+ /* for warning if not all spares present */ >+ mis.spare_disks = atoi(w+7); >+ } else if (strncasecmp(w, "metadata=", 9) == 0) { >+ /* style of metadata on the devices. */ >+ int i; >+ >+ for(i=0; superlist[i] && !mis.st; i++) >+ mis.st = superlist[i]->match_metadata_desc(w+9); >+ >+ if (!mis.st) >+ fprintf(stderr, Name ": metadata format %s unknown, ignored.\n", w+9); >+ } else if (strncasecmp(w, "auto=", 5) == 0 ) { >+ /* whether to create device special files as needed */ >+ mis.autof = parse_auto(w+5, "auto type", 0); >+ } else { >+ fprintf(stderr, Name ": unrecognised word on ARRAY line: %s\n", >+ w); >+ } >+ } >+ if (mis.devname == NULL) >+ fprintf(stderr, Name ": ARRAY line with no device\n"); >+ else if (mis.uuid_set == 0 && mis.devices == NULL && mis.super_minor == UnSet && mis.name[0] == 0) >+ fprintf(stderr, Name ": ARRAY line %s has no identity information.\n", mis.devname); >+ else { >+ mi = malloc(sizeof(*mi)); >+ *mi = mis; >+ mi->devname = strdup(mis.devname); >+ mi->next = NULL; >+ *mddevlp = mi; >+ mddevlp = &mi->next; >+ } >+} >+ >+static char *alert_email = NULL; >+void mailline(char *line) >+{ >+ char *w; >+ >+ for (w=dl_next(line); w != line ; w=dl_next(w)) { >+ if (alert_email == NULL) >+ alert_email = strdup(w); >+ else >+ fprintf(stderr, Name ": excess address on MAIL line: %s - ignored\n", >+ w); >+ } >+} >+ >+static char *alert_mail_from = NULL; >+void mailfromline(char *line) >+{ >+ char *w; >+ >+ for (w=dl_next(line); w != line ; w=dl_next(w)) { >+ if (alert_mail_from == NULL) >+ alert_mail_from = strdup(w); >+ else { >+ char *t= NULL; >+ asprintf(&t, "%s %s", alert_mail_from, w); >+ free(alert_mail_from); >+ alert_mail_from = t; >+ } >+ } >+} >+ >+ >+static char *alert_program = NULL; >+void programline(char *line) >+{ >+ char *w; >+ >+ for (w=dl_next(line); w != line ; w=dl_next(w)) { >+ if (alert_program == NULL) >+ alert_program = strdup(w); >+ else >+ fprintf(stderr, Name ": excess program on PROGRAM line: %s - ignored\n", >+ w); >+ } >+} >+ >+static char *home_host = NULL; >+void homehostline(char *line) >+{ >+ char *w; >+ >+ for (w=dl_next(line); w != line ; w=dl_next(w)) { >+ if (home_host == NULL) >+ home_host = strdup(w); >+ else >+ fprintf(stderr, Name ": excess host name on HOMEHOST line: %s - ignored\n", >+ w); >+ } >+} >+ >+ >+int loaded = 0; >+ >+static char *conffile = NULL; >+void set_conffile(char *file) >+{ >+ conffile = file; >+} >+ >+void load_conffile(void) >+{ >+ FILE *f; >+ char *line; >+ >+ if (loaded) return; >+ if (conffile == NULL) >+ conffile = DefaultConfFile; >+ >+ if (strcmp(conffile, "none") == 0) { >+ loaded = 1; >+ return; >+ } >+ if (strcmp(conffile, "partitions")==0) { >+ char *list = dl_strdup("DEV"); >+ dl_init(list); >+ dl_add(list, dl_strdup("partitions")); >+ devline(list); >+ free_line(list); >+ loaded = 1; >+ return; >+ } >+ f = fopen(conffile, "r"); >+ /* Debian chose to relocate mdadm.conf into /etc/mdadm/. >+ * To allow Debian users to compile from clean source and still >+ * have a working mdadm, we read /etc/mdadm/mdadm.conf >+ * if /etc/mdadm.conf doesn't exist >+ */ >+ if (f == NULL && >+ conffile == DefaultConfFile) { >+ f = fopen(DefaultAltConfFile, "r"); >+ if (f) >+ conffile = DefaultAltConfFile; >+ } >+ if (f == NULL) >+ return; >+ >+ loaded = 1; >+ while ((line=conf_line(f))) { >+ switch(match_keyword(line)) { >+ case Devices: >+ devline(line); >+ break; >+ case Array: >+ arrayline(line); >+ break; >+ case Mailaddr: >+ mailline(line); >+ break; >+ case Mailfrom: >+ mailfromline(line); >+ break; >+ case Program: >+ programline(line); >+ break; >+ case CreateDev: >+ createline(line); >+ break; >+ case Homehost: >+ homehostline(line); >+ break; >+ default: >+ fprintf(stderr, Name ": Unknown keyword %s\n", line); >+ } >+ free_line(line); >+ } >+ >+ fclose(f); >+ >+/* printf("got file\n"); */ >+} >+ >+char *conf_get_mailaddr(void) >+{ >+ load_conffile(); >+ return alert_email; >+} >+ >+char *conf_get_mailfrom(void) >+{ >+ load_conffile(); >+ return alert_mail_from; >+} >+ >+char *conf_get_program(void) >+{ >+ load_conffile(); >+ return alert_program; >+} >+ >+char *conf_get_homehost(void) >+{ >+ load_conffile(); >+ return home_host; >+} >+ >+struct createinfo *conf_get_create_info(void) >+{ >+ load_conffile(); >+ return &createinfo; >+} >+ >+mddev_ident_t conf_get_ident(char *dev) >+{ >+ mddev_ident_t rv; >+ load_conffile(); >+ rv = mddevlist; >+ while (dev && rv && strcmp(dev, rv->devname)!=0) >+ rv = rv->next; >+ return rv; >+} >+ >+mddev_dev_t conf_get_devs() >+{ >+ glob_t globbuf; >+ struct conf_dev *cd; >+ int flags = 0; >+ static mddev_dev_t dlist = NULL; >+ unsigned int i; >+ >+ while (dlist) { >+ mddev_dev_t t = dlist; >+ dlist = dlist->next; >+ free(t->devname); >+ free(t); >+ } >+ >+ load_conffile(); >+ >+ if (cdevlist == NULL) >+ /* default to 'partitions */ >+ dlist = load_partitions(); >+ >+ for (cd=cdevlist; cd; cd=cd->next) { >+ if (strcasecmp(cd->name, "partitions")==0 && dlist == NULL) >+ dlist = load_partitions(); >+ else { >+ glob(cd->name, flags, NULL, &globbuf); >+ flags |= GLOB_APPEND; >+ } >+ } >+ if (flags & GLOB_APPEND) { >+ for (i=0; i<globbuf.gl_pathc; i++) { >+ mddev_dev_t t = malloc(sizeof(*t)); >+ t->devname = strdup(globbuf.gl_pathv[i]); >+ t->next = dlist; >+ t->used = 0; >+ dlist = t; >+/* printf("one dev is %s\n", t->devname);*/ >+ } >+ globfree(&globbuf); >+ } >+ >+ return dlist; >+} >+ >+int conf_test_dev(char *devname) >+{ >+ struct conf_dev *cd; >+ if (cdevlist == NULL) >+ /* allow anything by default */ >+ return 1; >+ for (cd = cdevlist ; cd ; cd = cd->next) { >+ if (strcasecmp(cd->name, "partitions") == 0) >+ return 1; >+ if (fnmatch(cd->name, devname, FNM_PATHNAME) == 0) >+ return 1; >+ } >+ return 0; >+} >+ >+ >+int match_oneof(char *devices, char *devname) >+{ >+ /* check if one of the comma separated patterns in devices >+ * matches devname >+ */ >+ >+ >+ while (devices && *devices) { >+ char patn[1024]; >+ char *p = devices; >+ devices = strchr(devices, ','); >+ if (!devices) >+ devices = p + strlen(p); >+ if (devices-p < 1024) { >+ strncpy(patn, p, devices-p); >+ patn[devices-p] = 0; >+ if (fnmatch(patn, devname, FNM_PATHNAME)==0) >+ return 1; >+ } >+ if (*devices == ',') >+ devices++; >+ } >+ return 0; >+} >--- a/mdadm/Config.in 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/Config.in 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,15 @@ >+# >+# For a description of the syntax of this configuration file, >+# see scripts/kbuild/config-language.txt. >+# >+ >+menu "Linux mdadm Utilities" >+ >+config MDADM >+ bool "mdadm" >+ default n >+ help >+ assemble or examine raid array >+ >+endmenu >+ >--- a/mdadm/dlink.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/dlink.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,79 @@ >+ >+/* doubly linked lists */ >+/* This is free software. No strings attached. No copyright claimed */ >+ >+#include <unistd.h> >+#include <stdlib.h> >+#include <string.h> >+#ifdef __dietlibc__ >+char *strncpy(char *dest, const char *src, size_t n) __THROW; >+#endif >+#include "dlink.h" >+ >+ >+void *dl_head() >+{ >+ void *h; >+ h = dl_alloc(0); >+ dl_next(h) = h; >+ dl_prev(h) = h; >+ return h; >+} >+ >+void dl_free(void *v) >+{ >+ struct __dl_head *vv = v; >+ free(vv-1); >+} >+ >+void dl_init(void *v) >+{ >+ dl_next(v) = v; >+ dl_prev(v) = v; >+} >+ >+void dl_insert(void *head, void *val) >+{ >+ dl_next(val) = dl_next(head); >+ dl_prev(val) = head; >+ dl_next(dl_prev(val)) = val; >+ dl_prev(dl_next(val)) = val; >+} >+ >+void dl_add(void *head, void *val) >+{ >+ dl_prev(val) = dl_prev(head); >+ dl_next(val) = head; >+ dl_next(dl_prev(val)) = val; >+ dl_prev(dl_next(val)) = val; >+} >+ >+void dl_del(void *val) >+{ >+ if (dl_prev(val) == 0 || dl_next(val) == 0) >+ return; >+ dl_prev(dl_next(val)) = dl_prev(val); >+ dl_next(dl_prev(val)) = dl_next(val); >+ dl_prev(val) = dl_next(val) = 0; >+} >+ >+char *dl_strndup(char *s, int l) >+{ >+ char *n; >+ if (s == NULL) >+ return NULL; >+ n = dl_newv(char, l+1); >+ if (n == NULL) >+ return NULL; >+ else >+ { >+ strncpy(n, s, l); >+ n[l] = 0; >+ return n; >+ } >+} >+ >+char *dl_strdup(char *s) >+{ >+ return dl_strndup(s, (int)strlen(s)); >+} >--- a/mdadm/dlink.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/dlink.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,25 @@ >+ >+/* doubley linked lists */ >+/* This is free software. No strings attached. No copyright claimed */ >+ >+struct __dl_head >+{ >+ void * dh_prev; >+ void * dh_next; >+}; >+ >+#define dl_alloc(size) ((void*)(((char*)calloc(1,(size)+sizeof(struct __dl_head)))+sizeof(struct __dl_head))) >+#define dl_new(t) ((t*)dl_alloc(sizeof(t))) >+#define dl_newv(t,n) ((t*)dl_alloc(sizeof(t)*n)) >+ >+#define dl_next(p) *(&(((struct __dl_head*)(p))[-1].dh_next)) >+#define dl_prev(p) *(&(((struct __dl_head*)(p))[-1].dh_prev)) >+ >+void *dl_head(void); >+char *dl_strdup(char *); >+char *dl_strndup(char *, int); >+void dl_insert(void*, void*); >+void dl_add(void*, void*); >+void dl_del(void*); >+void dl_free(void*); >+void dl_init(void*); >--- a/mdadm/Kbuild 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/Kbuild 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,9 @@ >+# Makefile for busybox >+# >+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> >+# >+# Licensed under the GPL v2, see the file LICENSE in this tarball. >+ >+lib-y:= >+MDADM-y:= config.o util.o dlink.o sha1.o super0.o super1.o mdexamine.o mdassemble.o >+lib-$(CONFIG_MDADM) += mdadm.o $(MDADM-y) >--- a/mdadm/md5.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/md5.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,134 @@ >+/* Declaration of functions and data types used for MD5 sum computing >+ library functions. >+ Copyright (C) 1995-1997,1999-2005 Free Software Foundation, Inc. >+ >+ NOTE: The canonical source of this file is maintained with the GNU C >+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. >+ >+ 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. >+ >+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ >+ >+#ifndef _MD5_H >+#define _MD5_H 1 >+ >+#include <stdio.h> >+ >+# include <inttypes.h> >+#if HAVE_STDINT_H || _LIBC >+# include <stdint.h> >+#endif >+ >+#ifndef __GNUC_PREREQ >+# if defined __GNUC__ && defined __GNUC_MINOR__ >+# define __GNUC_PREREQ(maj, min) \ >+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) >+# else >+# define __GNUC_PREREQ(maj, min) 0 >+# endif >+#endif >+ >+#ifndef __THROW >+# if defined __cplusplus && __GNUC_PREREQ (2,8) >+# define __THROW throw () >+# else >+# define __THROW >+# endif >+#endif >+ >+#ifndef __attribute__ >+# if ! __GNUC_PREREQ (2,8) || __STRICT_ANSI__ >+# define __attribute__(x) >+# endif >+#endif >+ >+#ifndef _LIBC >+# define __md5_buffer md5_buffer >+# define __md5_finish_ctx md5_finish_ctx >+# define __md5_init_ctx md5_init_ctx >+# define __md5_process_block md5_process_block >+# define __md5_process_bytes md5_process_bytes >+# define __md5_read_ctx md5_read_ctx >+# define __md5_stream md5_stream >+#endif >+ >+typedef uint32_t md5_uint32; >+ >+/* Structure to save state of computation between the single steps. */ >+struct md5_ctx >+{ >+ md5_uint32 A; >+ md5_uint32 B; >+ md5_uint32 C; >+ md5_uint32 D; >+ >+ md5_uint32 total[2]; >+ md5_uint32 buflen; >+ char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); >+}; >+ >+/* >+ * The following three functions are build up the low level used in >+ * the functions `md5_stream' and `md5_buffer'. >+ */ >+ >+/* Initialize structure containing state of computation. >+ (RFC 1321, 3.3: Step 3) */ >+extern void __md5_init_ctx (struct md5_ctx *ctx) __THROW; >+ >+/* Starting with the result of former calls of this function (or the >+ initialization function update the context for the next LEN bytes >+ starting at BUFFER. >+ It is necessary that LEN is a multiple of 64!!! */ >+extern void __md5_process_block (const void *buffer, size_t len, >+ struct md5_ctx *ctx) __THROW; >+ >+/* Starting with the result of former calls of this function (or the >+ initialization function update the context for the next LEN bytes >+ starting at BUFFER. >+ It is NOT required that LEN is a multiple of 64. */ >+extern void __md5_process_bytes (const void *buffer, size_t len, >+ struct md5_ctx *ctx) __THROW; >+ >+/* Process the remaining bytes in the buffer and put result from CTX >+ in first 16 bytes following RESBUF. The result is always in little >+ endian byte order, so that a byte-wise output yields to the wanted >+ ASCII representation of the message digest. >+ >+ IMPORTANT: On some systems it is required that RESBUF be correctly >+ aligned for a 32 bits value. */ >+extern void *__md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) __THROW; >+ >+ >+/* Put result from CTX in first 16 bytes following RESBUF. The result is >+ always in little endian byte order, so that a byte-wise output yields >+ to the wanted ASCII representation of the message digest. >+ >+ IMPORTANT: On some systems it is required that RESBUF is correctly >+ aligned for a 32 bits value. */ >+extern void *__md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) __THROW; >+ >+ >+/* Compute MD5 message digest for bytes read from STREAM. The >+ resulting message digest number will be written into the 16 bytes >+ beginning at RESBLOCK. */ >+extern int __md5_stream (FILE *stream, void *resblock) __THROW; >+ >+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The >+ result is always in little endian byte order, so that a byte-wise >+ output yields to the wanted ASCII representation of the message >+ digest. */ >+extern void *__md5_buffer (const char *buffer, size_t len, >+ void *resblock) __THROW; >+ >+#endif /* md5.h */ >--- a/mdadm/mdadm.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/mdadm.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,18 @@ >+/* >+ * mdadm support for busybox. >+ * added by Alan Hourihane <alanh@fairlite.demon.co.uk> >+ */ >+#include <string.h> >+ >+extern int mdassemble_main(int argc, char **argv); >+extern int mdexamine_main(int argc, char **argv); >+ >+int mdadm_main(int argc, char **argv) { >+ if (argc >= 2) { >+ if (!strncmp(argv[1],"--assemble",10)) >+ return mdassemble_main(argc, argv); >+ if (!strncmp(argv[1],"--examine",9)) >+ return mdexamine_main(argc, argv); >+ } >+ return 0; >+} >--- a/mdadm/mdadm.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/mdadm.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,540 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * Paper: Neil Brown >+ * School of Computer Science and Engineering >+ * The University of New South Wales >+ * Sydney, 2052 >+ * Australia >+ */ >+ >+#include <unistd.h> >+#ifndef __dietlibc__ >+extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); >+#else >+# if defined(__NO_STAT64) || __WORDSIZE != 32 >+# define lseek64 lseek >+# endif >+#endif >+ >+#include <sys/types.h> >+#include <sys/stat.h> >+#include <stdlib.h> >+#include <time.h> >+#include <sys/time.h> >+#include <getopt.h> >+#include <fcntl.h> >+#include <stdio.h> >+#include <errno.h> >+#include <string.h> >+#include <syslog.h> >+#ifdef __dietlibc__ >+#include <strings.h> >+/* dietlibc has deprecated random and srandom!! */ >+#define random rand >+#define srandom srand >+#endif >+ >+ >+#include <linux/kdev_t.h> >+/*#include <linux/fs.h> */ >+#include <sys/mount.h> >+#include <asm/types.h> >+#include <sys/ioctl.h> >+#define MD_MAJOR 9 >+#define MdpMinorShift 6 >+ >+#ifndef BLKGETSIZE64 >+#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */ >+#endif >+ >+#define DEFAULT_BITMAP_CHUNK 4096 >+#define DEFAULT_BITMAP_DELAY 5 >+#define DEFAULT_MAX_WRITE_BEHIND 256 >+ >+#include "md_u.h" >+#include "md_p.h" >+#include "bitmap.h" >+ >+#include <endian.h> >+/* Redhat don't like to #include <asm/byteorder.h>, and >+ * some time include <linux/byteorder/xxx_endian.h> isn't enough, >+ * and there is no standard conversion function so... */ >+/* And dietlibc doesn't think byteswap is ok, so.. */ >+/* #include <byteswap.h> */ >+#define bswap_16(x) (((x) & 0x00ffU) << 8 | \ >+ ((x) & 0xff00U) >> 8) >+#define bswap_32(x) (((x) & 0x000000ffU) << 24 | \ >+ ((x) & 0xff000000U) >> 24 | \ >+ ((x) & 0x0000ff00U) << 8 | \ >+ ((x) & 0x00ff0000U) >> 8) >+#define bswap_64(x) (((x) & 0x00000000000000ffULL) << 56 | \ >+ ((x) & 0xff00000000000000ULL) >> 56 | \ >+ ((x) & 0x000000000000ff00ULL) << 40 | \ >+ ((x) & 0x00ff000000000000ULL) >> 40 | \ >+ ((x) & 0x0000000000ff0000ULL) << 24 | \ >+ ((x) & 0x0000ff0000000000ULL) >> 24 | \ >+ ((x) & 0x00000000ff000000ULL) << 8 | \ >+ ((x) & 0x000000ff00000000ULL) >> 8) >+ >+#if BYTE_ORDER == LITTLE_ENDIAN >+#define __cpu_to_le16(_x) (_x) >+#define __cpu_to_le32(_x) (_x) >+#define __cpu_to_le64(_x) (_x) >+#define __le16_to_cpu(_x) (_x) >+#define __le32_to_cpu(_x) (_x) >+#define __le64_to_cpu(_x) (_x) >+#elif BYTE_ORDER == BIG_ENDIAN >+#define __cpu_to_le16(_x) bswap_16(_x) >+#define __cpu_to_le32(_x) bswap_32(_x) >+#define __cpu_to_le64(_x) bswap_64(_x) >+#define __le16_to_cpu(_x) bswap_16(_x) >+#define __le32_to_cpu(_x) bswap_32(_x) >+#define __le64_to_cpu(_x) bswap_64(_x) >+#else >+# error "unknown endianness." >+#endif >+ >+ >+ >+/* general information that might be extracted from a superblock */ >+struct mdinfo { >+ mdu_array_info_t array; >+ mdu_disk_info_t disk; >+ __u64 events; >+ int uuid[4]; >+ char name[33]; >+ unsigned long long data_offset; >+ unsigned long long component_size; >+ int reshape_active; >+ unsigned long long reshape_progress; >+ int new_level, delta_disks, new_layout, new_chunk; >+}; >+ >+struct createinfo { >+ int uid; >+ int gid; >+ int autof; >+ int mode; >+ int symlinks; >+ struct supertype *supertype; >+}; >+ >+#define Name "mdadm" >+ >+enum mode { >+ ASSEMBLE=1, >+ BUILD, >+ CREATE, >+ MANAGE, >+ MISC, >+ MONITOR, >+ GROW, >+ INCREMENTAL, >+ AUTODETECT, >+}; >+ >+extern char short_options[]; >+extern char short_bitmap_auto_options[]; >+extern struct option long_options[]; >+extern char Version[], Usage[], Help[], OptionHelp[], >+ Help_create[], Help_build[], Help_assemble[], Help_grow[], >+ Help_incr[], >+ Help_manage[], Help_misc[], Help_monitor[], Help_config[]; >+ >+/* for option that don't have short equivilents, we assign arbitrary >+ * small numbers. '1' means an undecorated option, so we start at '2'. >+ */ >+enum special_options { >+ AssumeClean = 2, >+ BitmapChunk, >+ WriteBehind, >+ ReAdd, >+ NoDegraded, >+ Sparc22, >+ BackupFile, >+ HomeHost, >+ AutoHomeHost, >+ Symlinks, >+ AutoDetect, >+}; >+ >+/* 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; >+ int uuid[4]; >+ char name[33]; >+ >+ 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; >+ struct supertype *st; >+ int autof; /* 1 for normal, 2 for partitioned */ >+ char *spare_group; >+ char *bitmap_file; >+ int bitmap_fd; >+ >+ 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 >+ */ >+ char writemostly; >+ char re_add; >+ char used; /* set when used */ >+ 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 */ >+ int resync; /* 1 if resync, 0 if recovery */ >+ struct mdstat_ent *next; >+}; >+ >+extern struct mdstat_ent *mdstat_read(int hold, int start); >+extern void free_mdstat(struct mdstat_ent *ms); >+extern void mdstat_wait(int seconds); >+extern int mddev_busy(int devnum); >+ >+struct map_ent { >+ struct map_ent *next; >+ int devnum; >+ int major,minor; >+ int uuid[4]; >+ char *path; >+}; >+extern int map_update(struct map_ent **mpp, int devnum, int major, int minor, >+ int uuid[4], char *path); >+extern struct map_ent *map_by_uuid(struct map_ent **map, int uuid[4]); >+extern void map_read(struct map_ent **melp); >+extern int map_write(struct map_ent *mel); >+extern void map_delete(struct map_ent **mapp, int devnum); >+extern void map_free(struct map_ent *map); >+extern void map_add(struct map_ent **melp, >+ int devnum, int major, int minor, int uuid[4], char *path); >+ >+/* Data structure for holding info read from sysfs */ >+struct sysdev { >+ char name[20]; >+ int role; >+ int major, minor; >+ unsigned long long offset, size; >+ int state; >+ int errors; >+ struct sysdev *next; >+}; >+struct sysarray { >+ char name[20]; >+ struct sysdev *devs; >+ int chunk; >+ unsigned long long component_size; >+ int layout; >+ int level; >+ int spares; >+ int cache_size; >+ int mismatch_cnt; >+ int major_version, minor_version; >+}; >+/* various details can be requested */ >+#define GET_LEVEL 1 >+#define GET_LAYOUT 2 >+#define GET_COMPONENT 4 >+#define GET_CHUNK 8 >+#define GET_CACHE 16 >+#define GET_MISMATCH 32 >+#define GET_VERSION 64 >+ >+#define GET_DEVS 1024 /* gets role, major, minor */ >+#define GET_OFFSET 2048 >+#define GET_SIZE 4096 >+#define GET_STATE 8192 >+#define GET_ERROR 16384 >+ >+/* If fd >= 0, get the array it is open on, >+ * else use devnum. >=0 -> major9. <0..... >+ */ >+extern void sysfs_free(struct sysarray *sra); >+extern struct sysarray *sysfs_read(int fd, int devnum, unsigned long options); >+extern int sysfs_set_str(struct sysarray *sra, struct sysdev *dev, >+ char *name, char *val); >+extern int sysfs_set_num(struct sysarray *sra, struct sysdev *dev, >+ char *name, unsigned long long val); >+extern int sysfs_get_ll(struct sysarray *sra, struct sysdev *dev, >+ char *name, unsigned long long *val); >+ >+ >+extern int save_stripes(int *source, unsigned long long *offsets, >+ int raid_disks, int chunk_size, int level, int layout, >+ int nwrites, int *dest, >+ unsigned long long start, unsigned long long length); >+extern int restore_stripes(int *dest, unsigned long long *offsets, >+ int raid_disks, int chunk_size, int level, int layout, >+ int source, unsigned long long read_offset, >+ unsigned long long start, unsigned long long length); >+ >+#ifndef Sendmail >+#define Sendmail "/usr/lib/sendmail -t" >+#endif >+ >+#define SYSLOG_FACILITY LOG_DAEMON >+ >+extern char *map_num(mapping_t *map, int num); >+extern int map_name(mapping_t *map, char *name); >+extern mapping_t r5layout[], pers[], modes[], faultylayout[]; >+ >+extern char *map_dev(int major, int minor, int create); >+ >+ >+extern struct superswitch { >+ void (*examine_super)(void *sbv, char *homehost); >+ void (*brief_examine_super)(void *sbv); >+ void (*detail_super)(void *sbv, char *homehost); >+ void (*export_super)(void *sbv); >+ void (*brief_detail_super)(void *sbv); >+ void (*uuid_from_super)(int uuid[4], void *sbv); >+ void (*getinfo_super)(struct mdinfo *info, void *sbv); >+ int (*match_home)(void *sbv, char *homehost); >+ int (*update_super)(struct mdinfo *info, void *sbv, char *update, >+ char *devname, int verbose, >+ int uuid_set, char *homehost); >+ int (*init_super)(struct supertype *st, void **sbp, mdu_array_info_t *info, unsigned long long size, char *name, char *homehost, int *uuid); >+ void (*add_to_super)(void *sbv, mdu_disk_info_t *dinfo); >+ int (*store_super)(struct supertype *st, int fd, void *sbv); >+ int (*write_init_super)(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname); >+ int (*compare_super)(void **firstp, void *secondv); >+ int (*load_super)(struct supertype *st, int fd, void **sbp, char *devname); >+ struct supertype * (*match_metadata_desc)(char *arg); >+ __u64 (*avail_size)(struct supertype *st, __u64 size); >+ int (*add_internal_bitmap)(struct supertype *st, void *sbv, int *chunkp, >+ int delay, int write_behind, >+ unsigned long long size, int may_change, int major); >+ void (*locate_bitmap)(struct supertype *st, int fd, void *sbv); >+ int (*write_bitmap)(struct supertype *st, int fd, void *sbv); >+ int major; >+ int swapuuid; /* true if uuid is bigending rather than hostendian */ >+} super0, super1, *superlist[]; >+ >+struct supertype { >+ struct superswitch *ss; >+ int minor_version; >+ int max_devs; >+}; >+ >+extern struct supertype *super_by_version(int vers, int minor); >+extern struct supertype *guess_super(int fd); >+extern int get_dev_size(int fd, char *dname, unsigned long long *sizep); >+extern void get_one_disk(int mdfd, mdu_array_info_t *ainf, >+ mdu_disk_info_t *disk); >+ >+#if __GNUC__ < 3 >+struct stat64; >+#endif >+ >+#define HAVE_NFTW we assume >+#define HAVE_FTW >+ >+#ifdef UCLIBC >+# include <features.h> >+# ifndef __UCLIBC_HAS_FTW__ >+# undef HAVE_FTW >+# undef HAVE_NFTW >+# endif >+#endif >+ >+#ifdef __dietlibc__ >+# undef HAVE_NFTW >+#endif >+ >+#ifndef HAVE_NFTW >+# define FTW_PHYS 1 >+# ifndef HAVE_FTW >+ struct FTW {}; >+# endif >+#endif >+ >+#ifdef HAVE_FTW >+# include <ftw.h> >+#endif >+ >+extern int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s); >+ >+ >+extern int Manage_ro(char *devname, int fd, int readonly); >+extern int Manage_runstop(char *devname, int fd, int runstop, int quiet); >+extern int Manage_resize(char *devname, int fd, long long size, int raid_disks); >+extern int Manage_reconfig(char *devname, int fd, int layout); >+extern int Manage_subdevs(char *devname, int fd, >+ mddev_dev_t devlist, int verbose); >+extern int autodetect(void); >+extern int Grow_Add_device(char *devname, int fd, char *newdev); >+extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force); >+extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, >+ long long size, >+ int level, int layout, int chunksize, int raid_disks); >+extern int Grow_restart(struct supertype *st, struct mdinfo *info, >+ int *fdlist, int cnt, char *backup_file); >+ >+ >+extern int Assemble(struct supertype *st, char *mddev, int mdfd, >+ mddev_ident_t ident, >+ mddev_dev_t devlist, char *backup_file, >+ int readonly, int runstop, >+ char *update, char *homehost, >+ int verbose, int force); >+ >+extern int Build(char *mddev, int mdfd, int chunk, int level, int layout, >+ int raiddisks, >+ mddev_dev_t devlist, int assume_clean, >+ char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int verbose); >+ >+ >+extern int Create(struct supertype *st, char *mddev, int mdfd, >+ int chunk, int level, int layout, unsigned long long size, int raiddisks, int sparedisks, >+ char *name, char *homehost, int *uuid, >+ int subdevs, mddev_dev_t devlist, >+ int runstop, int verbose, int force, int assume_clean, >+ char *bitmap_file, int bitmap_chunk, int write_behind, int delay); >+ >+extern int Detail(char *dev, int brief, int export, int test, char *homehost); >+extern int Query(char *dev); >+ >+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 int get_mdp_major(void); >+extern int dev_open(char *dev, int flags); >+extern int is_standard(char *dev, int *nump); >+ >+extern int parse_auto(char *str, char *msg, int config); >+extern mddev_ident_t conf_get_ident(char *dev); >+extern mddev_dev_t conf_get_devs(void); >+extern int conf_test_dev(char *devname); >+extern struct createinfo *conf_get_create_info(void); >+extern void set_conffile(char *file); >+extern char *conf_get_mailaddr(void); >+extern char *conf_get_mailfrom(void); >+extern char *conf_get_program(void); >+extern char *conf_get_homehost(void); >+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 void uuid_from_super(int uuid[4], mdp_super_t *super); >+extern int same_uuid(int a[4], int b[4], int swapuuid); >+extern void copy_uuid(void *a, int b[4], int swapuuid); >+/* extern int compare_super(mdp_super_t *first, mdp_super_t *second);*/ >+extern unsigned long calc_csum(void *super, int bytes); >+extern int enough(int level, int raid_disks, int layout, int clean, >+ char *avail, int avail_disks); >+extern int ask(char *mesg); >+extern unsigned long long get_component_size(int fd); >+extern void remove_partitions(int fd); >+ >+ >+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[]; >+ >+extern int open_mddev(char *dev, int autof); >+extern int open_mddev_devnum(char *devname, int devnum, char *name, >+ char *chosen_name); >+ >+ >+#define LEVEL_MULTIPATH (-4) >+#define LEVEL_LINEAR (-1) >+#define LEVEL_FAULTY (-5) >+ >+ >+/* faulty stuff */ >+ >+#define WriteTransient 0 >+#define ReadTransient 1 >+#define WritePersistent 2 >+#define ReadPersistent 3 >+#define WriteAll 4 /* doesn't go to device */ >+#define ReadFixable 5 >+#define Modes 6 >+ >+#define ClearErrors 31 >+#define ClearFaults 30 >+ >+#define AllPersist 100 /* internal use only */ >+#define NoPersist 101 >+ >+#define ModeMask 0x1f >+#define ModeShift 5 >+ >+ >+#ifdef __TINYC__ >+#undef minor >+#undef major >+#undef makedev >+#define minor(x) ((x)&0xff) >+#define major(x) (((x)>>8)&0xff) >+#define makedev(M,m) (((M)<<8) | (m)) >+#endif >+ >+/* for raid5 */ >+#define ALGORITHM_LEFT_ASYMMETRIC 0 >+#define ALGORITHM_RIGHT_ASYMMETRIC 1 >+#define ALGORITHM_LEFT_SYMMETRIC 2 >+#define ALGORITHM_RIGHT_SYMMETRIC 3 >--- a/mdadm/mdassemble.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/mdassemble.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,908 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * Paper: Neil Brown >+ * School of Computer Science and Engineering >+ * The University of New South Wales >+ * Sydney, 2052 >+ * Australia >+ */ >+ >+#include "mdadm.h" >+#include <ctype.h> >+ >+static int name_matches(char *found, char *required, char *homehost) >+{ >+ /* See if the name found matches the required name, possibly >+ * prefixed with 'homehost' >+ */ >+ char fnd[33]; >+ >+ strncpy(fnd, found, 32); >+ fnd[32] = 0; >+ if (strcmp(found, required)==0) >+ return 1; >+ if (homehost) { >+ int l = strlen(homehost); >+ if (l < 32 && fnd[l] == ':' && >+ strcmp(fnd+l+1, required)==0) >+ return 1; >+ } >+ return 0; >+} >+ >+int open_mddev(char *dev, int autof/*unused */) >+{ >+ int mdfd = open(dev, O_RDWR, 0); >+ if (mdfd < 0) >+ fprintf(stderr, Name ": error opening %s: %s\n", >+ dev, strerror(errno)); >+ else if (md_get_version(mdfd) <= 0) { >+ fprintf(stderr, Name ": %s does not appear to be an md device\n", >+ dev); >+ close(mdfd); >+ mdfd = -1; >+ } >+ return mdfd; >+} >+ >+int Assemble(struct supertype *st, char *mddev, int mdfd, >+ mddev_ident_t ident, >+ mddev_dev_t devlist, char *backup_file, >+ int readonly, int runstop, >+ char *update, char *homehost, >+ int verbose, int force) >+{ >+ /* >+ * The task of Assemble is to find a collection of >+ * devices that should (according to their superblocks) >+ * form an array, and to give this collection to the MD driver. >+ * In Linux-2.4 and later, this involves submitting a >+ * SET_ARRAY_INFO ioctl with no arg - to prepare >+ * the array - and then submit a number of >+ * ADD_NEW_DISK ioctls to add disks into >+ * the array. Finally RUN_ARRAY might >+ * be submitted to start the array. >+ * >+ * Much of the work of Assemble is in finding and/or >+ * checking the disks to make sure they look right. >+ * >+ * If mddev is not set, then scan must be set and we >+ * read through the config file for dev+uuid mapping >+ * We recurse, setting mddev, for each device that >+ * - isn't running >+ * - has a valid uuid (or any uuid if !uuidset) >+ * >+ * If mddev is set, we try to determine state of md. >+ * check version - must be at least 0.90.0 >+ * check kernel version. must be at least 2.4. >+ * If not, we can possibly fall back on START_ARRAY >+ * Try to GET_ARRAY_INFO. >+ * If possible, give up >+ * If not, try to STOP_ARRAY just to make sure >+ * >+ * If !uuidset and scan, look in conf-file for uuid >+ * If not found, give up >+ * If !devlist and scan and uuidset, get list of devs from conf-file >+ * >+ * For each device: >+ * Check superblock - discard if bad >+ * Check uuid (set if we don't have one) - discard if no match >+ * Check superblock similarity if we have a superblock - discard if different >+ * Record events, devicenum >+ * This should give us a list of devices for the array >+ * We should collect the most recent event number >+ * >+ * Count disks with recent enough event count >+ * While force && !enough disks >+ * Choose newest rejected disks, update event count >+ * mark clean and rewrite superblock >+ * If recent kernel: >+ * SET_ARRAY_INFO >+ * foreach device with recent events : ADD_NEW_DISK >+ * if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY >+ * If old kernel: >+ * Check the device numbers in superblock are right >+ * update superblock if any changes >+ * START_ARRAY >+ * >+ */ >+ int clean = 0; >+ int old_linux = 0; >+ int vers = 0; /* Keep gcc quite - it really is initialised */ >+ void *first_super = NULL, *super = NULL; >+ struct { >+ char *devname; >+ unsigned int major, minor; >+ unsigned int oldmajor, oldminor; >+ long long events; >+ int uptodate; >+ int state; >+ int raid_disk; >+ int disk_nr; >+ } *devices; >+ int *best = NULL; /* indexed by raid_disk */ >+ unsigned int bestcnt = 0; >+ int devcnt = 0; >+ unsigned int okcnt, sparecnt; >+ unsigned int req_cnt; >+ unsigned int i; >+ int most_recent = 0; >+ int chosen_drive; >+ int change = 0; >+ int inargv = 0; >+ int bitmap_done; >+ int start_partial_ok = (runstop >= 0) && (force || devlist==NULL || mdfd < 0); >+ unsigned int num_devs; >+ mddev_dev_t tmpdev; >+ struct mdinfo info; >+ char *avail; >+ int nextspare = 0; >+ >+ if (mdfd < 0) >+ return 2; >+ >+ if (get_linux_version() < 2004000) >+ old_linux = 1; >+ >+ if (mdfd >= 0) { >+ vers = md_get_version(mdfd); >+ if (vers <= 0) { >+ fprintf(stderr, Name ": %s appears not to be an md device.\n", mddev); >+ return 1; >+ } >+ if (vers < 9000) { >+ fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n" >+ " Upgrade your kernel or try --build\n"); >+ return 1; >+ } >+ >+ if (ioctl(mdfd, GET_ARRAY_INFO, &info.array)>=0) { >+ fprintf(stderr, Name ": device %s already active - cannot assemble it\n", >+ mddev); >+ return 1; >+ } >+ ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */ >+ } >+ /* >+ * If any subdevs are listed, then any that don't >+ * match ident are discarded. Remainder must all match and >+ * become the array. >+ * If no subdevs, then we scan all devices in the config file, but >+ * there must be something in the identity >+ */ >+ >+ if (!devlist && >+ ident->uuid_set == 0 && >+ ident->super_minor < 0 && >+ ident->devices == NULL) { >+ fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n", >+ mddev ? mddev : "further assembly"); >+ return 1; >+ } >+ if (devlist == NULL) >+ devlist = conf_get_devs(); >+ else if (mdfd >= 0) >+ inargv = 1; >+ >+ tmpdev = devlist; num_devs = 0; >+ while (tmpdev) { >+ if (tmpdev->used) >+ tmpdev->used = 2; >+ else >+ num_devs++; >+ tmpdev = tmpdev->next; >+ } >+ devices = malloc(num_devs * sizeof(*devices)); >+ >+ if (!st && ident->st) st = ident->st; >+ >+ if (verbose>0) >+ fprintf(stderr, Name ": looking for devices for %s\n", >+ mddev ? mddev : "further assembly"); >+ >+ /* first walk the list of devices to find a consistent set >+ * that match the criterea, if that is possible. >+ * We flag the one we like with 'used'. >+ */ >+ for (tmpdev = devlist; >+ tmpdev; >+ tmpdev = tmpdev->next) { >+ char *devname = tmpdev->devname; >+ int dfd; >+ struct stat stb; >+ struct supertype *tst = st; >+ >+ if (tmpdev->used > 1) continue; >+ >+ if (ident->devices && >+ !match_oneof(ident->devices, devname)) { >+ if ((inargv && verbose>=0) || verbose > 0) >+ fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices); >+ continue; >+ } >+ >+ if (super) { >+ free(super); >+ super = NULL; >+ } >+ >+ dfd = dev_open(devname, O_RDONLY|O_EXCL); >+ if (dfd < 0) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": cannot open device %s: %s\n", >+ devname, strerror(errno)); >+ tmpdev->used = 2; >+ } else if (fstat(dfd, &stb)< 0) { >+ /* Impossible! */ >+ fprintf(stderr, Name ": fstat failed for %s: %s\n", >+ devname, strerror(errno)); >+ tmpdev->used = 2; >+ } else if ((stb.st_mode & S_IFMT) != S_IFBLK) { >+ fprintf(stderr, Name ": %s is not a block device.\n", >+ devname); >+ tmpdev->used = 2; >+ } else if (!tst && (tst = guess_super(dfd)) == NULL) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": no recogniseable superblock on %s\n", >+ devname); >+ tmpdev->used = 2; >+ } else if (tst->ss->load_super(tst,dfd, &super, NULL)) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf( stderr, Name ": no RAID superblock on %s\n", >+ devname); >+ } else { >+ tst->ss->getinfo_super(&info, super); >+ } >+ if (dfd >= 0) close(dfd); >+ >+ if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) && >+ (!super || same_uuid(info.uuid, ident->uuid, tst->ss->swapuuid)==0)) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s has wrong uuid.\n", >+ devname); >+ continue; >+ } >+ if (ident->name[0] && (!update || strcmp(update, "name")!= 0) && >+ (!super || name_matches(info.name, ident->name, homehost)==0)) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s has wrong name.\n", >+ devname); >+ continue; >+ } >+ if (ident->super_minor != UnSet && >+ (!super || ident->super_minor != info.array.md_minor)) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s has wrong super-minor.\n", >+ devname); >+ continue; >+ } >+ if (ident->level != UnSet && >+ (!super|| ident->level != info.array.level)) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s has wrong raid level.\n", >+ devname); >+ continue; >+ } >+ if (ident->raid_disks != UnSet && >+ (!super || ident->raid_disks!= info.array.raid_disks)) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s requires wrong number of drives.\n", >+ devname); >+ continue; >+ } >+ if (mdfd < 0) { >+ if (tst == NULL || super == NULL) >+ continue; >+ if (update == NULL && >+ tst->ss->match_home(super, homehost)==0) { >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s is not built for host %s.\n", >+ devname, homehost); >+ /* Auto-assemble, and this is not a usable host */ >+ /* if update != NULL, we are updating the host >+ * name... */ >+ continue; >+ } >+ } >+ /* If we are this far, then we are nearly commited to this device. >+ * If the super_block doesn't exist, or doesn't match others, >+ * then we probably cannot continue >+ * However if one of the arrays is for the homehost, and >+ * the other isn't that can disambiguate. >+ */ >+ >+ if (!super) { >+ fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", >+ devname); >+ free(first_super); >+ return 1; >+ } >+ >+ if (st == NULL) >+ st = tst; >+ if (st->ss != tst->ss || >+ st->minor_version != tst->minor_version || >+ st->ss->compare_super(&first_super, super) != 0) { >+ /* Some mismatch. If exactly one array matches this host, >+ * we can resolve on that one. >+ * Or, if we are auto assembling, we just ignore the second >+ * for now. >+ */ >+ if (mdfd < 0) >+ continue; >+ if (homehost) { >+ int first = st->ss->match_home(first_super, homehost); >+ int last = tst->ss->match_home(super, homehost); >+ if (first+last == 1) { >+ /* We can do something */ >+ if (first) {/* just ignore this one */ >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s misses out due to wrong homehost\n", >+ devname); >+ continue; >+ } else { /* reject all those sofar */ >+ mddev_dev_t td; >+ if ((inargv && verbose >= 0) || verbose > 0) >+ fprintf(stderr, Name ": %s overrides previous devices due to good homehost\n", >+ devname); >+ for (td=devlist; td != tmpdev; td=td->next) >+ if (td->used == 1) >+ td->used = 0; >+ tmpdev->used = 1; >+ continue; >+ } >+ } >+ } >+ fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", >+ devname); >+ free(super); >+ free(first_super); >+ return 1; >+ } >+ >+ tmpdev->used = 1; >+ } >+ >+ /* Ok, no bad inconsistancy, we can try updating etc */ >+ bitmap_done = 0; >+ for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) { >+ char *devname = tmpdev->devname; >+ struct stat stb; >+ /* looks like a good enough match to update the super block if needed */ >+ { >+ int dfd; >+ dfd = dev_open(devname, O_RDWR|O_EXCL); >+ >+ remove_partitions(dfd); >+ >+ if (super) { >+ free(super); >+ super = NULL; >+ } >+ >+ st->ss->load_super(st, dfd, &super, NULL); >+ st->ss->getinfo_super(&info, super); >+ close(dfd); >+ } >+ >+ stat(devname, &stb); >+ >+ if (verbose > 0) >+ fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", >+ devname, mddev, info.disk.raid_disk); >+ devices[devcnt].devname = devname; >+ devices[devcnt].major = major(stb.st_rdev); >+ devices[devcnt].minor = minor(stb.st_rdev); >+ devices[devcnt].oldmajor = info.disk.major; >+ devices[devcnt].oldminor = info.disk.minor; >+ devices[devcnt].events = info.events; >+ devices[devcnt].raid_disk = info.disk.raid_disk; >+ devices[devcnt].disk_nr = info.disk.number; >+ devices[devcnt].uptodate = 0; >+ devices[devcnt].state = info.disk.state; >+ if (most_recent < devcnt) { >+ if (devices[devcnt].events >+ > devices[most_recent].events) >+ most_recent = devcnt; >+ } >+ if (info.array.level == -4) >+ /* with multipath, the raid_disk from the superblock is meaningless */ >+ i = devcnt; >+ else >+ i = devices[devcnt].raid_disk; >+ if (i+1 == 0) { >+ if (nextspare < info.array.raid_disks) >+ nextspare = info.array.raid_disks; >+ i = nextspare++; >+ } else { >+ if (i >= info.array.raid_disks && >+ i >= nextspare) >+ nextspare = i+1; >+ } >+ if (i < 10000) { >+ if (i >= bestcnt) { >+ unsigned int newbestcnt = i+10; >+ int *newbest = malloc(sizeof(int)*newbestcnt); >+ unsigned int c; >+ for (c=0; c < newbestcnt; c++) >+ if (c < bestcnt) >+ newbest[c] = best[c]; >+ else >+ newbest[c] = -1; >+ if (best)free(best); >+ best = newbest; >+ bestcnt = newbestcnt; >+ } >+ if (best[i] >=0 && >+ devices[best[i]].events == devices[devcnt].events && >+ devices[best[i]].minor != devices[devcnt].minor && >+ st->ss->major == 0 && >+ info.array.level != -4) { >+ /* two different devices with identical superblock. >+ * Could be a mis-detection caused by overlapping >+ * partitions. fail-safe. >+ */ >+ fprintf(stderr, Name ": WARNING %s and %s appear" >+ " to have very similar superblocks.\n" >+ " If they are really different, " >+ "please --zero the superblock on one\n" >+ " If they are the same or overlap," >+ " please remove one from %s.\n", >+ devices[best[i]].devname, devname, >+ inargv ? "the list" : >+ "the\n DEVICE list in mdadm.conf" >+ ); >+ return 1; >+ } >+ if (best[i] == -1 >+ || devices[best[i]].events < devices[devcnt].events) >+ best[i] = devcnt; >+ } >+ devcnt++; >+ } >+ >+ if (super) >+ free(super); >+ super = NULL; >+ >+ if (update && strcmp(update, "byteorder")==0) >+ st->minor_version = 90; >+ >+ if (devcnt == 0) { >+ fprintf(stderr, Name ": no devices found for %s\n", >+ mddev); >+ free(first_super); >+ return 1; >+ } >+ >+ st->ss->getinfo_super(&info, first_super); >+ clean = info.array.state & 1; >+ >+ /* now we have some devices that might be suitable. >+ * I wonder how many >+ */ >+ avail = malloc(info.array.raid_disks); >+ memset(avail, 0, info.array.raid_disks); >+ okcnt = 0; >+ sparecnt=0; >+ for (i=0; i< bestcnt ;i++) { >+ int j = best[i]; >+ int event_margin = 1; /* always allow a difference of '1' >+ * like the kernel does >+ */ >+ if (j < 0) continue; >+ /* note: we ignore error flags in multipath arrays >+ * as they don't make sense >+ */ >+ if (info.array.level != -4) >+ if (!(devices[j].state & (1<<MD_DISK_SYNC))) { >+ if (!(devices[j].state & (1<<MD_DISK_FAULTY))) >+ sparecnt++; >+ continue; >+ } >+ if (devices[j].events+event_margin >= >+ devices[most_recent].events) { >+ devices[j].uptodate = 1; >+ if (i < info.array.raid_disks) { >+ okcnt++; >+ avail[i]=1; >+ } else >+ sparecnt++; >+ } >+ } >+ while (force && !enough(info.array.level, info.array.raid_disks, >+ info.array.layout, 1, >+ avail, okcnt)) { >+ /* Choose the newest best drive which is >+ * not up-to-date, update the superblock >+ * and add it. >+ */ >+ int fd; >+ long long current_events; >+ chosen_drive = -1; >+ for (i=0; i<info.array.raid_disks && i < bestcnt; i++) { >+ int j = best[i]; >+ if (j>=0 && >+ !devices[j].uptodate && >+ devices[j].events > 0 && >+ (chosen_drive < 0 || >+ devices[j].events > devices[chosen_drive].events)) >+ chosen_drive = j; >+ } >+ if (chosen_drive < 0) >+ break; >+ current_events = devices[chosen_drive].events; >+ add_another: >+ if (verbose >= 0) >+ fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n", >+ devices[chosen_drive].devname, devices[chosen_drive].raid_disk, >+ (int)(devices[chosen_drive].events), >+ (int)(devices[most_recent].events)); >+ fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); >+ if (fd < 0) { >+ fprintf(stderr, Name ": Couldn't open %s for write - not updating\n", >+ devices[chosen_drive].devname); >+ devices[chosen_drive].events = 0; >+ continue; >+ } >+ if (st->ss->load_super(st,fd, &super, NULL)) { >+ close(fd); >+ fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", >+ devices[chosen_drive].devname); >+ devices[chosen_drive].events = 0; >+ continue; >+ } >+ info.events = devices[most_recent].events; >+ st->ss->update_super(&info, super, "force-one", >+ devices[chosen_drive].devname, verbose, >+ 0, NULL); >+ >+ if (st->ss->store_super(st, fd, super)) { >+ close(fd); >+ fprintf(stderr, Name ": Could not re-write superblock on %s\n", >+ devices[chosen_drive].devname); >+ devices[chosen_drive].events = 0; >+ free(super); >+ continue; >+ } >+ close(fd); >+ devices[chosen_drive].events = devices[most_recent].events; >+ devices[chosen_drive].uptodate = 1; >+ avail[chosen_drive] = 1; >+ okcnt++; >+ free(super); >+ >+ /* If there are any other drives of the same vintage, >+ * add them in as well. We can't lose and we might gain >+ */ >+ for (i=0; i<info.array.raid_disks && i < bestcnt ; i++) { >+ int j = best[i]; >+ if (j >= 0 && >+ !devices[j].uptodate && >+ devices[j].events > 0 && >+ devices[j].events == current_events) { >+ chosen_drive = j; >+ goto add_another; >+ } >+ } >+ } >+ >+ /* Now we want to look at the superblock which the kernel will base things on >+ * and compare the devices that we think are working with the devices that the >+ * superblock thinks are working. >+ * If there are differences and --force is given, then update this chosen >+ * superblock. >+ */ >+ chosen_drive = -1; >+ super = NULL; >+ for (i=0; chosen_drive < 0 && i<bestcnt; i++) { >+ int j = best[i]; >+ int fd; >+ >+ if (j<0) >+ continue; >+ if (!devices[j].uptodate) >+ continue; >+ chosen_drive = j; >+ if ((fd=dev_open(devices[j].devname, O_RDONLY|O_EXCL))< 0) { >+ fprintf(stderr, Name ": Cannot open %s: %s\n", >+ devices[j].devname, strerror(errno)); >+ return 1; >+ } >+ if (st->ss->load_super(st,fd, &super, NULL)) { >+ close(fd); >+ fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", >+ devices[j].devname); >+ return 1; >+ } >+ close(fd); >+ } >+ if (super == NULL) { >+ fprintf(stderr, Name ": No suitable drives found for %s\n", mddev); >+ return 1; >+ } >+ st->ss->getinfo_super(&info, super); >+ for (i=0; i<bestcnt; i++) { >+ int j = best[i]; >+ unsigned int desired_state; >+ >+ if (i < info.array.raid_disks) >+ desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC); >+ else >+ desired_state = 0; >+ >+ if (j<0) >+ continue; >+ if (!devices[j].uptodate) >+ continue; >+ info.disk.number = devices[j].disk_nr; >+ info.disk.raid_disk = i; >+ info.disk.state = desired_state; >+ >+ if (devices[j].uptodate && >+ st->ss->update_super(&info, super, "assemble", NULL, verbose, 0, NULL)) { >+ if (force) { >+ if (verbose >= 0) >+ fprintf(stderr, Name ": " >+ "clearing FAULTY flag for device %d in %s for %s\n", >+ j, mddev, devices[j].devname); >+ change = 1; >+ } else { >+ if (verbose >= -1) >+ fprintf(stderr, Name ": " >+ "device %d in %s has wrong state in superblock, but %s seems ok\n", >+ i, mddev, devices[j].devname); >+ } >+ } >+#if 0 >+ if (!devices[j].uptodate && >+ !(super.disks[i].state & (1 << MD_DISK_FAULTY))) { >+ fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n", >+ i, mddev); >+ } >+#endif >+ } >+ if (force && !clean && >+ !enough(info.array.level, info.array.raid_disks, >+ info.array.layout, clean, >+ avail, okcnt)) { >+ change += st->ss->update_super(&info, super, "force-array", >+ devices[chosen_drive].devname, verbose, >+ 0, NULL); >+ clean = 1; >+ } >+ >+ if (change) { >+ int fd; >+ fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); >+ if (fd < 0) { >+ fprintf(stderr, Name ": Could not open %s for write - cannot Assemble array.\n", >+ devices[chosen_drive].devname); >+ return 1; >+ } >+ if (st->ss->store_super(st, fd, super)) { >+ close(fd); >+ fprintf(stderr, Name ": Could not re-write superblock on %s\n", >+ devices[chosen_drive].devname); >+ return 1; >+ } >+ close(fd); >+ } >+ >+ /* count number of in-sync devices according to the superblock. >+ * We must have this number to start the array without -s or -R >+ */ >+ req_cnt = info.array.working_disks; >+ >+ /* Almost ready to actually *do* something */ >+ if (!old_linux) { >+ int rv; >+ if ((vers % 100) >= 1) { /* can use different versions */ >+ mdu_array_info_t inf; >+ memset(&inf, 0, sizeof(inf)); >+ inf.major_version = st->ss->major; >+ inf.minor_version = st->minor_version; >+ rv = ioctl(mdfd, SET_ARRAY_INFO, &inf); >+ } else >+ rv = ioctl(mdfd, SET_ARRAY_INFO, NULL); >+ >+ if (rv) { >+ fprintf(stderr, Name ": SET_ARRAY_INFO failed for %s: %s\n", >+ mddev, strerror(errno)); >+ return 1; >+ } >+ if (ident->bitmap_fd >= 0) { >+ if (ioctl(mdfd, SET_BITMAP_FILE, ident->bitmap_fd) != 0) { >+ fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n"); >+ return 1; >+ } >+ } else if (ident->bitmap_file) { >+ /* From config file */ >+ int bmfd = open(ident->bitmap_file, O_RDWR); >+ if (bmfd < 0) { >+ fprintf(stderr, Name ": Could not open bitmap file %s\n", >+ ident->bitmap_file); >+ return 1; >+ } >+ if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) { >+ fprintf(stderr, Name ": Failed to set bitmapfile for %s\n", mddev); >+ close(bmfd); >+ return 1; >+ } >+ close(bmfd); >+ } >+ >+ /* First, add the raid disks, but add the chosen one last */ >+ for (i=0; i<= bestcnt; i++) { >+ int j; >+ if (i < bestcnt) { >+ j = best[i]; >+ if (j == chosen_drive) >+ continue; >+ } else >+ j = chosen_drive; >+ >+ if (j >= 0 /* && devices[j].uptodate */) { >+ mdu_disk_info_t disk; >+ memset(&disk, 0, sizeof(disk)); >+ disk.major = devices[j].major; >+ disk.minor = devices[j].minor; >+ if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) { >+ fprintf(stderr, Name ": failed to add %s to %s: %s\n", >+ devices[j].devname, >+ mddev, >+ strerror(errno)); >+ if (i < info.array.raid_disks || i == bestcnt) >+ okcnt--; >+ else >+ sparecnt--; >+ } else if (verbose > 0) >+ fprintf(stderr, Name ": added %s to %s as %d\n", >+ devices[j].devname, mddev, devices[j].raid_disk); >+ } else if (verbose > 0 && i < info.array.raid_disks) >+ fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", >+ i, mddev); >+ } >+ >+ if (runstop == 1 || >+ (runstop <= 0 && >+ ( enough(info.array.level, info.array.raid_disks, >+ info.array.layout, clean, avail, okcnt) && >+ (okcnt >= req_cnt || start_partial_ok) >+ ))) { >+ if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { >+ if (verbose >= 0) { >+ fprintf(stderr, Name ": %s has been started with %d drive%s", >+ mddev, okcnt, okcnt==1?"":"s"); >+ if (okcnt < info.array.raid_disks) >+ fprintf(stderr, " (out of %d)", info.array.raid_disks); >+ if (sparecnt) >+ fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); >+ fprintf(stderr, ".\n"); >+ } >+ return 0; >+ } >+ fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", >+ mddev, strerror(errno)); >+ >+ if (!enough(info.array.level, info.array.raid_disks, >+ info.array.layout, 1, avail, okcnt)) >+ fprintf(stderr, Name ": Not enough devices to " >+ "start the array.\n"); >+ else if (!enough(info.array.level, >+ info.array.raid_disks, >+ info.array.layout, clean, >+ avail, okcnt)) >+ fprintf(stderr, Name ": Not enough devices to " >+ "start the array while not clean " >+ "- consider --force.\n"); >+ >+ return 1; >+ } >+ if (runstop == -1) { >+ fprintf(stderr, Name ": %s assembled from %d drive%s", >+ mddev, okcnt, okcnt==1?"":"s"); >+ if (okcnt != info.array.raid_disks) >+ fprintf(stderr, " (out of %d)", info.array.raid_disks); >+ fprintf(stderr, ", but not started.\n"); >+ return 0; >+ } >+ if (verbose >= -1) { >+ fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); >+ if (sparecnt) >+ fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); >+ if (!enough(info.array.level, info.array.raid_disks, >+ info.array.layout, 1, avail, okcnt)) >+ fprintf(stderr, " - not enough to start the array.\n"); >+ else if (!enough(info.array.level, >+ info.array.raid_disks, >+ info.array.layout, clean, >+ avail, okcnt)) >+ fprintf(stderr, " - not enough to start the " >+ "array while not clean - consider " >+ "--force.\n"); >+ else { >+ if (req_cnt == info.array.raid_disks) >+ fprintf(stderr, " - need all %d to start it", req_cnt); >+ else >+ fprintf(stderr, " - need %d of %d to start", req_cnt, info.array.raid_disks); >+ fprintf(stderr, " (use --run to insist).\n"); >+ } >+ } >+ return 1; >+ } else { >+ /* The "chosen_drive" is a good choice, and if necessary, the superblock has >+ * been updated to point to the current locations of devices. >+ * so we can just start the array >+ */ >+ unsigned long dev; >+ dev = makedev(devices[chosen_drive].major, >+ devices[chosen_drive].minor); >+ if (ioctl(mdfd, START_ARRAY, dev)) { >+ fprintf(stderr, Name ": Cannot start array: %s\n", >+ strerror(errno)); >+ } >+ >+ } >+ return 0; >+} >+ >+int mdfd = -1; >+int runstop = 0; >+int readonly = 0; >+int verbose = 0; >+int force = 0; >+ >+int mdassemble_main(int argc, char **argv) { >+ mddev_ident_t array_list = conf_get_ident(NULL); >+ int minor; >+ if (!array_list) { >+ fprintf(stderr, Name ": No arrays found in config file\n"); >+ return 1; >+ } else { >+ for (; array_list; array_list = array_list->next) { >+ mdu_array_info_t array; >+ if (!strncmp("/dev/md", array_list->devname, 7)) { >+ errno = 0; >+ minor = strtoul(array_list->devname + 7, NULL, 0); >+ if (!errno) { >+ mknod(array_list->devname, S_IFBLK|0600, makedev(MD_MAJOR, minor)); >+ } >+ } >+ mdfd = open_mddev(array_list->devname, array_list->autof); >+ if (mdfd < 0) { >+ >+ fprintf(stderr, Name ": failed to open array\n"); >+ continue; >+ } >+ if (ioctl(mdfd, GET_ARRAY_INFO, &array) < 0) { >+ Assemble(array_list->st, array_list->devname, mdfd, >+ array_list, NULL, NULL, >+ readonly, runstop, NULL, NULL, verbose, force); >+ } >+ close(mdfd); >+ } >+ } >+ return 0; >+} >+ >--- a/mdadm/mdexamine.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/mdexamine.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,157 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * Paper: Neil Brown >+ * School of Computer Science and Engineering >+ * The University of New South Wales >+ * Sydney, 2052 >+ * Australia >+ */ >+ >+#include "mdadm.h" >+#include "dlink.h" >+ >+#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN) >+#error no endian defined >+#endif >+#include "md_u.h" >+#include "md_p.h" >+ >+static int Examine(mddev_dev_t devlist, int brief, int scan, >+ int SparcAdjust, struct supertype *forcest, >+ char *homehost) >+{ >+ >+ /* Read the raid superblock from a device and >+ * display important content. >+ * >+ * If cannot be found, print reason: too small, bad magic >+ * >+ * Print: >+ * version, ctime, level, size, raid+spare+ >+ * prefered minor >+ * uuid >+ * >+ * utime, state etc >+ * >+ * If (brief) gather devices for same array and just print a mdadm.conf line including devices= >+ * if devlist==NULL, use conf_get_devs() >+ */ >+ int fd; >+ void *super = NULL; >+ int rv = 0; >+ int err = 0; >+ >+ struct array { >+ void *super; >+ struct supertype *st; >+ struct mdinfo info; >+ void *devs; >+ struct array *next; >+ int spares; >+ } *arrays = NULL; >+ >+ for (; devlist ; devlist=devlist->next) { >+ struct supertype *st = forcest; >+ >+ fd = dev_open(devlist->devname, O_RDONLY); >+ if (fd < 0) { >+ if (!scan) { >+ fprintf(stderr,Name ": cannot open %s: %s\n", >+ devlist->devname, strerror(errno)); >+ rv = 1; >+ } >+ err = 1; >+ } >+ else { >+ if (!st) >+ st = guess_super(fd); >+ if (st) >+ err = st->ss->load_super(st, fd, &super, (brief||scan)?NULL:devlist->devname); >+ else { >+ if (!brief) { >+ fprintf(stderr, Name ": No md superblock detected on %s.\n", devlist->devname); >+ rv = 1; >+ } >+ err = 1; >+ } >+ close(fd); >+ } >+ if (err) >+ continue; >+ >+ if (SparcAdjust) >+ st->ss->update_super(NULL, super, "sparc2.2", devlist->devname, 0, 0, NULL); >+ /* Ok, its good enough to try, though the checksum could be wrong */ >+ if (brief) { >+ struct array *ap; >+ char *d; >+ for (ap=arrays; ap; ap=ap->next) { >+ if (st->ss == ap->st->ss && st->ss->compare_super(&ap->super, super)==0) >+ break; >+ } >+ if (!ap) { >+ ap = malloc(sizeof(*ap)); >+ ap->super = super; >+ ap->devs = dl_head(); >+ ap->next = arrays; >+ ap->spares = 0; >+ ap->st = st; >+ arrays = ap; >+ st->ss->getinfo_super(&ap->info, super); >+ } else { >+ st->ss->getinfo_super(&ap->info, super); >+ free(super); >+ } >+ if (!(ap->info.disk.state & MD_DISK_SYNC)) >+ ap->spares++; >+ d = dl_strdup(devlist->devname); >+ dl_add(ap->devs, d); >+ } >+ } >+ if (brief) { >+ struct array *ap; >+ for (ap=arrays; ap; ap=ap->next) { >+ char sep='='; >+ char *d; >+ ap->st->ss->brief_examine_super(ap->super); >+ if (ap->spares) printf(" spares=%d", ap->spares); >+ if (brief > 1) { >+ printf(" devices"); >+ for (d=dl_next(ap->devs); d!= ap->devs; d=dl_next(d)) { >+ printf("%c%s", sep, d); >+ sep=','; >+ } >+ } >+ free(ap->super); >+ /* FIXME free ap */ >+ if (ap->spares || brief > 1) >+ printf("\n"); >+ } >+ } >+ return rv; >+} >+ >+int mdexamine_main(int argc, char **argv) { >+ return Examine(conf_get_devs(), 1, 0, 0, NULL, NULL); >+} >+ >--- a/mdadm/md_p.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/md_p.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,194 @@ >+/* >+ 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 */ >+ >+#define MD_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config. >+ * read requests will only be sent here in >+ * dire need >+ */ >+ >+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 >+ >+#define MD_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */ >+ >+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 */ >+ __u32 cp_events_hi; /* 9 high-order of checkpoint update count */ >+ __u32 cp_events_lo; /* 10 low-order of checkpoint update count */ >+#else >+ __u32 events_lo; /* 7 low-order of superblock update count */ >+ __u32 events_hi; /* 8 high-order of superblock update count */ >+ __u32 cp_events_lo; /* 9 low-order of checkpoint update count */ >+ __u32 cp_events_hi; /* 10 high-order of checkpoint update count */ >+#endif >+ __u32 recovery_cp; /* 11 recovery checkpoint sector count */ >+ /* There are only valid for minor_version > 90 */ >+ __u64 reshape_position; /* 12,13 next address in array-space for reshape */ >+ __u32 new_level; /* 14 new level we are reshaping to */ >+ __u32 delta_disks; /* 15 change in number of raid_disks */ >+ __u32 new_layout; /* 16 new layout */ >+ __u32 new_chunk; /* 17 new chunk size (bytes) */ >+ __u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 18]; >+ >+ /* >+ * 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 >+ >--- a/mdadm/md_u.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/md_u.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,123 @@ >+/* >+ 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) >+#define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t) >+ >+/* 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) >+#define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int) >+ >+/* 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_bitmap_file_s >+{ >+ char pathname[4096]; >+} mdu_bitmap_file_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 >+ >--- a/mdadm/sha1.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/sha1.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,423 @@ >+/* sha1.c - Functions to compute SHA1 message digest of files or >+ memory blocks according to the NIST specification FIPS-180-1. >+ >+ Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. >+ >+ 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. >+ >+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ >+ >+/* Written by Scott G. Miller >+ Credits: >+ Robert Klep <robert@ilse.nl> -- Expansion function fix >+*/ >+ >+#ifdef HAVE_CONFIG_H >+# include <config.h> >+#endif >+ >+#include "sha1.h" >+ >+#include <stddef.h> >+#include <string.h> >+ >+#if USE_UNLOCKED_IO >+# include "unlocked-io.h" >+#endif >+ >+/* SWAP does an endian swap on architectures that are little-endian, >+ as SHA1 needs some data in a big-endian form. */ >+ >+#ifdef WORDS_BIGENDIAN >+# define SWAP(n) (n) >+#else >+# define SWAP(n) \ >+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) >+#endif >+ >+#define BLOCKSIZE 4096 >+#if BLOCKSIZE % 64 != 0 >+# error "invalid BLOCKSIZE" >+#endif >+ >+/* This array contains the bytes used to pad the buffer to the next >+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */ >+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; >+ >+ >+/* >+ Takes a pointer to a 160 bit block of data (five 32 bit ints) and >+ intializes it to the start constants of the SHA1 algorithm. This >+ must be called before using hash in the call to sha1_hash. >+*/ >+void >+sha1_init_ctx (struct sha1_ctx *ctx) >+{ >+ ctx->A = 0x67452301; >+ ctx->B = 0xefcdab89; >+ ctx->C = 0x98badcfe; >+ ctx->D = 0x10325476; >+ ctx->E = 0xc3d2e1f0; >+ >+ ctx->total[0] = ctx->total[1] = 0; >+ ctx->buflen = 0; >+} >+ >+/* Put result from CTX in first 20 bytes following RESBUF. The result >+ must be in little endian byte order. >+ >+ IMPORTANT: On some systems it is required that RESBUF is correctly >+ aligned for a 32 bits value. */ >+void * >+sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) >+{ >+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); >+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); >+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); >+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); >+ ((md5_uint32 *) resbuf)[4] = SWAP (ctx->E); >+ >+ return resbuf; >+} >+ >+/* Process the remaining bytes in the internal buffer and the usual >+ prolog according to the standard and write the result to RESBUF. >+ >+ IMPORTANT: On some systems it is required that RESBUF is correctly >+ aligned for a 32 bits value. */ >+void * >+sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) >+{ >+ /* Take yet unprocessed bytes into account. */ >+ md5_uint32 bytes = ctx->buflen; >+ size_t pad; >+ >+ /* Now count remaining bytes. */ >+ ctx->total[0] += bytes; >+ if (ctx->total[0] < bytes) >+ ++ctx->total[1]; >+ >+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; >+ memcpy (&ctx->buffer[bytes], fillbuf, pad); >+ >+ /* Put the 64-bit file length in *bits* at the end of the buffer. */ >+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP (ctx->total[0] << 3); >+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) | >+ (ctx->total[0] >> 29)); >+ >+ /* Process last bytes. */ >+ sha1_process_block (ctx->buffer, bytes + pad + 8, ctx); >+ >+ return sha1_read_ctx (ctx, resbuf); >+} >+ >+/* Compute SHA1 message digest for bytes read from STREAM. The >+ resulting message digest number will be written into the 16 bytes >+ beginning at RESBLOCK. */ >+int >+sha1_stream (FILE *stream, void *resblock) >+{ >+ struct sha1_ctx ctx; >+ char buffer[BLOCKSIZE + 72]; >+ size_t sum; >+ >+ /* Initialize the computation context. */ >+ sha1_init_ctx (&ctx); >+ >+ /* Iterate over full file contents. */ >+ while (1) >+ { >+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the >+ computation function processes the whole buffer so that with the >+ next round of the loop another block can be read. */ >+ size_t n; >+ sum = 0; >+ >+ /* Read block. Take care for partial reads. */ >+ while (1) >+ { >+ n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); >+ >+ sum += n; >+ >+ if (sum == BLOCKSIZE) >+ break; >+ >+ if (n == 0) >+ { >+ /* Check for the error flag IFF N == 0, so that we don't >+ exit the loop after a partial read due to e.g., EAGAIN >+ or EWOULDBLOCK. */ >+ if (ferror (stream)) >+ return 1; >+ goto process_partial_block; >+ } >+ >+ /* We've read at least one byte, so ignore errors. But always >+ check for EOF, since feof may be true even though N > 0. >+ Otherwise, we could end up calling fread after EOF. */ >+ if (feof (stream)) >+ goto process_partial_block; >+ } >+ >+ /* Process buffer with BLOCKSIZE bytes. Note that >+ BLOCKSIZE % 64 == 0 >+ */ >+ sha1_process_block (buffer, BLOCKSIZE, &ctx); >+ } >+ >+ process_partial_block:; >+ >+ /* Process any remaining bytes. */ >+ if (sum > 0) >+ sha1_process_bytes (buffer, sum, &ctx); >+ >+ /* Construct result in desired memory. */ >+ sha1_finish_ctx (&ctx, resblock); >+ return 0; >+} >+ >+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The >+ result is always in little endian byte order, so that a byte-wise >+ output yields to the wanted ASCII representation of the message >+ digest. */ >+void * >+sha1_buffer (const char *buffer, size_t len, void *resblock) >+{ >+ struct sha1_ctx ctx; >+ >+ /* Initialize the computation context. */ >+ sha1_init_ctx (&ctx); >+ >+ /* Process whole buffer but last len % 64 bytes. */ >+ sha1_process_bytes (buffer, len, &ctx); >+ >+ /* Put result in desired memory area. */ >+ return sha1_finish_ctx (&ctx, resblock); >+} >+ >+void >+sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) >+{ >+ /* When we already have some bits in our internal buffer concatenate >+ both inputs first. */ >+ if (ctx->buflen != 0) >+ { >+ size_t left_over = ctx->buflen; >+ size_t add = 128 - left_over > len ? len : 128 - left_over; >+ >+ memcpy (&ctx->buffer[left_over], buffer, add); >+ ctx->buflen += add; >+ >+ if (ctx->buflen > 64) >+ { >+ sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); >+ >+ ctx->buflen &= 63; >+ /* The regions in the following copy operation cannot overlap. */ >+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], >+ ctx->buflen); >+ } >+ >+ buffer = (const char *) buffer + add; >+ len -= add; >+ } >+ >+ /* Process available complete blocks. */ >+ if (len >= 64) >+ { >+#if !_STRING_ARCH_unaligned >+# define alignof(type) offsetof (struct { char c; type x; }, x) >+# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0) >+ if (UNALIGNED_P (buffer)) >+ while (len > 64) >+ { >+ sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); >+ buffer = (const char *) buffer + 64; >+ len -= 64; >+ } >+ else >+#endif >+ { >+ sha1_process_block (buffer, len & ~63, ctx); >+ buffer = (const char *) buffer + (len & ~63); >+ len &= 63; >+ } >+ } >+ >+ /* Move remaining bytes in internal buffer. */ >+ if (len > 0) >+ { >+ size_t left_over = ctx->buflen; >+ >+ memcpy (&ctx->buffer[left_over], buffer, len); >+ left_over += len; >+ if (left_over >= 64) >+ { >+ sha1_process_block (ctx->buffer, 64, ctx); >+ left_over -= 64; >+ memcpy (ctx->buffer, &ctx->buffer[64], left_over); >+ } >+ ctx->buflen = left_over; >+ } >+} >+ >+/* --- Code below is the primary difference between md5.c and sha1.c --- */ >+ >+/* SHA1 round constants */ >+#define K1 0x5a827999L >+#define K2 0x6ed9eba1L >+#define K3 0x8f1bbcdcL >+#define K4 0xca62c1d6L >+ >+/* Round functions. Note that F2 is the same as F4. */ >+#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) >+#define F2(B,C,D) (B ^ C ^ D) >+#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) >+#define F4(B,C,D) (B ^ C ^ D) >+ >+/* Process LEN bytes of BUFFER, accumulating context into CTX. >+ It is assumed that LEN % 64 == 0. >+ Most of this code comes from GnuPG's cipher/sha1.c. */ >+ >+void >+sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) >+{ >+ const md5_uint32 *words = buffer; >+ size_t nwords = len / sizeof (md5_uint32); >+ const md5_uint32 *endp = words + nwords; >+ md5_uint32 x[16]; >+ md5_uint32 a = ctx->A; >+ md5_uint32 b = ctx->B; >+ md5_uint32 c = ctx->C; >+ md5_uint32 d = ctx->D; >+ md5_uint32 e = ctx->E; >+ >+ /* First increment the byte count. RFC 1321 specifies the possible >+ length of the file up to 2^64 bits. Here we only compute the >+ number of bytes. Do a double word increment. */ >+ ctx->total[0] += len; >+ if (ctx->total[0] < len) >+ ++ctx->total[1]; >+ >+#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) >+ >+#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ >+ ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ >+ , (x[I&0x0f] = rol(tm, 1)) ) >+ >+#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ >+ + F( B, C, D ) \ >+ + K \ >+ + M; \ >+ B = rol( B, 30 ); \ >+ } while(0) >+ >+ while (words < endp) >+ { >+ md5_uint32 tm; >+ int t; >+ for (t = 0; t < 16; t++) >+ { >+ x[t] = SWAP (*words); >+ words++; >+ } >+ >+ R( a, b, c, d, e, F1, K1, x[ 0] ); >+ R( e, a, b, c, d, F1, K1, x[ 1] ); >+ R( d, e, a, b, c, F1, K1, x[ 2] ); >+ R( c, d, e, a, b, F1, K1, x[ 3] ); >+ R( b, c, d, e, a, F1, K1, x[ 4] ); >+ R( a, b, c, d, e, F1, K1, x[ 5] ); >+ R( e, a, b, c, d, F1, K1, x[ 6] ); >+ R( d, e, a, b, c, F1, K1, x[ 7] ); >+ R( c, d, e, a, b, F1, K1, x[ 8] ); >+ R( b, c, d, e, a, F1, K1, x[ 9] ); >+ R( a, b, c, d, e, F1, K1, x[10] ); >+ R( e, a, b, c, d, F1, K1, x[11] ); >+ R( d, e, a, b, c, F1, K1, x[12] ); >+ R( c, d, e, a, b, F1, K1, x[13] ); >+ R( b, c, d, e, a, F1, K1, x[14] ); >+ R( a, b, c, d, e, F1, K1, x[15] ); >+ R( e, a, b, c, d, F1, K1, M(16) ); >+ R( d, e, a, b, c, F1, K1, M(17) ); >+ R( c, d, e, a, b, F1, K1, M(18) ); >+ R( b, c, d, e, a, F1, K1, M(19) ); >+ R( a, b, c, d, e, F2, K2, M(20) ); >+ R( e, a, b, c, d, F2, K2, M(21) ); >+ R( d, e, a, b, c, F2, K2, M(22) ); >+ R( c, d, e, a, b, F2, K2, M(23) ); >+ R( b, c, d, e, a, F2, K2, M(24) ); >+ R( a, b, c, d, e, F2, K2, M(25) ); >+ R( e, a, b, c, d, F2, K2, M(26) ); >+ R( d, e, a, b, c, F2, K2, M(27) ); >+ R( c, d, e, a, b, F2, K2, M(28) ); >+ R( b, c, d, e, a, F2, K2, M(29) ); >+ R( a, b, c, d, e, F2, K2, M(30) ); >+ R( e, a, b, c, d, F2, K2, M(31) ); >+ R( d, e, a, b, c, F2, K2, M(32) ); >+ R( c, d, e, a, b, F2, K2, M(33) ); >+ R( b, c, d, e, a, F2, K2, M(34) ); >+ R( a, b, c, d, e, F2, K2, M(35) ); >+ R( e, a, b, c, d, F2, K2, M(36) ); >+ R( d, e, a, b, c, F2, K2, M(37) ); >+ R( c, d, e, a, b, F2, K2, M(38) ); >+ R( b, c, d, e, a, F2, K2, M(39) ); >+ R( a, b, c, d, e, F3, K3, M(40) ); >+ R( e, a, b, c, d, F3, K3, M(41) ); >+ R( d, e, a, b, c, F3, K3, M(42) ); >+ R( c, d, e, a, b, F3, K3, M(43) ); >+ R( b, c, d, e, a, F3, K3, M(44) ); >+ R( a, b, c, d, e, F3, K3, M(45) ); >+ R( e, a, b, c, d, F3, K3, M(46) ); >+ R( d, e, a, b, c, F3, K3, M(47) ); >+ R( c, d, e, a, b, F3, K3, M(48) ); >+ R( b, c, d, e, a, F3, K3, M(49) ); >+ R( a, b, c, d, e, F3, K3, M(50) ); >+ R( e, a, b, c, d, F3, K3, M(51) ); >+ R( d, e, a, b, c, F3, K3, M(52) ); >+ R( c, d, e, a, b, F3, K3, M(53) ); >+ R( b, c, d, e, a, F3, K3, M(54) ); >+ R( a, b, c, d, e, F3, K3, M(55) ); >+ R( e, a, b, c, d, F3, K3, M(56) ); >+ R( d, e, a, b, c, F3, K3, M(57) ); >+ R( c, d, e, a, b, F3, K3, M(58) ); >+ R( b, c, d, e, a, F3, K3, M(59) ); >+ R( a, b, c, d, e, F4, K4, M(60) ); >+ R( e, a, b, c, d, F4, K4, M(61) ); >+ R( d, e, a, b, c, F4, K4, M(62) ); >+ R( c, d, e, a, b, F4, K4, M(63) ); >+ R( b, c, d, e, a, F4, K4, M(64) ); >+ R( a, b, c, d, e, F4, K4, M(65) ); >+ R( e, a, b, c, d, F4, K4, M(66) ); >+ R( d, e, a, b, c, F4, K4, M(67) ); >+ R( c, d, e, a, b, F4, K4, M(68) ); >+ R( b, c, d, e, a, F4, K4, M(69) ); >+ R( a, b, c, d, e, F4, K4, M(70) ); >+ R( e, a, b, c, d, F4, K4, M(71) ); >+ R( d, e, a, b, c, F4, K4, M(72) ); >+ R( c, d, e, a, b, F4, K4, M(73) ); >+ R( b, c, d, e, a, F4, K4, M(74) ); >+ R( a, b, c, d, e, F4, K4, M(75) ); >+ R( e, a, b, c, d, F4, K4, M(76) ); >+ R( d, e, a, b, c, F4, K4, M(77) ); >+ R( c, d, e, a, b, F4, K4, M(78) ); >+ R( b, c, d, e, a, F4, K4, M(79) ); >+ >+ a = ctx->A += a; >+ b = ctx->B += b; >+ c = ctx->C += c; >+ d = ctx->D += d; >+ e = ctx->E += e; >+ } >+} >--- a/mdadm/sha1.h 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/sha1.h 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,87 @@ >+/* Declarations of functions and data types used for SHA1 sum >+ library functions. >+ Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation, Inc. >+ >+ 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. >+ >+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ >+ >+#ifndef SHA1_H >+# define SHA1_H 1 >+ >+# include <stdio.h> >+# include "md5.h" >+ >+/* Structure to save state of computation between the single steps. */ >+struct sha1_ctx >+{ >+ md5_uint32 A; >+ md5_uint32 B; >+ md5_uint32 C; >+ md5_uint32 D; >+ md5_uint32 E; >+ >+ md5_uint32 total[2]; >+ md5_uint32 buflen; >+ char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); >+}; >+ >+ >+/* Initialize structure containing state of computation. */ >+extern void sha1_init_ctx (struct sha1_ctx *ctx); >+ >+/* Starting with the result of former calls of this function (or the >+ initialization function update the context for the next LEN bytes >+ starting at BUFFER. >+ It is necessary that LEN is a multiple of 64!!! */ >+extern void sha1_process_block (const void *buffer, size_t len, >+ struct sha1_ctx *ctx); >+ >+/* Starting with the result of former calls of this function (or the >+ initialization function update the context for the next LEN bytes >+ starting at BUFFER. >+ It is NOT required that LEN is a multiple of 64. */ >+extern void sha1_process_bytes (const void *buffer, size_t len, >+ struct sha1_ctx *ctx); >+ >+/* Process the remaining bytes in the buffer and put result from CTX >+ in first 20 bytes following RESBUF. The result is always in little >+ endian byte order, so that a byte-wise output yields to the wanted >+ ASCII representation of the message digest. >+ >+ IMPORTANT: On some systems it is required that RESBUF be correctly >+ aligned for a 32 bits value. */ >+extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); >+ >+ >+/* Put result from CTX in first 20 bytes following RESBUF. The result is >+ always in little endian byte order, so that a byte-wise output yields >+ to the wanted ASCII representation of the message digest. >+ >+ IMPORTANT: On some systems it is required that RESBUF is correctly >+ aligned for a 32 bits value. */ >+extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); >+ >+ >+/* Compute SHA1 message digest for bytes read from STREAM. The >+ resulting message digest number will be written into the 20 bytes >+ beginning at RESBLOCK. */ >+extern int sha1_stream (FILE *stream, void *resblock); >+ >+/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The >+ result is always in little endian byte order, so that a byte-wise >+ output yields to the wanted ASCII representation of the message >+ digest. */ >+extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); >+ >+#endif >--- a/mdadm/super0.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/super0.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,562 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * Paper: Neil Brown >+ * School of Computer Science and Engineering >+ * The University of New South Wales >+ * Sydney, 2052 >+ * Australia >+ */ >+ >+#define HAVE_STDINT_H 1 >+#include "mdadm.h" >+/* >+ * All handling for the 0.90.0 version superblock is in >+ * this file. >+ * This includes: >+ * - finding, loading, and writing the superblock. >+ * - initialising a new superblock >+ * - printing the superblock for --examine >+ * - printing part of the superblock for --detail >+ * .. other stuff >+ */ >+ >+ >+static unsigned long calc_sb0_csum(mdp_super_t *super) >+{ >+ unsigned long csum = super->sb_csum; >+ unsigned long newcsum; >+ super->sb_csum= 0 ; >+ newcsum = calc_csum(super, MD_SB_BYTES); >+ super->sb_csum = csum; >+ return newcsum; >+} >+ >+ >+void super0_swap_endian(struct mdp_superblock_s *sb) >+{ >+ /* as super0 superblocks are host-endian, it is sometimes >+ * useful to be able to swap the endianness >+ * as (almost) everything is u32's we byte-swap every 4byte >+ * number. >+ * We then also have to swap the events_hi and events_lo >+ */ >+ char *sbc = (char *)sb; >+ __u32 t32; >+ int i; >+ >+ for (i=0; i < MD_SB_BYTES ; i+=4) { >+ char t = sbc[i]; >+ sbc[i] = sbc[i+3]; >+ sbc[i+3] = t; >+ t=sbc[i+1]; >+ sbc[i+1]=sbc[i+2]; >+ sbc[i+2]=t; >+ } >+ t32 = sb->events_hi; >+ sb->events_hi = sb->events_lo; >+ sb->events_lo = t32; >+ >+ t32 = sb->cp_events_hi; >+ sb->cp_events_hi = sb->cp_events_lo; >+ sb->cp_events_lo = t32; >+ >+} >+ >+static void brief_examine_super0(void *sbv) >+{ >+ mdp_super_t *sb = sbv; >+ char *c=map_num(pers, sb->level); >+ char devname[20]; >+ >+ sprintf(devname, "/dev/md%d", sb->md_minor); >+ >+ printf("ARRAY %s level=%s num-devices=%d UUID=", >+ devname, >+ c?c:"-unknown-", sb->raid_disks); >+ if (sb->minor_version >= 90) >+ printf("%08x:%08x:%08x:%08x", sb->set_uuid0, sb->set_uuid1, >+ sb->set_uuid2, sb->set_uuid3); >+ else >+ printf("%08x", sb->set_uuid0); >+ printf("\n"); >+} >+ >+static int match_home0(void *sbv, char *homehost) >+{ >+ mdp_super_t *sb = sbv; >+ char buf[20]; >+ char *hash = sha1_buffer(homehost, >+ strlen(homehost), >+ buf); >+ >+ return (memcmp(&sb->set_uuid2, hash, 8)==0); >+} >+ >+static void uuid_from_super0(int uuid[4], void * sbv) >+{ >+ mdp_super_t *super = sbv; >+ 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; >+ } >+} >+ >+static void getinfo_super0(struct mdinfo *info, void *sbv) >+{ >+ mdp_super_t *sb = sbv; >+ int working = 0; >+ int i; >+ >+ info->array.major_version = sb->major_version; >+ info->array.minor_version = sb->minor_version; >+ info->array.patch_version = sb->patch_version; >+ info->array.raid_disks = sb->raid_disks; >+ info->array.level = sb->level; >+ info->array.layout = sb->layout; >+ info->array.md_minor = sb->md_minor; >+ info->array.ctime = sb->ctime; >+ info->array.utime = sb->utime; >+ info->array.chunk_size = sb->chunk_size; >+ info->array.state = sb->state; >+ info->component_size = sb->size*2; >+ >+ info->disk.state = sb->this_disk.state; >+ info->disk.major = sb->this_disk.major; >+ info->disk.minor = sb->this_disk.minor; >+ info->disk.raid_disk = sb->this_disk.raid_disk; >+ info->disk.number = sb->this_disk.number; >+ >+ info->events = md_event(sb); >+ info->data_offset = 0; >+ >+ uuid_from_super0(info->uuid, sbv); >+ >+ if (sb->minor_version > 90 && (sb->reshape_position+1) != 0) { >+ info->reshape_active = 1; >+ info->reshape_progress = sb->reshape_position; >+ info->new_level = sb->new_level; >+ info->delta_disks = sb->delta_disks; >+ info->new_layout = sb->new_layout; >+ info->new_chunk = sb->new_chunk; >+ } else >+ info->reshape_active = 0; >+ >+ sprintf(info->name, "%d", sb->md_minor); >+ /* work_disks is calculated rather than read directly */ >+ for (i=0; i < MD_SB_DISKS; i++) >+ if ((sb->disks[i].state & (1<<MD_DISK_SYNC)) && >+ (sb->disks[i].raid_disk < info->array.raid_disks) && >+ (sb->disks[i].state & (1<<MD_DISK_ACTIVE)) && >+ !(sb->disks[i].state & (1<<MD_DISK_FAULTY))) >+ working ++; >+ info->array.working_disks = working; >+} >+ >+ >+static int update_super0(struct mdinfo *info, void *sbv, char *update, >+ char *devname, int verbose, >+ int uuid_set, char *homehost) >+{ >+ /* NOTE: for 'assemble' and 'force' we need to return non-zero if any change was made. >+ * For others, the return value is ignored. >+ */ >+ int rv = 0; >+ mdp_super_t *sb = sbv; >+ if (strcmp(update, "sparc2.2")==0 ) { >+ /* 2.2 sparc put the events in the wrong place >+ * So we copy the tail of the superblock >+ * up 4 bytes before continuing >+ */ >+ __u32 *sb32 = (__u32*)sb; >+ memcpy(sb32+MD_SB_GENERIC_CONSTANT_WORDS+7, >+ sb32+MD_SB_GENERIC_CONSTANT_WORDS+7+1, >+ (MD_SB_WORDS - (MD_SB_GENERIC_CONSTANT_WORDS+7+1))*4); >+ if (verbose >= 0) >+ fprintf (stderr, Name ": adjusting superblock of %s for 2.2/sparc compatability.\n", >+ devname); >+ } >+ if (strcmp(update, "super-minor") ==0) { >+ sb->md_minor = info->array.md_minor; >+ if (verbose > 0) >+ fprintf(stderr, Name ": updating superblock of %s with minor number %d\n", >+ devname, info->array.md_minor); >+ } >+ if (strcmp(update, "summaries") == 0) { >+ int i; >+ /* set nr_disks, active_disks, working_disks, >+ * failed_disks, spare_disks based on disks[] >+ * array in superblock. >+ * Also make sure extra slots aren't 'failed' >+ */ >+ sb->nr_disks = sb->active_disks = >+ sb->working_disks = sb->failed_disks = >+ sb->spare_disks = 0; >+ for (i=0; i < MD_SB_DISKS ; i++) >+ if (sb->disks[i].major || >+ sb->disks[i].minor) { >+ int state = sb->disks[i].state; >+ if (state & (1<<MD_DISK_REMOVED)) >+ continue; >+ sb->nr_disks++; >+ if (state & (1<<MD_DISK_ACTIVE)) >+ sb->active_disks++; >+ if (state & (1<<MD_DISK_FAULTY)) >+ sb->failed_disks++; >+ else >+ sb->working_disks++; >+ if (state == 0) >+ sb->spare_disks++; >+ } else if (i >= sb->raid_disks && sb->disks[i].number == 0) >+ sb->disks[i].state = 0; >+ } >+ if (strcmp(update, "force-one")==0) { >+ /* Not enough devices for a working array, so >+ * bring this one up-to-date. >+ */ >+ __u32 ehi = sb->events_hi, elo = sb->events_lo; >+ sb->events_hi = (info->events>>32) & 0xFFFFFFFF; >+ sb->events_lo = (info->events) & 0xFFFFFFFF; >+ if (sb->events_hi != ehi || >+ sb->events_lo != elo) >+ rv = 1; >+ } >+ if (strcmp(update, "force-array")==0) { >+ /* degraded array and 'force' requested, so >+ * maybe need to mark it 'clean' >+ */ >+ if ((sb->level == 5 || sb->level == 4 || sb->level == 6) && >+ (sb->state & (1 << MD_SB_CLEAN)) == 0) { >+ /* need to force clean */ >+ sb->state |= (1 << MD_SB_CLEAN); >+ rv = 1; >+ } >+ } >+ if (strcmp(update, "assemble")==0) { >+ int d = info->disk.number; >+ int wonly = sb->disks[d].state & (1<<MD_DISK_WRITEMOSTLY); >+ if ((sb->disks[d].state & ~(1<<MD_DISK_WRITEMOSTLY)) >+ != info->disk.state) { >+ sb->disks[d].state = info->disk.state | wonly; >+ rv = 1; >+ } >+ } >+ if (strcmp(update, "linear-grow-new") == 0) { >+ memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0])); >+ sb->disks[info->disk.number].number = info->disk.number; >+ sb->disks[info->disk.number].major = info->disk.major; >+ sb->disks[info->disk.number].minor = info->disk.minor; >+ sb->disks[info->disk.number].raid_disk = info->disk.raid_disk; >+ sb->disks[info->disk.number].state = info->disk.state; >+ sb->this_disk = sb->disks[info->disk.number]; >+ } >+ if (strcmp(update, "linear-grow-update") == 0) { >+ sb->raid_disks = info->array.raid_disks; >+ sb->nr_disks = info->array.nr_disks; >+ sb->active_disks = info->array.active_disks; >+ sb->working_disks = info->array.working_disks; >+ memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0])); >+ sb->disks[info->disk.number].number = info->disk.number; >+ sb->disks[info->disk.number].major = info->disk.major; >+ sb->disks[info->disk.number].minor = info->disk.minor; >+ sb->disks[info->disk.number].raid_disk = info->disk.raid_disk; >+ sb->disks[info->disk.number].state = info->disk.state; >+ } >+ if (strcmp(update, "resync") == 0) { >+ /* make sure resync happens */ >+ sb->state &= ~(1<<MD_SB_CLEAN); >+ sb->recovery_cp = 0; >+ } >+ if (strcmp(update, "homehost") == 0 && >+ homehost) { >+ uuid_set = 0; >+ update = "uuid"; >+ info->uuid[0] = sb->set_uuid0; >+ info->uuid[1] = sb->set_uuid1; >+ } >+ if (strcmp(update, "uuid") == 0) { >+ if (!uuid_set && homehost) { >+ char buf[20]; >+ char *hash = sha1_buffer(homehost, >+ strlen(homehost), >+ buf); >+ memcpy(info->uuid+2, hash, 8); >+ } >+ sb->set_uuid0 = info->uuid[0]; >+ sb->set_uuid1 = info->uuid[1]; >+ sb->set_uuid2 = info->uuid[2]; >+ sb->set_uuid3 = info->uuid[3]; >+ if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) { >+ struct bitmap_super_s *bm; >+ bm = (struct bitmap_super_s*)(sb+1); >+ uuid_from_super0((int*)bm->uuid, sbv); >+ } >+ } >+ if (strcmp(update, "_reshape_progress")==0) >+ sb->reshape_position = info->reshape_progress; >+ >+ sb->sb_csum = calc_sb0_csum(sb); >+ return rv; >+} >+ >+static int store_super0(struct supertype *st, int fd, void *sbv) >+{ >+ unsigned long long dsize; >+ unsigned long long offset; >+ mdp_super_t *super = sbv; >+ >+ if (!get_dev_size(fd, NULL, &dsize)) >+ return 1; >+ >+ if (dsize < MD_RESERVED_SECTORS*2*512) >+ return 2; >+ >+ offset = MD_NEW_SIZE_SECTORS(dsize>>9); >+ >+ offset *= 512; >+ >+ if (lseek64(fd, offset, 0)< 0LL) >+ return 3; >+ >+ if (write(fd, super, sizeof(*super)) != sizeof(*super)) >+ return 4; >+ >+ if (super->state & (1<<MD_SB_BITMAP_PRESENT)) { >+ struct bitmap_super_s * bm = (struct bitmap_super_s*)(super+1); >+ if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) >+ if (write(fd, bm, sizeof(*bm)) != sizeof(*bm)) >+ return 5; >+ } >+ >+ fsync(fd); >+ return 0; >+} >+ >+static int compare_super0(void **firstp, void *secondv) >+{ >+ /* >+ * return: >+ * 0 same, or first was empty, and second was copied >+ * 1 second had wrong number >+ * 2 wrong uuid >+ * 3 wrong other info >+ */ >+ mdp_super_t *first = *firstp; >+ mdp_super_t *second = secondv; >+ >+ int uuid1[4], uuid2[4]; >+ if (second->md_magic != MD_SB_MAGIC) >+ return 1; >+ if (!first) { >+ first = malloc(MD_SB_BYTES + sizeof(struct bitmap_super_s)); >+ memcpy(first, second, MD_SB_BYTES + sizeof(struct bitmap_super_s)); >+ *firstp = first; >+ return 0; >+ } >+ >+ uuid_from_super0(uuid1, first); >+ uuid_from_super0(uuid2, second); >+ if (!same_uuid(uuid1, uuid2, 0)) >+ 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; >+} >+ >+ >+static int load_super0(struct supertype *st, int fd, void **sbp, char *devname) >+{ >+ /* try to read in the superblock >+ * Return: >+ * 0 on success >+ * 1 on cannot get superblock >+ * 2 on superblock meaningless >+ */ >+ unsigned long long dsize; >+ unsigned long long offset; >+ mdp_super_t *super; >+ int uuid[4]; >+ struct bitmap_super_s *bsb; >+ >+ if (!get_dev_size(fd, devname, &dsize)) >+ return 1; >+ >+ if (dsize < MD_RESERVED_SECTORS*512 * 2) { >+ if (devname) >+ fprintf(stderr, Name >+ ": %s is too small for md: size is %llu sectors.\n", >+ devname, dsize); >+ return 1; >+ } >+ >+ offset = MD_NEW_SIZE_SECTORS(dsize>>9); >+ >+ offset *= 512; >+ >+ ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ >+ >+ if (lseek64(fd, offset, 0)< 0LL) { >+ if (devname) >+ fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", >+ devname, strerror(errno)); >+ return 1; >+ } >+ >+ super = malloc(MD_SB_BYTES + sizeof(bitmap_super_t)); >+ >+ if (read(fd, super, sizeof(*super)) != MD_SB_BYTES) { >+ if (devname) >+ fprintf(stderr, Name ": Cannot read superblock on %s\n", >+ devname); >+ free(super); >+ return 1; >+ } >+ >+ if (st->ss && st->minor_version == 9) >+ super0_swap_endian(super); >+ >+ if (super->md_magic != MD_SB_MAGIC) { >+ if (devname) >+ fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", >+ devname, MD_SB_MAGIC, super->md_magic); >+ free(super); >+ return 2; >+ } >+ >+ if (super->major_version != 0) { >+ if (devname) >+ fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", >+ devname, super->major_version); >+ free(super); >+ return 2; >+ } >+ *sbp = super; >+ if (st->ss == NULL) { >+ st->ss = &super0; >+ st->minor_version = 90; >+ st->max_devs = MD_SB_DISKS; >+ } >+ >+ /* Now check on the bitmap superblock */ >+ if ((super->state & (1<<MD_SB_BITMAP_PRESENT)) == 0) >+ return 0; >+ /* Read the bitmap superblock and make sure it looks >+ * valid. If it doesn't clear the bit. An --assemble --force >+ * should get that written out. >+ */ >+ if (read(fd, super+1, sizeof(struct bitmap_super_s)) >+ != sizeof(struct bitmap_super_s)) >+ goto no_bitmap; >+ >+ uuid_from_super0(uuid, super); >+ bsb = (struct bitmap_super_s *)(super+1); >+ if (__le32_to_cpu(bsb->magic) != BITMAP_MAGIC || >+ memcmp(bsb->uuid, uuid, 16) != 0) >+ goto no_bitmap; >+ return 0; >+ >+ no_bitmap: >+ super->state &= ~(1<<MD_SB_BITMAP_PRESENT); >+ >+ return 0; >+} >+ >+static struct supertype *match_metadata_desc0(char *arg) >+{ >+ struct supertype *st = malloc(sizeof(*st)); >+ if (!st) return st; >+ >+ st->ss = &super0; >+ st->minor_version = 90; >+ st->max_devs = MD_SB_DISKS; >+ if (strcmp(arg, "0") == 0 || >+ strcmp(arg, "0.90") == 0 || >+ strcmp(arg, "default") == 0 >+ ) >+ return st; >+ >+ st->minor_version = 9; /* flag for 'byte-swapped' */ >+ if (strcmp(arg, "0.swap")==0) >+ return st; >+ >+ free(st); >+ return NULL; >+} >+ >+void locate_bitmap0(struct supertype *st, int fd, void *sbv) >+{ >+ unsigned long long dsize; >+ unsigned long long offset; >+ >+ if (!get_dev_size(fd, NULL, &dsize)) >+ return; >+ >+ if (dsize < MD_RESERVED_SECTORS*512 * 2) >+ return; >+ >+ offset = MD_NEW_SIZE_SECTORS(dsize>>9); >+ >+ offset *= 512; >+ >+ offset += MD_SB_BYTES; >+ >+ lseek64(fd, offset, 0); >+} >+ >+struct superswitch super0 = { >+ .examine_super = NULL, >+ .brief_examine_super = brief_examine_super0, >+ .detail_super = NULL, >+ .brief_detail_super = NULL, >+ .export_super = NULL, >+ .match_home = match_home0, >+ .uuid_from_super = uuid_from_super0, >+ .getinfo_super = getinfo_super0, >+ .update_super = update_super0, >+ .init_super = NULL, >+ .add_to_super = NULL, >+ .store_super = store_super0, >+ .write_init_super = NULL, >+ .compare_super = compare_super0, >+ .load_super = load_super0, >+ .match_metadata_desc = match_metadata_desc0, >+ .avail_size = NULL, >+ .add_internal_bitmap = NULL, >+ .locate_bitmap = locate_bitmap0, >+ .write_bitmap = NULL, >+ .major = 0, >+ .swapuuid = 0, >+}; >--- a/mdadm/super1.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/super1.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,731 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * Paper: Neil Brown >+ * School of Computer Science and Engineering >+ * The University of New South Wales >+ * Sydney, 2052 >+ * Australia >+ */ >+ >+#include "mdadm.h" >+/* >+ * The version-1 superblock : >+ * All numeric fields are little-endian. >+ * >+ * total size: 256 bytes plus 2 per device. >+ * 1K allows 384 devices. >+ */ >+struct mdp_superblock_1 { >+ /* constant array information - 128 bytes */ >+ __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ >+ __u32 major_version; /* 1 */ >+ __u32 feature_map; /* 0 for now */ >+ __u32 pad0; /* always set to 0 when writing */ >+ >+ __u8 set_uuid[16]; /* user-space generated. */ >+ char set_name[32]; /* set and interpreted by user-space */ >+ >+ __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ >+ __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */ >+ __u32 layout; /* only for raid5 currently */ >+ __u64 size; /* used size of component devices, in 512byte sectors */ >+ >+ __u32 chunksize; /* in 512byte sectors */ >+ __u32 raid_disks; >+ __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts >+ * NOTE: signed, so bitmap can be before superblock >+ * only meaningful of feature_map[0] is set. >+ */ >+ >+ /* These are only valid with feature bit '4' */ >+ __u32 new_level; /* new level we are reshaping to */ >+ __u64 reshape_position; /* next address in array-space for reshape */ >+ __u32 delta_disks; /* change in number of raid_disks */ >+ __u32 new_layout; /* new layout */ >+ __u32 new_chunk; /* new chunk size (bytes) */ >+ __u8 pad1[128-124]; /* set to 0 when written */ >+ >+ /* constant this-device information - 64 bytes */ >+ __u64 data_offset; /* sector start of data, often 0 */ >+ __u64 data_size; /* sectors in this device that can be used for data */ >+ __u64 super_offset; /* sector start of this superblock */ >+ __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */ >+ __u32 dev_number; /* permanent identifier of this device - not role in raid */ >+ __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */ >+ __u8 device_uuid[16]; /* user-space setable, ignored by kernel */ >+ __u8 devflags; /* per-device flags. Only one defined...*/ >+#define WriteMostly1 1 /* mask for writemostly flag in above */ >+ __u8 pad2[64-57]; /* set to 0 when writing */ >+ >+ /* array state information - 64 bytes */ >+ __u64 utime; /* 40 bits second, 24 btes microseconds */ >+ __u64 events; /* incremented when superblock updated */ >+ __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */ >+ __u32 sb_csum; /* checksum upto devs[max_dev] */ >+ __u32 max_dev; /* size of devs[] array to consider */ >+ __u8 pad3[64-32]; /* set to 0 when writing */ >+ >+ /* device state information. Indexed by dev_number. >+ * 2 bytes per device >+ * Note there are no per-device state flags. State information is rolled >+ * into the 'roles' value. If a device is spare or faulty, then it doesn't >+ * have a meaningful role. >+ */ >+ __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ >+}; >+ >+struct misc_dev_info { >+ __u64 device_size; >+}; >+ >+/* feature_map bits */ >+#define MD_FEATURE_BITMAP_OFFSET 1 >+#define MD_FEATURE_RECOVERY_OFFSET 2 /* recovery_offset is present and >+ * must be honoured >+ */ >+#define MD_FEATURE_RESHAPE_ACTIVE 4 >+ >+#define MD_FEATURE_ALL (1|2|4) >+ >+#ifndef offsetof >+#define offsetof(t,f) ((size_t)&(((t*)0)->f)) >+#endif >+static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) >+{ >+ unsigned int disk_csum, csum; >+ unsigned long long newcsum; >+ int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2; >+ unsigned int *isuper = (unsigned int*)sb; >+ int i; >+ >+/* make sure I can count... */ >+ if (offsetof(struct mdp_superblock_1,data_offset) != 128 || >+ offsetof(struct mdp_superblock_1, utime) != 192 || >+ sizeof(struct mdp_superblock_1) != 256) { >+ fprintf(stderr, "WARNING - superblock isn't sized correctly\n"); >+ } >+ >+ disk_csum = sb->sb_csum; >+ sb->sb_csum = 0; >+ newcsum = 0; >+ for (i=0; size>=4; size -= 4 ) { >+ newcsum += __le32_to_cpu(*isuper); >+ isuper++; >+ } >+ >+ if (size == 2) >+ newcsum += __le16_to_cpu(*(unsigned short*) isuper); >+ >+ csum = (newcsum & 0xffffffff) + (newcsum >> 32); >+ sb->sb_csum = disk_csum; >+ return __cpu_to_le32(csum); >+} >+ >+static void brief_examine_super1(void *sbv) >+{ >+ struct mdp_superblock_1 *sb = sbv; >+ int i; >+ unsigned long long sb_offset; >+ char *nm; >+ char *c=map_num(pers, __le32_to_cpu(sb->level)); >+ >+ nm = strchr(sb->set_name, ':'); >+ if (nm) >+ nm++; >+ else if (sb->set_name[0]) >+ nm = sb->set_name; >+ else >+ nm = "??"; >+ >+ printf("ARRAY /dev/md%s level=%s ", nm, c?c:"-unknown-"); >+ sb_offset = __le64_to_cpu(sb->super_offset); >+ if (sb_offset <= 4) >+ printf("metadata=1.1 "); >+ else if (sb_offset <= 8) >+ printf("metadata=1.2 "); >+ else >+ printf("metadata=1.0 "); >+ printf("num-devices=%d UUID=", __le32_to_cpu(sb->raid_disks)); >+ for (i=0; i<16; i++) { >+ if ((i&3)==0 && i != 0) printf(":"); >+ printf("%02x", sb->set_uuid[i]); >+ } >+ if (sb->set_name[0]) >+ printf(" name=%.32s", sb->set_name); >+ printf("\n"); >+} >+ >+static int match_home1(void *sbv, char *homehost) >+{ >+ struct mdp_superblock_1 *sb = sbv; >+ int l = homehost ? strlen(homehost) : 0; >+ >+ return (l > 0 && l < 32 && >+ sb->set_name[l] == ':' && >+ strncmp(sb->set_name, homehost, l) == 0); >+} >+ >+static void uuid_from_super1(int uuid[4], void * sbv) >+{ >+ struct mdp_superblock_1 *super = sbv; >+ char *cuuid = (char*)uuid; >+ int i; >+ for (i=0; i<16; i++) >+ cuuid[i] = super->set_uuid[i]; >+} >+ >+static void getinfo_super1(struct mdinfo *info, void *sbv) >+{ >+ struct mdp_superblock_1 *sb = sbv; >+ int working = 0; >+ int i; >+ int role; >+ >+ info->array.major_version = 1; >+ info->array.minor_version = __le32_to_cpu(sb->feature_map); >+ info->array.patch_version = 0; >+ info->array.raid_disks = __le32_to_cpu(sb->raid_disks); >+ info->array.level = __le32_to_cpu(sb->level); >+ info->array.layout = __le32_to_cpu(sb->layout); >+ info->array.md_minor = -1; >+ info->array.ctime = __le64_to_cpu(sb->ctime); >+ info->array.utime = __le64_to_cpu(sb->utime); >+ info->array.chunk_size = __le32_to_cpu(sb->chunksize)*512; >+ info->array.state = >+ (__le64_to_cpu(sb->resync_offset) >= __le64_to_cpu(sb->size)) >+ ? 1 : 0; >+ >+ info->data_offset = __le64_to_cpu(sb->data_offset); >+ info->component_size = __le64_to_cpu(sb->size); >+ >+ info->disk.major = 0; >+ info->disk.minor = 0; >+ info->disk.number = __le32_to_cpu(sb->dev_number); >+ if (__le32_to_cpu(sb->dev_number) >= __le32_to_cpu(sb->max_dev) || >+ __le32_to_cpu(sb->max_dev) > 512) >+ role = 0xfffe; >+ else >+ role = __le16_to_cpu(sb->dev_roles[__le32_to_cpu(sb->dev_number)]); >+ >+ info->disk.raid_disk = -1; >+ switch(role) { >+ case 0xFFFF: >+ info->disk.state = 2; /* spare: ACTIVE, not sync, not faulty */ >+ break; >+ case 0xFFFE: >+ info->disk.state = 1; /* faulty */ >+ break; >+ default: >+ info->disk.state = 6; /* active and in sync */ >+ info->disk.raid_disk = role; >+ } >+ info->events = __le64_to_cpu(sb->events); >+ >+ memcpy(info->uuid, sb->set_uuid, 16); >+ >+ strncpy(info->name, sb->set_name, 32); >+ info->name[32] = 0; >+ >+ if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RESHAPE_ACTIVE)) { >+ info->reshape_active = 1; >+ info->reshape_progress = __le64_to_cpu(sb->reshape_position); >+ info->new_level = __le32_to_cpu(sb->new_level); >+ info->delta_disks = __le32_to_cpu(sb->delta_disks); >+ info->new_layout = __le32_to_cpu(sb->new_layout); >+ info->new_chunk = __le32_to_cpu(sb->new_chunk)<<9; >+ } else >+ info->reshape_active = 0; >+ >+ for (i=0; i< __le32_to_cpu(sb->max_dev); i++) { >+ role = __le16_to_cpu(sb->dev_roles[i]); >+ if (/*role == 0xFFFF || */role < info->array.raid_disks) >+ working++; >+ } >+ >+ info->array.working_disks = working; >+} >+ >+static int update_super1(struct mdinfo *info, void *sbv, char *update, >+ char *devname, int verbose, >+ int uuid_set, char *homehost) >+{ >+ /* NOTE: for 'assemble' and 'force' we need to return non-zero if any change was made. >+ * For others, the return value is ignored. >+ */ >+ int rv = 0; >+ struct mdp_superblock_1 *sb = sbv; >+ >+ if (strcmp(update, "force-one")==0) { >+ /* Not enough devices for a working array, >+ * so bring this one up-to-date >+ */ >+ if (sb->events != __cpu_to_le64(info->events)) >+ rv = 1; >+ sb->events = __cpu_to_le64(info->events); >+ } >+ if (strcmp(update, "force-array")==0) { >+ /* Degraded array and 'force' requests to >+ * maybe need to mark it 'clean'. >+ */ >+ switch(__le32_to_cpu(sb->level)) { >+ case 5: case 4: case 6: >+ /* need to force clean */ >+ if (sb->resync_offset != ~0ULL) >+ rv = 1; >+ sb->resync_offset = ~0ULL; >+ } >+ } >+ if (strcmp(update, "assemble")==0) { >+ int d = info->disk.number; >+ int want; >+ if (info->disk.state == 6) >+ want = __cpu_to_le32(info->disk.raid_disk); >+ else >+ want = 0xFFFF; >+ if (sb->dev_roles[d] != want) { >+ sb->dev_roles[d] = want; >+ rv = 1; >+ } >+ } >+ if (strcmp(update, "linear-grow-new") == 0) { >+ int i; >+ int rfd; >+ int max = __le32_to_cpu(sb->max_dev); >+ >+ for (i=0 ; i < max ; i++) >+ if (__le16_to_cpu(sb->dev_roles[i]) >= 0xfffe) >+ break; >+ sb->dev_number = __cpu_to_le32(i); >+ info->disk.number = i; >+ if (max >= __le32_to_cpu(sb->max_dev)) >+ sb->max_dev = __cpu_to_le32(max+1); >+ >+ if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || >+ read(rfd, sb->device_uuid, 16) != 16) { >+ *(__u32*)(sb->device_uuid) = random(); >+ *(__u32*)(sb->device_uuid+4) = random(); >+ *(__u32*)(sb->device_uuid+8) = random(); >+ *(__u32*)(sb->device_uuid+12) = random(); >+ } >+ >+ sb->dev_roles[i] = >+ __cpu_to_le16(info->disk.raid_disk); >+ } >+ if (strcmp(update, "linear-grow-update") == 0) { >+ sb->raid_disks = __cpu_to_le32(info->array.raid_disks); >+ sb->dev_roles[info->disk.number] = >+ __cpu_to_le16(info->disk.raid_disk); >+ } >+ if (strcmp(update, "resync") == 0) { >+ /* make sure resync happens */ >+ sb->resync_offset = 0ULL; >+ } >+ if (strcmp(update, "uuid") == 0) { >+ copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid); >+ >+ if (__le32_to_cpu(sb->feature_map)&MD_FEATURE_BITMAP_OFFSET) { >+ struct bitmap_super_s *bm; >+ bm = (struct bitmap_super_s*)(sbv+1024); >+ memcpy(bm->uuid, sb->set_uuid, 16); >+ } >+ } >+ if (strcmp(update, "homehost") == 0 && >+ homehost) { >+ char *c; >+ update = "name"; >+ c = strchr(sb->set_name, ':'); >+ if (c) >+ strncpy(info->name, c+1, 31 - (c-sb->set_name)); >+ else >+ strncpy(info->name, sb->set_name, 32); >+ info->name[32] = 0; >+ } >+ if (strcmp(update, "name") == 0) { >+ if (info->name[0] == 0) >+ sprintf(info->name, "%d", info->array.md_minor); >+ memset(sb->set_name, 0, sizeof(sb->set_name)); >+ if (homehost && >+ strchr(info->name, ':') == NULL && >+ strlen(homehost)+1+strlen(info->name) < 32) { >+ strcpy(sb->set_name, homehost); >+ strcat(sb->set_name, ":"); >+ strcat(sb->set_name, info->name); >+ } else >+ strcpy(sb->set_name, info->name); >+ } >+ if (strcmp(update, "devicesize") == 0 && >+ __le64_to_cpu(sb->super_offset) < >+ __le64_to_cpu(sb->data_offset)) { >+ /* set data_size to device size less data_offset */ >+ struct misc_dev_info *misc = (struct misc_dev_info*) >+ (sbv + 1024 + sizeof(struct bitmap_super_s)); >+ printf("Size was %llu\n", (unsigned long long) >+ __le64_to_cpu(sb->data_size)); >+ sb->data_size = __cpu_to_le64( >+ misc->device_size - __le64_to_cpu(sb->data_offset)); >+ printf("Size is %llu\n", (unsigned long long) >+ __le64_to_cpu(sb->data_size)); >+ } >+ if (strcmp(update, "_reshape_progress")==0) >+ sb->reshape_position = __cpu_to_le64(info->reshape_progress); >+ >+ sb->sb_csum = calc_sb_1_csum(sb); >+ return rv; >+} >+ >+static void locate_bitmap1(struct supertype *st, int fd, void *sbv); >+ >+static int store_super1(struct supertype *st, int fd, void *sbv) >+{ >+ struct mdp_superblock_1 *sb = sbv; >+ unsigned long long sb_offset; >+ int sbsize; >+ unsigned long long dsize; >+ >+ if (!get_dev_size(fd, NULL, &dsize)) >+ return 1; >+ >+ dsize >>= 9; >+ >+ if (dsize < 24) >+ return 2; >+ >+ /* >+ * Calculate the position of the superblock. >+ * It is always aligned to a 4K boundary and >+ * depending on minor_version, it can be: >+ * 0: At least 8K, but less than 12K, from end of device >+ * 1: At start of device >+ * 2: 4K from start of device. >+ */ >+ switch(st->minor_version) { >+ case 0: >+ sb_offset = dsize; >+ sb_offset -= 8*2; >+ sb_offset &= ~(4*2-1); >+ break; >+ case 1: >+ sb_offset = 0; >+ break; >+ case 2: >+ sb_offset = 4*2; >+ break; >+ default: >+ return -EINVAL; >+ } >+ >+ >+ >+ if (sb_offset != __le64_to_cpu(sb->super_offset) && >+ 0 != __le64_to_cpu(sb->super_offset) >+ ) { >+ fprintf(stderr, Name ": internal error - sb_offset is wrong\n"); >+ abort(); >+ } >+ >+ if (lseek64(fd, sb_offset << 9, 0)< 0LL) >+ return 3; >+ >+ sbsize = sizeof(*sb) + 2 * __le32_to_cpu(sb->max_dev); >+ >+ if (write(fd, sb, sbsize) != sbsize) >+ return 4; >+ >+ if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) { >+ struct bitmap_super_s *bm = (struct bitmap_super_s*) >+ (((char*)sb)+1024); >+ if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) { >+ locate_bitmap1(st, fd, sbv); >+ if (write(fd, bm, sizeof(*bm)) != sizeof(*bm)) >+ return 5; >+ } >+ } >+ fsync(fd); >+ return 0; >+} >+ >+static int load_super1(struct supertype *st, int fd, void **sbp, char *devname); >+ >+static int compare_super1(void **firstp, void *secondv) >+{ >+ /* >+ * return: >+ * 0 same, or first was empty, and second was copied >+ * 1 second had wrong number >+ * 2 wrong uuid >+ * 3 wrong other info >+ */ >+ struct mdp_superblock_1 *first = *firstp; >+ struct mdp_superblock_1 *second = secondv; >+ >+ if (second->magic != __cpu_to_le32(MD_SB_MAGIC)) >+ return 1; >+ if (second->major_version != __cpu_to_le32(1)) >+ return 1; >+ >+ if (!first) { >+ first = malloc(1024+sizeof(bitmap_super_t) + >+ sizeof(struct misc_dev_info)); >+ memcpy(first, second, 1024+sizeof(bitmap_super_t) + >+ sizeof(struct misc_dev_info)); >+ *firstp = first; >+ return 0; >+ } >+ if (memcmp(first->set_uuid, second->set_uuid, 16)!= 0) >+ return 2; >+ >+ if (first->ctime != second->ctime || >+ first->level != second->level || >+ first->layout != second->layout || >+ first->size != second->size || >+ first->chunksize != second->chunksize || >+ first->raid_disks != second->raid_disks) >+ return 3; >+ return 0; >+} >+ >+static int load_super1(struct supertype *st, int fd, void **sbp, char *devname) >+{ >+ unsigned long long dsize; >+ unsigned long long sb_offset; >+ struct mdp_superblock_1 *super; >+ int uuid[4]; >+ struct bitmap_super_s *bsb; >+ struct misc_dev_info *misc; >+ >+ >+ if (st->ss == NULL) { >+ int bestvers = -1; >+ __u64 bestctime = 0; >+ /* guess... choose latest ctime */ >+ st->ss = &super1; >+ for (st->minor_version = 0; st->minor_version <= 2 ; st->minor_version++) { >+ switch(load_super1(st, fd, sbp, devname)) { >+ case 0: super = *sbp; >+ if (bestvers == -1 || >+ bestctime < __le64_to_cpu(super->ctime)) { >+ bestvers = st->minor_version; >+ bestctime = __le64_to_cpu(super->ctime); >+ } >+ free(super); >+ *sbp = NULL; >+ break; >+ case 1: st->ss = NULL; return 1; /*bad device */ >+ case 2: break; /* bad, try next */ >+ } >+ } >+ if (bestvers != -1) { >+ int rv; >+ st->minor_version = bestvers; >+ st->ss = &super1; >+ st->max_devs = 384; >+ rv = load_super1(st, fd, sbp, devname); >+ if (rv) st->ss = NULL; >+ return rv; >+ } >+ st->ss = NULL; >+ return 2; >+ } >+ if (!get_dev_size(fd, devname, &dsize)) >+ return 1; >+ dsize >>= 9; >+ >+ if (dsize < 24) { >+ if (devname) >+ fprintf(stderr, Name ": %s is too small for md: size is %llu sectors.\n", >+ devname, dsize); >+ return 1; >+ } >+ >+ /* >+ * Calculate the position of the superblock. >+ * It is always aligned to a 4K boundary and >+ * depending on minor_version, it can be: >+ * 0: At least 8K, but less than 12K, from end of device >+ * 1: At start of device >+ * 2: 4K from start of device. >+ */ >+ switch(st->minor_version) { >+ case 0: >+ sb_offset = dsize; >+ sb_offset -= 8*2; >+ sb_offset &= ~(4*2-1); >+ break; >+ case 1: >+ sb_offset = 0; >+ break; >+ case 2: >+ sb_offset = 4*2; >+ break; >+ default: >+ return -EINVAL; >+ } >+ >+ ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ >+ >+ >+ if (lseek64(fd, sb_offset << 9, 0)< 0LL) { >+ if (devname) >+ fprintf(stderr, Name ": Cannot seek to superblock on %s: %s\n", >+ devname, strerror(errno)); >+ return 1; >+ } >+ >+ super = malloc(1024 + sizeof(bitmap_super_t) + >+ sizeof(struct misc_dev_info)); >+ >+ if (read(fd, super, 1024) != 1024) { >+ if (devname) >+ fprintf(stderr, Name ": Cannot read superblock on %s\n", >+ devname); >+ free(super); >+ return 1; >+ } >+ >+ if (__le32_to_cpu(super->magic) != MD_SB_MAGIC) { >+ if (devname) >+ fprintf(stderr, Name ": No super block found on %s (Expected magic %08x, got %08x)\n", >+ devname, MD_SB_MAGIC, __le32_to_cpu(super->magic)); >+ free(super); >+ return 2; >+ } >+ >+ if (__le32_to_cpu(super->major_version) != 1) { >+ if (devname) >+ fprintf(stderr, Name ": Cannot interpret superblock on %s - version is %d\n", >+ devname, __le32_to_cpu(super->major_version)); >+ free(super); >+ return 2; >+ } >+ if (__le64_to_cpu(super->super_offset) != sb_offset) { >+ if (devname) >+ fprintf(stderr, Name ": No superblock found on %s (super_offset is wrong)\n", >+ devname); >+ free(super); >+ return 2; >+ } >+ *sbp = super; >+ >+ bsb = (struct bitmap_super_s *)(((char*)super)+1024); >+ >+ misc = (struct misc_dev_info*) (bsb+1); >+ misc->device_size = dsize; >+ >+ /* Now check on the bitmap superblock */ >+ if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0) >+ return 0; >+ /* Read the bitmap superblock and make sure it looks >+ * valid. If it doesn't clear the bit. An --assemble --force >+ * should get that written out. >+ */ >+ locate_bitmap1(st, fd, super); >+ if (read(fd, ((char*)super)+1024, sizeof(struct bitmap_super_s)) >+ != sizeof(struct bitmap_super_s)) >+ goto no_bitmap; >+ >+ uuid_from_super1(uuid, super); >+ if (__le32_to_cpu(bsb->magic) != BITMAP_MAGIC || >+ memcmp(bsb->uuid, uuid, 16) != 0) >+ goto no_bitmap; >+ return 0; >+ >+ no_bitmap: >+ super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) & ~1); >+ return 0; >+} >+ >+ >+static struct supertype *match_metadata_desc1(char *arg) >+{ >+ struct supertype *st = malloc(sizeof(*st)); >+ if (!st) return st; >+ >+ st->ss = &super1; >+ st->max_devs = 384; >+ if (strcmp(arg, "1") == 0 || >+ strcmp(arg, "1.0") == 0 || >+ strcmp(arg, "default/large") == 0) { >+ st->minor_version = 0; >+ return st; >+ } >+ if (strcmp(arg, "1.1") == 0) { >+ st->minor_version = 1; >+ return st; >+ } >+ if (strcmp(arg, "1.2") == 0) { >+ st->minor_version = 2; >+ return st; >+ } >+ >+ free(st); >+ return NULL; >+} >+ >+static void locate_bitmap1(struct supertype *st, int fd, void *sbv) >+{ >+ unsigned long long offset; >+ struct mdp_superblock_1 *sb; >+ int mustfree = 0; >+ >+ if (!sbv) { >+ if (st->ss->load_super(st, fd, &sbv, NULL)) >+ return; /* no error I hope... */ >+ mustfree = 1; >+ } >+ sb = sbv; >+ >+ offset = __le64_to_cpu(sb->super_offset); >+ offset += (int32_t) __le32_to_cpu(sb->bitmap_offset); >+ if (mustfree) >+ free(sb); >+ lseek64(fd, offset<<9, 0); >+} >+ >+struct superswitch super1 = { >+ .examine_super = NULL, >+ .brief_examine_super = brief_examine_super1, >+ .detail_super = NULL, >+ .brief_detail_super = NULL, >+ .export_super = NULL, >+ .match_home = match_home1, >+ .uuid_from_super = uuid_from_super1, >+ .getinfo_super = getinfo_super1, >+ .update_super = update_super1, >+ .init_super = NULL, >+ .add_to_super = NULL, >+ .store_super = store_super1, >+ .write_init_super = NULL, >+ .compare_super = compare_super1, >+ .load_super = load_super1, >+ .match_metadata_desc = match_metadata_desc1, >+ .avail_size = NULL, >+ .add_internal_bitmap = NULL, >+ .locate_bitmap = locate_bitmap1, >+ .write_bitmap = NULL, >+ .major = 1, >+#if __BYTE_ORDER == BIG_ENDIAN >+ .swapuuid = 0, >+#else >+ .swapuuid = 1, >+#endif >+}; >--- a/mdadm/util.c 1970-01-01 03:00:00.000000000 +0300 >+++ mdadm/mdadm/util.c 2011-01-12 21:33:01.000000000 +0200 >@@ -0,0 +1,652 @@ >+/* >+ * mdadm - manage Linux "md" devices aka RAID arrays. >+ * >+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de> >+ * >+ * >+ * 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: <neilb@cse.unsw.edu.au> >+ * 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 <sys/utsname.h> >+#include <ctype.h> >+ >+/* >+ * following taken from linux/blkpg.h because they aren't >+ * anywhere else and it isn't safe to #include linux/ * stuff. >+ */ >+ >+#define BLKPG _IO(0x12,105) >+ >+/* The argument structure */ >+struct blkpg_ioctl_arg { >+ int op; >+ int flags; >+ int datalen; >+ void *data; >+}; >+ >+/* The subfunctions (for the op field) */ >+#define BLKPG_ADD_PARTITION 1 >+#define BLKPG_DEL_PARTITION 2 >+ >+/* Sizes of name fields. Unused at present. */ >+#define BLKPG_DEVNAMELTH 64 >+#define BLKPG_VOLNAMELTH 64 >+ >+/* The data structure for ADD_PARTITION and DEL_PARTITION */ >+struct blkpg_partition { >+ long long start; /* starting offset in bytes */ >+ long long length; /* length in bytes */ >+ int pno; /* partition number */ >+ char devname[BLKPG_DEVNAMELTH]; /* partition name, like sda5 or c0d1p2, >+ to be used in kernel messages */ >+ char volname[BLKPG_VOLNAMELTH]; /* volume label */ >+}; >+ >+/* >+ * Parse a 128 bit uuid in 4 integers >+ * format is 32 hexx nibbles with options :.<space> 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; >+} >+ >+void remove_partitions(int fd) >+{ >+ /* remove partitions from this block devices. >+ * This is used for components added to an array >+ */ >+#ifdef BLKPG_DEL_PARTITION >+ struct blkpg_ioctl_arg a; >+ struct blkpg_partition p; >+ >+ a.op = BLKPG_DEL_PARTITION; >+ a.data = (void*)&p; >+ a.datalen = sizeof(p); >+ a.flags = 0; >+ memset(a.data, 0, a.datalen); >+ for (p.pno=0; p.pno < 16; p.pno++) >+ ioctl(fd, BLKPG, &a); >+#endif >+} >+ >+int enough(int level, int raid_disks, int layout, int clean, >+ char *avail, int avail_disks) >+{ >+ int copies, first; >+ switch (level) { >+ case 10: >+ /* This is the tricky one - we need to check >+ * which actual disks are present. >+ */ >+ copies = (layout&255)* ((layout>>8) & 255); >+ first=0; >+ do { >+ /* there must be one of the 'copies' form 'first' */ >+ int n = copies; >+ int cnt=0; >+ while (n--) { >+ if (avail[first]) >+ cnt++; >+ first = (first+1) % raid_disks; >+ } >+ if (cnt == 0) >+ return 0; >+ >+ } while (first != 0); >+ return 1; >+ >+ 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: >+ if (clean) >+ return avail_disks >= raid_disks-1; >+ else >+ return avail_disks >= raid_disks; >+ case 6: >+ if (clean) >+ return avail_disks >= raid_disks-2; >+ else >+ return avail_disks >= raid_disks; >+ default: >+ return 0; >+ } >+} >+ >+int same_uuid(int a[4], int b[4], int swapuuid) >+{ >+ if (swapuuid) { >+ /* parse uuids are hostendian. >+ * uuid's from some superblocks are big-ending >+ * if there is a difference, we need to swap.. >+ */ >+ unsigned char *ac = (unsigned char *)a; >+ unsigned char *bc = (unsigned char *)b; >+ int i; >+ for (i=0; i<16; i+= 4) { >+ if (ac[i+0] != bc[i+3] || >+ ac[i+1] != bc[i+2] || >+ ac[i+2] != bc[i+1] || >+ ac[i+3] != bc[i+0]) >+ return 0; >+ } >+ return 1; >+ } else { >+ if (a[0]==b[0] && >+ a[1]==b[1] && >+ a[2]==b[2] && >+ a[3]==b[3]) >+ return 1; >+ return 0; >+ } >+} >+void copy_uuid(void *a, int b[4], int swapuuid) >+{ >+ if (swapuuid) { >+ /* parse uuids are hostendian. >+ * uuid's from some superblocks are big-ending >+ * if there is a difference, we need to swap.. >+ */ >+ unsigned char *ac = (unsigned char *)a; >+ unsigned char *bc = (unsigned char *)b; >+ int i; >+ for (i=0; i<16; i+= 4) { >+ ac[i+0] = bc[i+3]; >+ ac[i+1] = bc[i+2]; >+ ac[i+2] = bc[i+1]; >+ ac[i+3] = bc[i+0]; >+ } >+ } else >+ memcpy(a, b, 16); >+} >+ >+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; >+} >+ >+ >+int is_standard(char *dev, int *nump) >+{ >+ /* tests if dev is a "standard" md dev name. >+ * i.e if the last component is "/dNN" or "/mdNN", >+ * where NN is a string of digits >+ */ >+ char *d = strrchr(dev, '/'); >+ int type=0; >+ int num; >+ if (!d) >+ return 0; >+ if (strncmp(d, "/d",2)==0) >+ d += 2, type=1; /* /dev/md/dN{pM} */ >+ else if (strncmp(d, "/md_d", 5)==0) >+ d += 5, type=1; /* /dev/md_dNpM */ >+ else if (strncmp(d, "/md", 3)==0) >+ d += 3, type=-1; /* /dev/mdN */ >+ else if (d-dev > 3 && strncmp(d-2, "md/", 3)==0) >+ d += 1, type=-1; /* /dev/md/N */ >+ else >+ return 0; >+ if (!*d) >+ return 0; >+ num = atoi(d); >+ while (isdigit(*d)) >+ d++; >+ if (*d) >+ return 0; >+ if (nump) *nump = num; >+ >+ return type; >+} >+ >+ >+/* >+ * convert a major/minor pair for a block device into a name in /dev, if possible. >+ * On the first call, walk /dev collecting name. >+ * Put them in a simple linked listfor now. >+ */ >+struct devmap { >+ int major, minor; >+ char *name; >+ struct devmap *next; >+} *devlist = NULL; >+int devlist_ready = 0; >+ >+int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s) >+{ >+ struct stat st; >+ if (S_ISLNK(stb->st_mode)) { >+ stat(name, &st); >+ stb = &st; >+ } >+ >+ if ((stb->st_mode&S_IFMT)== S_IFBLK) { >+ char *n = strdup(name); >+ struct devmap *dm = malloc(sizeof(*dm)); >+ if (strncmp(n, "/dev/./", 7)==0) >+ strcpy(n+4, name+6); >+ if (dm) { >+ dm->major = major(stb->st_rdev); >+ dm->minor = minor(stb->st_rdev); >+ dm->name = n; >+ dm->next = devlist; >+ devlist = dm; >+ } >+ } >+ return 0; >+} >+ >+#ifndef HAVE_NFTW >+#ifdef HAVE_FTW >+int add_dev_1(const char *name, const struct stat *stb, int flag) >+{ >+ return add_dev(name, stb, flag, NULL); >+} >+int nftw(const char *path, int (*han)(const char *name, const struct stat *stb, int flag, struct FTW *s), int nopenfd, int flags) >+{ >+ return ftw(path, add_dev_1, nopenfd); >+} >+#else >+int nftw(const char *path, int (*han)(const char *name, const struct stat *stb, int flag, struct FTW *s), int nopenfd, int flags) >+{ >+ return 0; >+} >+#endif /* HAVE_FTW */ >+#endif /* HAVE_NFTW */ >+ >+/* >+ * Find a block device with the right major/minor number. >+ * If we find multiple names, choose the shortest. >+ * If we find a non-standard name, it is probably there >+ * deliberately so prefer it over a standard name. >+ * This applies only to names for MD devices. >+ */ >+char *map_dev(int major, int minor, int create) >+{ >+ struct devmap *p; >+ char *std = NULL, *nonstd=NULL; >+ int did_check = 0; >+ >+ if (major == 0 && minor == 0) >+ return NULL; >+ >+ retry: >+ if (!devlist_ready) { >+ char *dev = "/dev"; >+ struct stat stb; >+ while(devlist) { >+ struct devmap *d = devlist; >+ devlist = d->next; >+ free(d->name); >+ free(d); >+ } >+ if (lstat(dev, &stb)==0 && >+ S_ISLNK(stb.st_mode)) >+ dev = "/dev/."; >+ nftw(dev, add_dev, 10, FTW_PHYS); >+ devlist_ready=1; >+ did_check = 1; >+ } >+ >+ for (p=devlist; p; p=p->next) >+ if (p->major == major && >+ p->minor == minor) { >+ if (is_standard(p->name, NULL)) { >+ if (std == NULL || >+ strlen(p->name) < strlen(std)) >+ std = p->name; >+ } else { >+ if (nonstd == NULL || >+ strlen(p->name) < strlen(nonstd)) >+ nonstd = p->name; >+ } >+ } >+ if (!std && !nonstd && !did_check) { >+ devlist_ready = 0; >+ goto retry; >+ } >+ if (create && !std && !nonstd) { >+ static char buf[30]; >+ snprintf(buf, sizeof(buf), "%d:%d", major, minor); >+ nonstd = buf; >+ } >+ >+ return nonstd ? nonstd : std; >+} >+ >+unsigned long calc_csum(void *super, int bytes) >+{ >+ unsigned long long newcsum = 0; >+ int i; >+ unsigned int csum; >+ unsigned int *superc = (unsigned int*) super; >+ >+ for(i=0; i<bytes/4; i++) >+ newcsum+= superc[i]; >+ csum = (newcsum& 0xffffffff) + (newcsum>>32); >+#ifdef __alpha__ >+/* The in-kernel checksum calculation is always 16bit on >+ * the alpha, though it is 32 bit on i386... >+ * I wonder what it is elsewhere... (it uses and API in >+ * a way that it shouldn't). >+ */ >+ csum = (csum & 0xffff) + (csum >> 16); >+ csum = (csum & 0xffff) + (csum >> 16); >+#endif >+ return csum; >+} >+ >+char *human_size(long long bytes) >+{ >+ static char buf[30]; >+ >+ /* We convert bytes to either centi-M{ega,ibi}bytes or >+ * centi-G{igi,ibi}bytes, with appropriate rounding, >+ * and then print 1/100th of those as a decimal. >+ * We allow upto 2048Megabytes before converting to >+ * gigabytes, as that shows more precision and isn't >+ * too large a number. >+ * Terrabytes are not yet handled. >+ */ >+ >+ if (bytes < 5000*1024) >+ buf[0]=0; >+ else if (bytes < 2*1024LL*1024LL*1024LL) { >+ long cMiB = (bytes / ( (1LL<<20) / 200LL ) +1) /2; >+ long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2; >+ snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)", >+ cMiB/100 , cMiB % 100, >+ cMB/100, cMB % 100); >+ } else { >+ long cGiB = (bytes / ( (1LL<<30) / 200LL ) +1) /2; >+ long cGB = (bytes / (1000000000LL/200LL ) +1) /2; >+ snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)", >+ cGiB/100 , cGiB % 100, >+ cGB/100, cGB % 100); >+ } >+ return buf; >+} >+ >+char *human_size_brief(long long bytes) >+{ >+ static char buf[30]; >+ >+ >+ if (bytes < 5000*1024) >+ snprintf(buf, sizeof(buf), "%ld.%02ldKiB", >+ (long)(bytes>>10), (long)(((bytes&1023)*100+512)/1024) >+ ); >+ else if (bytes < 2*1024LL*1024LL*1024LL) >+ snprintf(buf, sizeof(buf), "%ld.%02ldMiB", >+ (long)(bytes>>20), >+ (long)((bytes&0xfffff)+0x100000/200)/(0x100000/100) >+ ); >+ else >+ snprintf(buf, sizeof(buf), "%ld.%02ldGiB", >+ (long)(bytes>>30), >+ (long)(((bytes>>10)&0xfffff)+0x100000/200)/(0x100000/100) >+ ); >+ return buf; >+} >+ >+int get_mdp_major(void) >+{ >+static int mdp_major = -1; >+ FILE *fl; >+ char *w; >+ int have_block = 0; >+ int have_devices = 0; >+ int last_num = -1; >+ >+ if (mdp_major != -1) >+ return mdp_major; >+ fl = fopen("/proc/devices", "r"); >+ if (!fl) >+ return -1; >+ 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); >+ return mdp_major; >+} >+ >+int dev_open(char *dev, int flags) >+{ >+ /* like 'open', but if 'dev' matches %d:%d, create a temp >+ * block device and open that >+ */ >+ char *e; >+ int fd = -1; >+ char devname[32]; >+ int major; >+ int minor; >+ >+ if (!dev) return -1; >+ >+ major = strtoul(dev, &e, 0); >+ if (e > dev && *e == ':' && e[1] && >+ (minor = strtoul(e+1, &e, 0)) >= 0 && >+ *e == 0) { >+ snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d", major, minor); >+ if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) { >+ fd = open(devname, flags); >+ unlink(devname); >+ } >+ } else >+ fd = open(dev, flags); >+ return fd; >+} >+ >+struct superswitch *superlist[] = { &super0, &super1, NULL }; >+ >+struct supertype *super_by_version(int vers, int minor) >+{ >+ struct supertype *st = malloc(sizeof(*st)); >+ if (!st) return st; >+ if (vers == 0) { >+ st->ss = &super0; >+ st->max_devs = MD_SB_DISKS; >+ } >+ >+ if (vers == 1) { >+ st->ss = &super1; >+ st->max_devs = 384; >+ } >+ st->minor_version = minor; >+ return st; >+} >+ >+struct supertype *guess_super(int fd) >+{ >+ /* try each load_super to find the best match, >+ * and return the best superswitch >+ */ >+ struct superswitch *ss; >+ struct supertype *st; >+ unsigned long besttime = 0; >+ int bestsuper = -1; >+ >+ void *sbp = NULL; >+ int i; >+ >+ st = malloc(sizeof(*st)); >+ memset(st, 0, sizeof(*st)); >+ for (i=0 ; superlist[i]; i++) { >+ int rv; >+ ss = superlist[i]; >+ st->ss = NULL; >+ rv = ss->load_super(st, fd, &sbp, NULL); >+ if (rv == 0) { >+ struct mdinfo info; >+ ss->getinfo_super(&info, sbp); >+ if (bestsuper == -1 || >+ besttime < info.array.ctime) { >+ bestsuper = i; >+ besttime = info.array.ctime; >+ } >+ free(sbp); >+ } >+ } >+ if (bestsuper != -1) { >+ int rv; >+ st->ss = NULL; >+ rv = superlist[bestsuper]->load_super(st, fd, &sbp, NULL); >+ if (rv == 0) { >+ free(sbp); >+ return st; >+ } >+ } >+ free(st); >+ return NULL; >+} >+ >+/* Return size of device in bytes */ >+int get_dev_size(int fd, char *dname, unsigned long long *sizep) >+{ >+ unsigned long long ldsize; >+#ifdef BLKGETSIZE64 >+ if (ioctl(fd, BLKGETSIZE64, &ldsize) != 0) >+#endif >+ { >+ unsigned long dsize; >+ if (ioctl(fd, BLKGETSIZE, &dsize) == 0) { >+ ldsize = dsize; >+ ldsize <<= 9; >+ } else { >+ if (dname) >+ fprintf(stderr, Name ": Cannot get size of %s: %s\b", >+ dname, strerror(errno)); >+ return 0; >+ } >+ } >+ *sizep = ldsize; >+ return 1; >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 331971
:
248723
|
248725
|
255835
|
255837
|
255839
|
255875
|
256047
|
256348
|
258432
|
258945
|
259650
| 262061