/*
* mdadm - manage Linux "md" devices aka RAID arrays.
*
- * Copyright (C) 2001-2004 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
*
*
* This program is free software; you can redistribute it and/or modify
*/
#include "mdadm.h"
-#include <endian.h>
-#include "asm/byteorder.h"
/*
* The version-1 superblock :
* All numeric fields are little-endian.
*/
/* These are only valid with feature bit '4' */
- __u64 reshape_position; /* next address in array-space for reshape */
__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) */
#define MD_FEATURE_ALL (1|2|4)
#ifndef offsetof
-#define offsetof(t,f) ((int)&(((t*)0)->f))
+#define offsetof(t,f) ((size_t)&(((t*)0)->f))
#endif
static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
{
disk_csum = sb->sb_csum;
sb->sb_csum = 0;
newcsum = 0;
- for (i=0; size>=4; size -= 4 )
- newcsum += __le32_to_cpu(*isuper++);
+ for (i=0; size>=4; size -= 4 ) {
+ newcsum += __le32_to_cpu(*isuper);
+ isuper++;
+ }
if (size == 2)
newcsum += __le16_to_cpu(*(unsigned short*) isuper);
}
#ifndef MDASSEMBLE
-static void examine_super1(void *sbv)
+static void examine_super1(void *sbv, char *homehost)
{
struct mdp_superblock_1 *sb = sbv;
time_t atime;
int faulty;
int i;
char *c;
+ int l = homehost ? strlen(homehost) : 0;
printf(" Magic : %08x\n", __le32_to_cpu(sb->magic));
- printf(" Version : %02d.%02d\n", 1, __le32_to_cpu(sb->feature_map));
+ printf(" Version : %02d\n", 1);
+ printf(" Feature Map : 0x%x\n", __le32_to_cpu(sb->feature_map));
printf(" Array UUID : ");
for (i=0; i<16; i++) {
if ((i&3)==0 && i != 0) printf(":");
printf("%02x", sb->set_uuid[i]);
}
printf("\n");
- printf(" Name : %.32s\n", sb->set_name);
-
+ printf(" Name : %.32s", sb->set_name);
+ if (l > 0 && l < 32 &&
+ sb->set_name[l] == ':' &&
+ strncmp(sb->set_name, homehost, l) == 0)
+ printf(" (local to host %s)", homehost);
+ printf("\n");
atime = __le64_to_cpu(sb->ctime) & 0xFFFFFFFFFFULL;
printf(" Creation Time : %.24s\n", ctime(&atime));
c=map_num(pers, __le32_to_cpu(sb->level));
}
printf("\n");
printf("\n");
+ if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) {
+ printf("Internal Bitmap : %ld sectors from superblock\n",
+ (long)__le32_to_cpu(sb->bitmap_offset));
+ }
if (sb->feature_map & __le32_to_cpu(MD_FEATURE_RESHAPE_ACTIVE)) {
- printf(" Reshape pos'n : %llu%s\n", __le64_to_cpu(sb->reshape_position)/2,
+ printf(" Reshape pos'n : %llu%s\n", (unsigned long long)__le64_to_cpu(sb->reshape_position)/2,
human_size(__le64_to_cpu(sb->reshape_position)<<9));
if (__le32_to_cpu(sb->delta_disks)) {
printf(" Delta Devices : %d", __le32_to_cpu(sb->delta_disks));
printf(" New Layout : %s\n", c?c:"-unknown-");
}
if (__le32_to_cpu(sb->level) == 10) {
- printf(" New Layout : near=%d, far=%d\n",
+ printf(" New Layout : near=%d, %s=%d\n",
__le32_to_cpu(sb->new_layout)&255,
+ (__le32_to_cpu(sb->new_layout)&0x10000)?"offset":"far",
(__le32_to_cpu(sb->new_layout)>>8)&255);
}
}
}
if (__le32_to_cpu(sb->level) == 10) {
int lo = __le32_to_cpu(sb->layout);
- printf(" Layout : near=%d, far=%d\n",
- lo&255, (lo>>8)&255);
+ printf(" Layout : near=%d, %s=%d\n",
+ lo&255,
+ (lo&0x10000)?"offset":"far",
+ (lo>>8)&255);
}
switch(__le32_to_cpu(sb->level)) {
case 0:
{
struct mdp_superblock_1 *sb = sbv;
int i;
-
+ char *nm;
char *c=map_num(pers, __le32_to_cpu(sb->level));
- printf("ARRAY /dev/?? level=%s metadata=1 num-devices=%d UUID=",
+ 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 metadata=1 num-devices=%d UUID=",
+ nm,
c?c:"-unknown-", sb->raid_disks);
for (i=0; i<16; i++) {
printf("%02x", sb->set_uuid[i]);
printf("\n");
}
-static void detail_super1(void *sbv)
+static void detail_super1(void *sbv, char *homehost)
{
struct mdp_superblock_1 *sb = sbv;
int i;
-
- printf(" Name : %.32s\n", sb->set_name);
- printf(" UUID : ");
+ int l = homehost ? strlen(homehost) : 0;
+
+ printf(" Name : %.32s", sb->set_name);
+ if (l > 0 && l < 32 &&
+ sb->set_name[l] == ':' &&
+ strncmp(sb->set_name, homehost, l) == 0)
+ printf(" (local to host %s)", homehost);
+ printf("\n UUID : ");
for (i=0; i<16; i++) {
if ((i&3)==0 && i != 0) printf(":");
printf("%02x", sb->set_uuid[i]);
#endif
+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;
cuuid[i] = super->set_uuid[i];
}
-static void getinfo_super1(struct mdinfo *info, mddev_ident_t ident, void *sbv)
+static void getinfo_super1(struct mdinfo *info, void *sbv)
{
struct mdp_superblock_1 *sb = sbv;
int working = 0;
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->data_offset = __le64_to_cpu(sb->data_offset);
+ info->component_size = __le64_to_cpu(sb->size);
info->disk.major = 0;
info->disk.minor = 0;
memcpy(info->uuid, sb->set_uuid, 16);
- strncpy(ident->name, sb->set_name, 32);
- ident->name[32] = 0;
+ 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]);
info->array.working_disks = working;
}
-static int update_super1(struct mdinfo *info, void *sbv, char *update, char *devname, int verbose)
+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")==0) {
+ if (sb->events != __cpu_to_le64(info->events))
+ rv = 1;
sb->events = __cpu_to_le64(info->events);
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;
}
}
/* make sure resync happens */
sb->resync_offset = ~0ULL;
}
- if (strcmp(update, "uuid") == 0)
+ if (strcmp(update, "uuid") == 0) {
memcpy(sb->set_uuid, info->uuid, 16);
+ 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, info->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[33] = 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, "_reshape_progress")==0)
+ sb->reshape_position = __cpu_to_le64(info->reshape_progress);
sb->sb_csum = calc_sb_1_csum(sb);
return rv;
return __le64_to_cpu(sb->events);
}
-static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info, unsigned long long size, char *name)
+static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info,
+ unsigned long long size, char *name, char *homehost)
{
struct mdp_superblock_1 *sb = malloc(1024 + sizeof(bitmap_super_t));
int spares;
int rfd;
+ char defname[10];
memset(sb, 0, 1024);
- if (info->major_version == -1)
+ if (info->major_version == -1) {
/* zeroing superblock */
+ *sbp = sb;
return 0;
+ }
spares = info->working_disks - info->active_disks;
if (info->raid_disks + spares > 384) {
return 0;
}
-
sb->magic = __cpu_to_le32(MD_SB_MAGIC);
sb->major_version = __cpu_to_le32(1);
sb->feature_map = 0;
}
if (rfd >= 0) close(rfd);
+ if (name == NULL || *name == 0) {
+ sprintf(defname, "%d", info->md_minor);
+ name = defname;
+ }
memset(sb->set_name, 0, 32);
- strcpy(sb->set_name, name);
+ if (homehost &&
+ strchr(name, ':')== NULL &&
+ strlen(homehost)+1+strlen(name) < 32) {
+ strcpy(sb->set_name, homehost);
+ strcat(sb->set_name, ":");
+ strcat(sb->set_name, name);
+ } else
+ strcpy(sb->set_name, name);
sb->ctime = __cpu_to_le64((unsigned long long)time(0));
sb->level = __cpu_to_le32(info->level);
*rp = 0xfffe;
}
+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;
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;
}
int rfd;
int rv;
- unsigned long size;
- unsigned long long dsize;
+ unsigned long size, space;
+ unsigned long long dsize, array_size;
long long sb_offset;
* Depending on the array size, we might leave extra space
* for a bitmap.
*/
+ array_size = __le64_to_cpu(sb->size);
switch(st->minor_version) {
case 0:
sb_offset = dsize;
sb_offset &= ~(4*2-1);
sb->super_offset = __cpu_to_le64(sb_offset);
sb->data_offset = __cpu_to_le64(0);
- if (sb_offset-64*2 >= array_size)
+ if (sb_offset-64*2 >= array_size && array_size > 8*1024*1024*2)
sb->data_size = __cpu_to_le64(sb_offset-64*2);
else
sb->data_size = __cpu_to_le64(sb_offset);
break;
case 1:
sb->super_offset = __cpu_to_le64(0);
- if (dsize - 64*2 >= array_size)
+ if (dsize - 64*2 >= array_size && array_size > 8*1024*1024*2)
space = 64*2;
else
space = 4*2;
break;
case 2:
sb_offset = 4*2;
- if (dsize - 4*2 - 64*2 >= array_size)
+ if (dsize - 4*2 - 64*2 >= array_size && array_size > 8*1024*1024*2)
space = 64*2;
else
space = 4*2;
return 1;
if (!first) {
- first = malloc(1024);
- memcpy(first, second, 1024);
+ first = malloc(1024+sizeof(bitmap_super_t));
+ memcpy(first, second, 1024+sizeof(bitmap_super_t));
*firstp = first;
return 0;
}
unsigned long long dsize;
unsigned long long sb_offset;
struct mdp_superblock_1 *super;
-
+ int uuid[4];
+ struct bitmap_super_s *bsb;
if (st->ss == NULL) {
/*
* Calculate the position of the superblock.
* It is always aligned to a 4K boundary and
- * depeding on minor_version, it can be:
+ * 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.
return 2;
}
*sbp = super;
+
+ /* 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);
+ bsb = (struct bitmap_super_s *)(((char*)super)+1024);
+ 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;
}
st->ss = &super1;
st->max_devs = 384;
if (strcmp(arg, "1") == 0 ||
- strcmp(arg, "1.0") == 0) {
+ strcmp(arg, "1.0") == 0 ||
+ strcmp(arg, "default/large") == 0) {
st->minor_version = 0;
return st;
}
}
-void locate_bitmap1(struct supertype *st, int fd, void *sbv)
+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))
+ 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 += (long) __le32_to_cpu(sb->bitmap_offset);
- if (!sbv)
+ if (mustfree)
free(sb);
lseek64(fd, offset<<9, 0);
}
-int write_bitmap1(struct supertype *st, int fd, void *sbv)
+static int write_bitmap1(struct supertype *st, int fd, void *sbv)
{
struct mdp_superblock_1 *sb = sbv;
bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+1024);
locate_bitmap1(st, fd, sbv);
- write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t));
+ if (write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t)) !=
+ sizeof(bitmap_super_t))
+ return -2;
towrite = __le64_to_cpu(bms->sync_size) / (__le32_to_cpu(bms->chunksize)>>9);
towrite = (towrite+7) >> 3; /* bits to bytes */
memset(buf, 0xff, sizeof(buf));
.detail_super = detail_super1,
.brief_detail_super = brief_detail_super1,
#endif
+ .match_home = match_home1,
.uuid_from_super = uuid_from_super1,
.getinfo_super = getinfo_super1,
.update_super = update_super1,