Support internal bitmaps with format-1 superblocks.

Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
This commit is contained in:
Neil Brown 2005-08-25 04:31:44 +00:00
parent eb3b43aa2a
commit 34163fc7cf
9 changed files with 236 additions and 43 deletions

View File

@ -210,7 +210,7 @@ int Create(struct supertype *st, char *mddev, int mdfd,
ldsize = dsize;
ldsize <<= 9;
}
freesize = st->ss->avail_size(ldsize >> 9);
freesize = st->ss->avail_size(st, ldsize >> 9, 64*2);
if (freesize == 0) {
fprintf(stderr, Name ": %s is too small: %luK\n",
dname, (unsigned long)(ldsize>>10));
@ -355,7 +355,7 @@ int Create(struct supertype *st, char *mddev, int mdfd,
fprintf(stderr, Name ": internal bitmaps not supported by this kernel.\n");
return 1;
}
if (!st->ss->add_internal_bitmap(super, bitmap_chunk, delay, write_behind,
if (!st->ss->add_internal_bitmap(st, super, bitmap_chunk, delay, write_behind,
size ? size : maxsize)) {
fprintf(stderr, Name ": Given bitmap chunk size not supported.\n");
return 1;
@ -451,7 +451,7 @@ int Create(struct supertype *st, char *mddev, int mdfd,
break;
case 2:
if (disk.state == 1) break;
st->ss->write_init_super(st, super, &disk, dv->devname);
st->ss->write_init_super(st, super, &disk, dv->devname, 64*2);
if (ioctl(mdfd, ADD_NEW_DISK, &disk)) {
fprintf(stderr, Name ": ADD_NEW_DISK for %s failed: %s\n",

2
Grow.c
View File

@ -273,7 +273,7 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
if (fd2 < 0)
continue;
if (st->ss->load_super(st, fd2, &super, NULL)==0) {
st->ss->add_internal_bitmap(super,
st->ss->add_internal_bitmap(st, super,
chunk, delay, write_behind,
array.size);
st->ss->write_bitmap(st, fd2, super);

View File

@ -311,7 +311,7 @@ int Manage_subdevs(char *devname, int fd,
if (dv->writemostly)
disc.state |= 1 << MD_DISK_WRITEMOSTLY;
st->ss->add_to_super(dsuper, &disc);
if (st->ss->write_init_super(st, dsuper, &disc, dv->devname))
if (st->ss->write_init_super(st, dsuper, &disc, dv->devname, 0 /* FIXME */))
return 1;
} else if (dv->re_add) {
/* this had better be raid1.

View File

@ -177,11 +177,12 @@ out:
return info;
}
bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st)
bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype **stp)
{
int fd;
bitmap_info_t *info;
struct stat stb;
struct supertype *st = *stp;
fd = open(filename, O_RDONLY);
if (fd < 0) {
@ -199,6 +200,8 @@ bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st)
} else {
st->ss->locate_bitmap(st, fd);
}
ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */
*stp = st;
}
info = bitmap_fd_read(fd, brief);
@ -206,6 +209,18 @@ bitmap_info_t *bitmap_file_read(char *filename, int brief, struct supertype *st)
return info;
}
__u32 swapl(__u32 l)
{
char *c = (char*)&l;
char t= c[0];
c[0] = c[3];
c[3] = t;
t = c[1];
c[1] = c[2];
c[2] = t;
return l;
}
int ExamineBitmap(char *filename, int brief, struct supertype *st)
{
/*
@ -217,7 +232,7 @@ int ExamineBitmap(char *filename, int brief, struct supertype *st)
int rv = 1;
char buf[64];
info = bitmap_file_read(filename, brief, st);
info = bitmap_file_read(filename, brief, &st);
if (!info)
return rv;
@ -234,11 +249,19 @@ int ExamineBitmap(char *filename, int brief, struct supertype *st)
}
rv = 0;
if (st && st->ss->swapuuid) {
printf(" UUID : %08x.%08x.%08x.%08x\n",
swapl(*(__u32 *)(sb->uuid+0)),
swapl(*(__u32 *)(sb->uuid+4)),
swapl(*(__u32 *)(sb->uuid+8)),
swapl(*(__u32 *)(sb->uuid+12)));
} else {
printf(" UUID : %08x.%08x.%08x.%08x\n",
*(__u32 *)(sb->uuid+0),
*(__u32 *)(sb->uuid+4),
*(__u32 *)(sb->uuid+8),
*(__u32 *)(sb->uuid+12));
}
printf(" Events : %llu\n", sb->events);
printf(" Events Cleared : %llu\n", sb->events_cleared);
printf(" State : %s\n", bitmap_state(sb->state));

View File

@ -185,12 +185,12 @@ extern struct superswitch {
int (*init_super)(struct supertype *st, void **sbp, mdu_array_info_t *info, char *name);
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 (*write_init_super)(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname, int reserve);
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)(__u64 size);
int (*add_internal_bitmap)(void *sbv, int chunk, int delay, int write_behind, unsigned long long size);
__u64 (*avail_size)(struct supertype *st, __u64 size, int reserve);
int (*add_internal_bitmap)(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size);
void (*locate_bitmap)(struct supertype *st, int fd);
int (*write_bitmap)(struct supertype *st, int fd, void *sbv);
int major;

View File

@ -472,7 +472,7 @@ static int store_super0(struct supertype *st, int fd, void *sbv)
return 0;
}
static int write_init_super0(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname)
static int write_init_super0(struct supertype *st, void *sbv, mdu_disk_info_t *dinfo, char *devname, int reserve)
{
mdp_super_t *sb = sbv;
int fd = open(devname, O_RDWR|O_EXCL);
@ -664,14 +664,15 @@ static struct supertype *match_metadata_desc0(char *arg)
return NULL;
}
static __u64 avail_size0(__u64 devsize)
static __u64 avail_size0(struct supertype *st, __u64 devsize, int reserve)
{
if (devsize < MD_RESERVED_SECTORS*2)
return 0ULL;
if (reserve > 64*2) return 0ULL;
return MD_NEW_SIZE_SECTORS(devsize);
}
static int add_internal_bitmap0(void *sbv, int chunk, int delay, int write_behind, unsigned long long size)
static int add_internal_bitmap0(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size)
{
/*
* The bitmap comes immediately after the superblock and must be 60K in size

216
super1.c
View File

@ -54,7 +54,11 @@ struct mdp_superblock_1 {
__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.
*/
__u8 pad1[128-100]; /* set to 0 when written */
/* constant this-device information - 64 bytes */
__u64 data_offset; /* sector start of data, often 0 */
@ -131,8 +135,8 @@ static void examine_super1(void *sbv)
printf(" Version : %02d.%02d\n", 1, __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);
@ -151,13 +155,13 @@ static void examine_super1(void *sbv)
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");
if (sb->devflags) {
printf(" Flags :");
if (sb->devflags & WriteMostly1)
if (sb->devflags & WriteMostly1)
printf(" write-mostly");
printf("\n");
}
@ -243,8 +247,8 @@ static void detail_super1(void *sbv)
printf(" Name : %.32s\n", 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]);
}
printf("\n Events : %llu\n\n", (unsigned long long)__le64_to_cpu(sb->events));
}
@ -258,8 +262,8 @@ static void brief_detail_super1(void *sbv)
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]);
}
}
@ -385,8 +389,9 @@ static __u64 event_super1(void *sbv)
static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info, char *name)
{
struct mdp_superblock_1 *sb = malloc(1024);
struct mdp_superblock_1 *sb = malloc(1024 + sizeof(bitmap_super_t));
int spares;
int rfd;
memset(sb, 0, 1024);
if (info->major_version == -1)
@ -405,10 +410,15 @@ static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info,
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();
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);
memset(sb->set_name, 0, 32);
strcpy(sb->set_name, name);
@ -431,7 +441,7 @@ static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info,
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));
@ -450,7 +460,7 @@ static void add_to_super1(void *sbv, mdu_disk_info_t *dk)
*rp = __cpu_to_le16(dk->raid_disk);
else if ((dk->state & ~2) == 0) /* active or idle -> spare */
*rp = 0xffff;
else
else
*rp = 0xfffe;
}
@ -493,7 +503,7 @@ static int store_super1(struct supertype *st, int fd, void *sbv)
}
if (sb_offset != __le64_to_cpu(sb->super_offset) &&
0 != __le64_to_cpu(sb->super_offset)
) {
@ -515,7 +525,9 @@ static int store_super1(struct supertype *st, int fd, void *sbv)
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,
int reserve)
{
struct mdp_superblock_1 *sb = sbv;
struct mdp_superblock_1 *refsb = NULL;
@ -534,7 +546,7 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d
}
sb->dev_number = __cpu_to_le32(dinfo->number);
if (dinfo->state & (1<<MD_DISK_WRITEMOSTLY))
if (dinfo->state & (1<<MD_DISK_WRITEMOSTLY))
sb->devflags |= WriteMostly1;
if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 ||
@ -556,7 +568,7 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d
}
free(refsb);
}
if (ioctl(fd, BLKGETSIZE, &size)) {
close(fd);
return 1;
@ -583,18 +595,18 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d
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 - reserve);
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(2 + reserve);
sb->data_size = __cpu_to_le64(size - 2 - reserve);
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);
sb->data_offset = __cpu_to_le64(sb_offset+2 + reserve);
sb->data_size = __cpu_to_le64(size - 4*2 - 2 - reserve);
break;
default:
return -EINVAL;
@ -605,6 +617,30 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d
rv = store_super1(st, fd, sb);
if (rv)
fprintf(stderr, Name ": failed to write superblock to %s\n", devname);
if (__le32_to_cpu(sb->feature_map) & 1) {
/* write the bitmap */
int towrite, n;
char buf[4096];
st->ss->locate_bitmap(st, fd);
write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t));
towrite = 62*1024;
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;
}
if (towrite)
rv = -2;
}
fsync(fd);
close(fd);
return rv;
}
@ -686,7 +722,7 @@ static int load_super1(struct supertype *st, int fd, void **sbp, char *devname)
return 2;
}
if (ioctl(fd, BLKGETSIZE, &size)) {
if (devname)
if (devname)
fprintf(stderr, Name ": cannot find device size for %s: %s\n",
devname, strerror(errno));
return 1;
@ -733,7 +769,7 @@ static int load_super1(struct supertype *st, int fd, void **sbp, char *devname)
return 1;
}
super = malloc(1024);
super = malloc(1024 + sizeof(bitmap_super_t));
if (read(fd, super, 1024) != 1024) {
if (devname)
@ -795,12 +831,137 @@ static struct supertype *match_metadata_desc1(char *arg)
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, int reserve)
{
if (devsize < 24)
return 0;
return (devsize - 8*2 ) & ~(4*2-1);
switch(st->minor_version) {
case 0:
/* at end, with reserve before it */
return ((devsize - 8*2 ) & ~(4*2-1)) - reserve;
case 1:
/* at start, 1K for superblock */
return devsize - 2 - reserve;
case 2:
/* 4k from start, 1K for superblock */
return devsize - (4+1)*2 - reserve;
}
return 0;
}
static int add_internal_bitmap1(struct supertype *st, void *sbv, int chunk, int delay, int write_behind, unsigned long long size)
{
/*
* The bitmap comes immediately before of after the superblock and must be 62K in size
* at most. The default size is between 31K and 62K
*
* size is in K, chunk is in bytes !!!
*/
unsigned long long bits = size;
unsigned long long max_bits = 62*1024*8;
unsigned long long min_chunk;
struct mdp_superblock_1 *sb = sbv;
bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
min_chunk = 4096; /* sub-page chunks don't work yet.. */
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 (st->minor_version == 0)
sb->bitmap_offset = __cpu_to_le32(-64*2);
else
sb->bitmap_offset = __cpu_to_le32(2);
sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1);
memset(bms, sizeof(*bms), 0);
bms->magic = __cpu_to_le32(BITMAP_MAGIC);
bms->version = __cpu_to_le32(BITMAP_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);
return 1;
}
void locate_bitmap1(struct supertype *st, int fd)
{
unsigned long long dsize;
unsigned long size;
unsigned long long offset;
switch(st->minor_version){
case 0:
#ifdef BLKGETSIZE64
if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
#endif
{
if (ioctl(fd, BLKGETSIZE, &size))
return;
else
dsize = ((unsigned long long)size)<<9;
}
offset = (dsize - 8192) & ~4095ULL;
offset -= 65536;
break;
case 1:
offset = 1024;
break;
case 2:
offset = 4096+1024;
}
lseek64(fd, offset, 0);
}
int write_bitmap1(struct supertype *st, int fd, void *sbv)
{
struct mdp_superblock_1 *sb = sbv;
int rv = 0;
int towrite, n;
char buf[4096];
locate_bitmap1(st, fd);
write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t));
towrite = 62*1024 - sizeof(bitmap_super_t);
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 = {
@ -822,6 +983,9 @@ struct superswitch 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,

11
test
View File

@ -27,7 +27,9 @@ md0=/dev/md0 md1=/dev/md1 md2=/dev/md2
targetdir=/tmp
size=20000
mdsize0=19904
mdsize1=19992
mdsize1=19928
mdsize11=19935
mdsize12=19931
cleanup() {
$mdadm -Ss
@ -96,7 +98,7 @@ check() {
bitmap )
grep -s bitmap > /dev/null /proc/mdstat || {
echo >&2 ERROR no bitmap ; cat /proc/mdstat ; exist 1; }
echo >&2 ERROR no bitmap ; cat /proc/mdstat ; exit 1; }
;;
nobitmap )
if grep -s "bitmap" > /dev/null /proc/mdstat
@ -134,8 +136,10 @@ rotest() {
for script in tests/$prefix*[^~]
for script in tests/$prefix tests/$prefix*[^~]
do
if [ -f "$script" ]
then
# source script in a subshell, so it has access to our
# namespace, but cannot change it.
if ( set -ex ; . $script ) 2> $targetdir/log
@ -144,5 +148,6 @@ do
echo "$script failed"
exit 1
fi
fi
done
exit 0

View File

@ -84,7 +84,7 @@ mdadm -A $md2 -u $uuid $devlist
$tst
mdadm -S $md2
# version 1 has now super-minor
# version 1 has no super-minor
# mdadm --assemble $md2 --super-minor=2 $devlist #
# $tst
# mdadm -S $md2