/*
* 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 "asm/byteorder.h"
/*
* The version-1 superblock :
* All numeric fields are little-endian.
__u32 chunksize; /* in 512byte sectors */
__u32 raid_disks;
- __u8 pad1[128-96]; /* set to 0 when written */
+ __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 */
__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 pad2[64-56]; /* set to 0 when writing */
+ __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 */
__u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
};
+/* 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) ((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);
csum = (newcsum & 0xffffffff) + (newcsum >> 32);
sb->sb_csum = disk_csum;
- return csum;
+ return __cpu_to_le32(csum);
}
-
-static void examine_super1(void *sbv)
+#ifndef MDASSEMBLE
+static void examine_super1(void *sbv, char *homehost)
{
struct mdp_superblock_1 *sb = sbv;
time_t atime;
int d;
- int spares, faulty;
+ int faulty;
int i;
char *c;
+ int l = homehost ? strlen(homehost) : 0;
+ int layout;
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++) {
- printf("%02x", sb->set_uuid[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(" Raid Devices : %d\n", __le32_to_cpu(sb->raid_disks));
printf("\n");
printf(" Device Size : %llu%s\n", (unsigned long long)sb->data_size, human_size(sb->data_size<<9));
+ if (__le32_to_cpu(sb->level) >= 0) {
+ int ddsks=0;
+ switch(__le32_to_cpu(sb->level)) {
+ case 1: ddsks=1;break;
+ case 4:
+ case 5: ddsks = __le32_to_cpu(sb->raid_disks)-1; break;
+ case 6: ddsks = __le32_to_cpu(sb->raid_disks)-2; break;
+ case 10:
+ layout = __le32_to_cpu(sb->layout);
+ ddsks = __le32_to_cpu(sb->raid_disks)
+ / (layout&255) / ((layout>>8)&255);
+ }
+ if (ddsks)
+ printf(" Array Size : %llu%s\n",
+ ddsks*(unsigned long long)__le64_to_cpu(sb->size),
+ human_size(ddsks*__le64_to_cpu(sb->size)<<9));
+ if (sb->size != sb->data_size)
+ printf(" Used Size : %llu%s\n",
+ (unsigned long long)__le64_to_cpu(sb->size),
+ human_size(__le64_to_cpu(sb->size)<<9));
+ }
if (sb->data_offset)
- printf(" Data Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->data_offset));
- if (sb->super_offset)
- printf(" Super Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->super_offset));
+ printf(" Data Offset : %llu sectors\n",
+ (unsigned long long)__le64_to_cpu(sb->data_offset));
+ printf(" Super Offset : %llu sectors\n",
+ (unsigned long long)__le64_to_cpu(sb->super_offset));
+ if (__le32_to_cpu(sb->feature_map) & MD_FEATURE_RECOVERY_OFFSET)
+ printf("Recovery Offset : %llu sectors\n", (unsigned long long)__le64_to_cpu(sb->recovery_offset));
printf(" State : %s\n", (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean");
printf(" Device UUID : ");
for (i=0; i<16; i++) {
- printf("%02x", sb->set_uuid[i]);
if ((i&3)==0 && i != 0) printf(":");
+ printf("%02x", sb->device_uuid[i]);
}
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", (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));
+ if (__le32_to_cpu(sb->delta_disks))
+ printf(" (%d->%d)\n",
+ __le32_to_cpu(sb->raid_disks)-__le32_to_cpu(sb->delta_disks),
+ __le32_to_cpu(sb->raid_disks));
+ else
+ printf(" (%d->%d)\n", __le32_to_cpu(sb->raid_disks),
+ __le32_to_cpu(sb->raid_disks)+__le32_to_cpu(sb->delta_disks));
+ }
+ if (__le32_to_cpu(sb->new_level) != __le32_to_cpu(sb->level)) {
+ c = map_num(pers, __le32_to_cpu(sb->new_level));
+ printf(" New Level : %s\n", c?c:"-unknown-");
+ }
+ if (__le32_to_cpu(sb->new_layout) != __le32_to_cpu(sb->layout)) {
+ if (__le32_to_cpu(sb->level) == 5) {
+ c = map_num(r5layout, __le32_to_cpu(sb->new_layout));
+ printf(" New Layout : %s\n", c?c:"-unknown-");
+ }
+ if (__le32_to_cpu(sb->level) == 10) {
+ 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->new_chunk) != __le32_to_cpu(sb->chunksize))
+ printf(" New Chunksize : %dK\n", __le32_to_cpu(sb->new_chunk)/2);
+ printf("\n");
+ }
+ if (sb->devflags) {
+ printf(" Flags :");
+ if (sb->devflags & WriteMostly1)
+ printf(" write-mostly");
+ printf("\n");
+ }
atime = __le64_to_cpu(sb->utime) & 0xFFFFFFFFFFULL;
printf(" Update Time : %.24s\n", ctime(&atime));
c = map_num(r5layout, __le32_to_cpu(sb->layout));
printf(" Layout : %s\n", c?c:"-unknown-");
}
+ if (__le32_to_cpu(sb->level) == 10) {
+ int lo = __le32_to_cpu(sb->layout);
+ printf(" Layout : near=%d, %s=%d\n",
+ lo&255,
+ (lo&0x10000)?"offset":"far",
+ (lo>>8)&255);
+ }
switch(__le32_to_cpu(sb->level)) {
case 0:
case 4:
case 5:
- printf(" Chunk Size : %dK\n", __le32_to_cpu(sb->chunksize/2));
+ case 6:
+ case 10:
+ printf(" Chunk Size : %dK\n", __le32_to_cpu(sb->chunksize)/2);
break;
case -1:
- printf(" Rounding : %dK\n", __le32_to_cpu(sb->chunksize/2));
+ printf(" Rounding : %dK\n", __le32_to_cpu(sb->chunksize)/2);
break;
default: break;
}
printf("\n");
+ printf(" Array Slot : %d (", __le32_to_cpu(sb->dev_number));
+ for (i= __le32_to_cpu(sb->max_dev); i> 0 ; i--)
+ if (__le16_to_cpu(sb->dev_roles[i-1]) != 0xffff)
+ break;
+ for (d=0; d < i; d++) {
+ int role = __le16_to_cpu(sb->dev_roles[d]);
+ if (d) printf(", ");
+ if (role == 0xffff) printf("empty");
+ else if(role == 0xfffe) printf("failed");
+ else printf("%d", role);
+ }
+ printf(")\n");
printf(" Array State : ");
for (d=0; d<__le32_to_cpu(sb->raid_disks); d++) {
int cnt = 0;
else if (cnt == 1) printf("u");
else printf ("_");
}
- spares = faulty = 0;
+ faulty = 0;
for (i=0; i< __le32_to_cpu(sb->max_dev); i++) {
int role = __le16_to_cpu(sb->dev_roles[i]);
- switch (role) {
- case 0xFFFF: spares++; break;
- case 0xFFFE: faulty++;
- }
+ if (role == 0xFFFE)
+ faulty++;
}
- if (spares) printf(" %d spares", spares);
if (faulty) printf(" %d failed", faulty);
printf("\n");
}
{
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=",
- c?c:"-unknown-", sb->raid_disks);
+ 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-", __le32_to_cpu(sb->raid_disks));
for (i=0; i<16; i++) {
- printf("%02x", sb->set_uuid[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 void detail_super1(void *sbv)
+static void detail_super1(void *sbv, char *homehost)
{
struct mdp_superblock_1 *sb = sbv;
int i;
-
- 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++) {
- printf("%02x", sb->set_uuid[i]);
if ((i&3)==0 && i != 0) printf(":");
+ printf("%02x", sb->set_uuid[i]);
}
printf("\n Events : %llu\n\n", (unsigned long long)__le64_to_cpu(sb->events));
}
struct mdp_superblock_1 *sb = sbv;
int i;
+ if (sb->set_name[0])
+ printf(" name=%.32s", sb->set_name);
printf(" UUID=");
for (i=0; i<16; i++) {
- printf("%02x", sb->set_uuid[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;
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->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;
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)
+ 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)
+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) {
- sb->events = __cpu_to_le32(info->events);
+ 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;
}
}
rv = 1;
}
}
-#if 0
- if (strcmp(update, "newdev") == 0) {
- int d = info->disk.number;
- memset(&sb->disks[d], 0, sizeof(sb->disks[d]));
- sb->disks[d].number = d;
- sb->disks[d].major = info->disk.major;
- sb->disks[d].minor = info->disk.minor;
- sb->disks[d].raid_disk = info->disk.raid_disk;
- sb->disks[d].state = info->disk.state;
- sb->this_disk = sb->disks[d];
- }
-#endif
if (strcmp(update, "grow") == 0) {
sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
/* FIXME */
}
if (strcmp(update, "resync") == 0) {
/* make sure resync happens */
- sb->resync_offset = ~0ULL;
+ sb->resync_offset = 0ULL;
}
+ 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[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, "_reshape_progress")==0)
+ sb->reshape_position = __cpu_to_le64(info->reshape_progress);
sb->sb_csum = calc_sb_1_csum(sb);
return rv;
}
-
-static __u64 event_super1(void *sbv)
-{
- struct mdp_superblock_1 *sb = sbv;
- return __le64_to_cpu(sb->events);
-}
-
-static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info)
+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);
+ 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;
sb->pad0 = 0;
- *(__u32*)(sb->set_uuid) = random();
- *(__u32*)(sb->set_uuid+4) = random();
- *(__u32*)(sb->set_uuid+8) = random();
- *(__u32*)(sb->set_uuid+12) = random();
- /* FIXME name */
+ if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 ||
+ read(rfd, sb->set_uuid, 16) != 16) {
+ *(__u32*)(sb->set_uuid) = random();
+ *(__u32*)(sb->set_uuid+4) = random();
+ *(__u32*)(sb->set_uuid+8) = random();
+ *(__u32*)(sb->set_uuid+12) = random();
+ }
+ if (rfd >= 0) close(rfd);
+
+ if (name == NULL || *name == 0) {
+ sprintf(defname, "%d", info->md_minor);
+ name = defname;
+ }
+ memset(sb->set_name, 0, 32);
+ 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);
sb->layout = __cpu_to_le32(info->layout);
- sb->size = __cpu_to_le64(info->size*2ULL);
+ sb->size = __cpu_to_le64(size*2ULL);
sb->chunksize = __cpu_to_le32(info->chunk_size>>9);
sb->raid_disks = __cpu_to_le32(info->raid_disks);
sb->resync_offset = ~0ULL;
else
sb->resync_offset = 0;
- sb->max_dev = __cpu_to_le32((1024- sizeof(struct mdp_superblock_1))/
+ sb->max_dev = __cpu_to_le32((1024- sizeof(struct mdp_superblock_1))/
sizeof(sb->dev_roles[0]));
memset(sb->pad3, 0, sizeof(sb->pad3));
{
struct mdp_superblock_1 *sb = sbv;
__u16 *rp = sb->dev_roles + dk->number;
- if (dk->state == 6) /* active, sync */
+ if ((dk->state & 6) == 6) /* active, sync */
*rp = __cpu_to_le16(dk->raid_disk);
- else if (dk->state == 2) /* active -> spare */
+ else if ((dk->state & ~2) == 0) /* active or idle -> spare */
*rp = 0xffff;
- else
+ else
*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;
- long long sb_offset;
+ unsigned long long sb_offset;
int sbsize;
- long size;
-
- if (ioctl(fd, BLKGETSIZE, &size))
- return 1;
+ unsigned long size;
+ unsigned long long dsize;
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
+#endif
+ {
+ if (ioctl(fd, BLKGETSIZE, &size))
+ return 1;
+ else
+ dsize = (unsigned long long)size;
+ } else
+ dsize >>= 9;
- if (size < 24)
+ if (dsize < 24)
return 2;
/*
*/
switch(st->minor_version) {
case 0:
- sb_offset = size;
+ sb_offset = dsize;
sb_offset -= 8*2;
sb_offset &= ~(4*2-1);
break;
case 1:
- sb->super_offset = __cpu_to_le64(0);
+ sb_offset = 0;
break;
case 2:
sb_offset = 4*2;
}
-
- if (sb_offset != (__le64_to_cpu(sb->super_offset) << 9 ) &&
- 0 != (__le64_to_cpu(sb->super_offset) << 9 )
+
+ 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, 0)< 0LL)
+ 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 write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname)
+static int write_init_super1(struct supertype *st, void *sbv,
+ mdu_disk_info_t *dinfo, char *devname)
{
struct mdp_superblock_1 *sb = sbv;
- struct mdp_superblock_1 *refsb = NULL;
+ void *refsbv = NULL;
int fd = open(devname, O_RDWR | O_EXCL);
int rfd;
int rv;
+ int bm_space;
- long size;
+ unsigned long space;
+ unsigned long long dsize, array_size;
long long sb_offset;
}
sb->dev_number = __cpu_to_le32(dinfo->number);
+ if (dinfo->state & (1<<MD_DISK_WRITEMOSTLY))
+ sb->devflags |= __cpu_to_le32(WriteMostly1);
if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 ||
read(rfd, sb->device_uuid, 16) != 16) {
if (rfd >= 0) close(rfd);
sb->events = 0;
- if (load_super1(st, fd, (void**)&refsb, NULL)==0) {
+ if (load_super1(st, fd, &refsbv, NULL)==0) {
+ struct mdp_superblock_1 *refsb = refsbv;
+
memcpy(sb->device_uuid, refsb->device_uuid, 16);
if (memcmp(sb->set_uuid, refsb->set_uuid, 16)==0) {
/* same array, so preserve events and dev_number */
sb->events = refsb->events;
- sb->dev_number = refsb->dev_number;
+ /* bugs in 2.6.17 and earlier mean the dev_number
+ * chosen in Manage must be preserved
+ */
+ if (get_linux_version() >= 2006018)
+ sb->dev_number = refsb->dev_number;
}
free(refsb);
}
-
- if (ioctl(fd, BLKGETSIZE, &size)) {
- close(fd);
- return 1;
- }
- if (size < 24) {
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
+#endif
+ {
+ unsigned long size;
+ if (ioctl(fd, BLKGETSIZE, &size))
+ return 1;
+ else
+ dsize = size;
+ } else
+ dsize >>= 9;
+
+ if (dsize < 24) {
close(fd);
return 2;
}
* 0: At least 8K, but less than 12K, from end of device
* 1: At start of device
* 2: 4K from start of device.
+ * Depending on the array size, we might leave extra space
+ * for a bitmap.
*/
+ array_size = __le64_to_cpu(sb->size);
+ /* work out how much space we left of a bitmap */
+ if (array_size >= 200*1024*1024*2)
+ bm_space = 128*2;
+ else if (array_size > 8*1024*1024*2)
+ bm_space = 64*2;
+ else
+ bm_space = 0;
+
switch(st->minor_version) {
case 0:
- sb_offset = size;
+ sb_offset = dsize;
sb_offset -= 8*2;
sb_offset &= ~(4*2-1);
sb->super_offset = __cpu_to_le64(sb_offset);
sb->data_offset = __cpu_to_le64(0);
- sb->data_size = sb->super_offset;
+ sb->data_size = __cpu_to_le64(sb_offset - bm_space);
break;
case 1:
sb->super_offset = __cpu_to_le64(0);
- sb->data_offset = __cpu_to_le64(2);
- sb->data_size = __cpu_to_le64(size - 2);
+ sb->data_offset = __cpu_to_le64(bm_space + 4*2);
+ sb->data_size = __cpu_to_le64(dsize - bm_space - 4*2);
break;
case 2:
sb_offset = 4*2;
- sb->super_offset = __cpu_to_le64(sb_offset);
- sb->data_offset = __cpu_to_le64(sb_offset+2);
- sb->data_size = __cpu_to_le64(size - 4*2 - 2);
+ if (dsize - 4*2 - 64*2 >= array_size && array_size > 8*1024*1024*2)
+ space = 64*2;
+ else
+ space = 4*2;
+ sb->super_offset = __cpu_to_le64(4*2);
+ sb->data_offset = __cpu_to_le64(4*2 + 4*2 + bm_space);
+ sb->data_size = __cpu_to_le64(dsize - 4*2 - 4*2 - bm_space );
break;
default:
return -EINVAL;
rv = store_super1(st, fd, sb);
if (rv)
fprintf(stderr, Name ": failed to write superblock to %s\n", devname);
+
+ if (rv == 0 && (__le32_to_cpu(sb->feature_map) & 1))
+ rv = st->ss->write_bitmap(st, fd, sbv);
close(fd);
return rv;
}
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;
}
static int load_super1(struct supertype *st, int fd, void **sbp, char *devname)
{
unsigned long size;
+ 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) {
st->ss = NULL;
return 2;
}
- if (ioctl(fd, BLKGETSIZE, &size)) {
- if (devname)
- fprintf(stderr, Name ": cannot find device size for %s: %s\n",
- devname, strerror(errno));
- return 1;
- }
+#ifdef BLKGETSIZE64
+ if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
+#endif
+ {
+ if (ioctl(fd, BLKGETSIZE, &size)) {
+ if (devname)
+ fprintf(stderr, Name ": cannot find device size for %s: %s\n",
+ devname, strerror(errno));
+ return 1;
+ }
+ dsize = size;
+ } else
+ dsize >>= 9;
- if (size < 24) {
+ if (dsize < 24) {
if (devname)
- fprintf(stderr, Name ": %s is too small for md: size is %lu sectors.\n",
- devname, size);
+ 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
- * 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.
*/
switch(st->minor_version) {
case 0:
- sb_offset = size;
+ sb_offset = dsize;
sb_offset -= 8*2;
sb_offset &= ~(4*2-1);
break;
return 1;
}
- super = malloc(1024);
+ super = malloc(1024 + sizeof(bitmap_super_t));
if (read(fd, super, 1024) != 1024) {
if (devname)
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;
}
return NULL;
}
-static __u64 avail_size1(__u64 devsize)
+/* find available size on device with this devsize, using
+ * superblock type st, and reserving 'reserve' sectors for
+ * a possible bitmap
+ */
+static __u64 avail_size1(struct supertype *st, __u64 devsize)
{
if (devsize < 24)
return 0;
- return (devsize - 8*2 ) & ~(4*2-1);
+ /* if the device is bigger than 8Gig, save 64k for bitmap usage,
+ * if bigger than 200Gig, save 128k
+ */
+ if (devsize-64*2 >= 200*1024*1024*2)
+ devsize -= 128*2;
+ else if (devsize >= 8*1024*1024*2)
+ devsize -= 64*2;
+
+ switch(st->minor_version) {
+ case 0:
+ /* at end */
+ return ((devsize - 8*2 ) & ~(4*2-1));
+ case 1:
+ /* at start, 4K for superblock and possible bitmap */
+ return devsize - 4*2;
+ case 2:
+ /* 4k from start, 4K for superblock and possible bitmap */
+ return devsize - (4+4)*2;
+ }
+ return 0;
+}
+
+static int
+add_internal_bitmap1(struct supertype *st, void *sbv,
+ int *chunkp, int delay, int write_behind,
+ unsigned long long size,
+ int may_change, int major)
+{
+ /*
+ * If not may_change, then this is a 'Grow', and the bitmap
+ * must fit after the superblock.
+ * If may_change, then this is create, and we can put the bitmap
+ * before the superblock if we like, or may move the start.
+ * If !may_change, the bitmap MUST live at offset of 1K, until
+ * we get a sysfs interface.
+ *
+ * size is in sectors, chunk is in bytes !!!
+ */
+
+ unsigned long long bits;
+ unsigned long long max_bits;
+ unsigned long long min_chunk;
+ long offset;
+ int chunk = *chunkp;
+ int room;
+ struct mdp_superblock_1 *sb = sbv;
+ bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
+
+ switch(st->minor_version) {
+ case 0:
+ /* either 3K after the superblock, or some amount of space
+ * before.
+ */
+ if (may_change) {
+ /* We are creating array, so we *know* how much room has
+ * been left.
+ */
+ offset = 0;
+ if (__le64_to_cpu(sb->size) >= 200*1024*1024*2)
+ room = 128*2;
+ else if (__le64_to_cpu(sb->size) > 8*1024*1024*2)
+ room = 64*2;
+ else {
+ room = 3*2;
+ offset = 2;
+ }
+ } else {
+ room = __le64_to_cpu(sb->super_offset)
+ - __le64_to_cpu(sb->data_offset)
+ - __le64_to_cpu(sb->data_size);
+ /* remove '1 ||' when we can set offset via sysfs */
+ if (1 || (room < 3*2 &&
+ __le32_to_cpu(sb->max_dev) <= 384)) {
+ room = 3*2;
+ offset = 1*2;
+ } else {
+ offset = 0; /* means movable offset */
+ }
+ }
+ break;
+ case 1:
+ case 2: /* between superblock and data */
+ if (may_change) {
+ offset = 4*2;
+ if (__le64_to_cpu(sb->size) >= 200*1024*1024*2)
+ room = 128*2;
+ else if (__le64_to_cpu(sb->size) > 8*1024*1024*2)
+ room = 64*2;
+ else
+ room = 3*2;
+ } else {
+ room = __le64_to_cpu(sb->data_offset)
+ - __le64_to_cpu(sb->super_offset);
+ if (1 || __le32_to_cpu(sb->max_dev) <= 384) {
+ room -= 2;
+ offset = 2;
+ } else {
+ room -= 4*2;
+ offset = 4*2;
+ }
+ }
+ break;
+ }
+
+ if (chunk == UnSet && room > 128*2)
+ /* Limit to 128K of bitmap when chunk size not requested */
+ room = 128*2;
+
+ max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8;
+
+ min_chunk = 4096; /* sub-page chunks don't work yet.. */
+ bits = (size*512)/min_chunk +1;
+ while (bits > max_bits) {
+ min_chunk *= 2;
+ bits = (bits+1)/2;
+ }
+ if (chunk == UnSet)
+ chunk = min_chunk;
+ else if (chunk < min_chunk)
+ return 0; /* chunk size too small */
+ if (chunk == 0) /* rounding problem */
+ return 0;
+
+ if (offset == 0) {
+ bits = (size*512) / chunk + 1;
+ room = ((bits+7)/8 + sizeof(bitmap_super_t) +511)/512;
+ offset = -room;
+ }
+
+ sb->bitmap_offset = __cpu_to_le32(offset);
+
+ sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1);
+ memset(bms, 0, sizeof(*bms));
+ bms->magic = __cpu_to_le32(BITMAP_MAGIC);
+ bms->version = __cpu_to_le32(major);
+ uuid_from_super1((int*)bms->uuid, sb);
+ bms->chunksize = __cpu_to_le32(chunk);
+ bms->daemon_sleep = __cpu_to_le32(delay);
+ bms->sync_size = __cpu_to_le64(size);
+ bms->write_behind = __cpu_to_le32(write_behind);
+
+ *chunkp = chunk;
+ return 1;
+}
+
+
+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 += (long) __le32_to_cpu(sb->bitmap_offset);
+ if (mustfree)
+ free(sb);
+ lseek64(fd, offset<<9, 0);
+}
+
+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);
+ int rv = 0;
+
+ int towrite, n;
+ char buf[4096];
+
+ locate_bitmap1(st, fd, sbv);
+
+ 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));
+ while (towrite > 0) {
+ n = towrite;
+ if (n > sizeof(buf))
+ n = sizeof(buf);
+ n = write(fd, buf, n);
+ if (n > 0)
+ towrite -= n;
+ else
+ break;
+ }
+ fsync(fd);
+ if (towrite)
+ rv = -2;
+
+ return rv;
}
struct superswitch super1 = {
+#ifndef MDASSEMBLE
.examine_super = examine_super1,
.brief_examine_super = brief_examine_super1,
.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,
- .event_super = event_super1,
.init_super = init_super1,
.add_to_super = add_to_super1,
.store_super = store_super1,
.load_super = load_super1,
.match_metadata_desc = match_metadata_desc1,
.avail_size = avail_size1,
+ .add_internal_bitmap = add_internal_bitmap1,
+ .locate_bitmap = locate_bitmap1,
+ .write_bitmap = write_bitmap1,
.major = 1,
+#if __BYTE_ORDER == BIG_ENDIAN
+ .swapuuid = 0,
+#else
+ .swapuuid = 1,
+#endif
};