| 1 | /* MDRAID Superblock generator |
| 2 | This should create valid mdraid superblock for raid1 with 1 device. |
| 3 | It is still work in progress, but following seems to be recognized: |
| 4 | |
| 5 | make mdraid |
| 6 | ./mdraid > test.img |
| 7 | mdadm --examine test.img |
| 8 | |
| 9 | losetup /dev/loop1 test.img |
| 10 | mdadm --assemble md /dev/loop1 |
| 11 | |
| 12 | Some docs: |
| 13 | https://raid.wiki.kernel.org/index.php/RAID_superblock_formats#Sub-versions_of_the_version-1_superblock |
| 14 | https://docs.huihoo.com/doxygen/linux/kernel/3.7/md__p_8h_source.html |
| 15 | |
| 16 | */ |
| 17 | |
| 18 | //#include <cstddef> |
| 19 | #include <string.h> |
| 20 | #include <time.h> |
| 21 | #include <stdlib.h> |
| 22 | #include <stdio.h> |
| 23 | #include <linux/raid/md_p.h> |
| 24 | |
| 25 | void random_uuid(__u8 *buf) |
| 26 | { |
| 27 | __u32 r[4]; |
| 28 | for (int i = 0; i < 4; i++) |
| 29 | r[i] = random(); |
| 30 | memcpy(buf, r, 16); |
| 31 | } |
| 32 | |
| 33 | static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) |
| 34 | { |
| 35 | unsigned int disk_csum, csum; |
| 36 | unsigned long long newcsum; |
| 37 | int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2; |
| 38 | unsigned int *isuper = (unsigned int*)sb; |
| 39 | |
| 40 | /* make sure I can count... (needs include cstddef) */ |
| 41 | /* |
| 42 | if (offsetof(struct mdp_superblock_1,data_offset) != 128 || |
| 43 | offsetof(struct mdp_superblock_1, utime) != 192 || |
| 44 | sizeof(struct mdp_superblock_1) != 256) { |
| 45 | fprintf(stderr, "WARNING - superblock isn't sized correctly\n"); |
| 46 | } |
| 47 | */ |
| 48 | |
| 49 | disk_csum = sb->sb_csum; |
| 50 | sb->sb_csum = 0; |
| 51 | newcsum = 0; |
| 52 | for (; size>=4; size -= 4 ) { |
| 53 | newcsum += __le32_to_cpu(*isuper); |
| 54 | isuper++; |
| 55 | } |
| 56 | |
| 57 | if (size == 2) |
| 58 | newcsum += __le16_to_cpu(*(unsigned short*) isuper); |
| 59 | |
| 60 | csum = (newcsum & 0xffffffff) + (newcsum >> 32); |
| 61 | sb->sb_csum = disk_csum; |
| 62 | return __cpu_to_le32(csum); |
| 63 | } |
| 64 | |
| 65 | int main() { |
| 66 | //printf("Superblock\n"); |
| 67 | |
| 68 | size_t data_size = 8192; //512B sectors (should be divisible by 8 sectors to keep 4kB alignment) |
| 69 | |
| 70 | srand(time(NULL)); //FIXME: Seed UUID properly |
| 71 | |
| 72 | struct mdp_superblock_1 sb = {0}; |
| 73 | |
| 74 | /* constant array information - 128 bytes */ |
| 75 | sb.magic = 0xa92b4efc; /* MD_SB_MAGIC: 0xa92b4efc - little endian */ |
| 76 | sb.major_version = 1; /* 1 */ |
| 77 | sb.feature_map = 0; //MD_FEATURE_BITMAP_OFFSET; /* bit 0 set if 'bitmap_offset' is meaningful */ //FIXME: internal bitmap bit is not seen by mdadm???? |
| 78 | sb.pad0 = 0; /* always set to 0 when writing */ |
| 79 | |
| 80 | //TODO: set these |
| 81 | random_uuid(sb.set_uuid); /* user-space generated. U8[16]*/ |
| 82 | memcpy(sb.set_name, "localhost:7", 12); /* set and interpreted by user-space. CHAR[32] */ |
| 83 | sb.ctime=0; /* lo 40 bits are seconds, top 24 are microseconds or 0*/ |
| 84 | |
| 85 | sb.level=1; /* -4 (multipath), -1 (linear), 0,1,4,5 */ |
| 86 | //sb.layout=2; /* only for raid5 and raid10 currently */ |
| 87 | sb.size=data_size; /* used size of component devices, in 512byte sectors */ |
| 88 | |
| 89 | sb.chunksize=0; /* in 512byte sectors - not used in raid 1 */ |
| 90 | sb.raid_disks=1; |
| 91 | sb.bitmap_offset=8; /* sectors after start of superblock that bitmap starts |
| 92 | * NOTE: signed, so bitmap can be before superblock |
| 93 | * only meaningful of feature_map[0] is set. |
| 94 | */ |
| 95 | |
| 96 | /* constant this-device information - 64 bytes */ |
| 97 | sb.data_offset=2048; /* sector start of data, often 0 */ |
| 98 | sb.data_size=data_size; /* sectors in this device that can be used for data */ |
| 99 | sb.super_offset=8; /* sector start of this superblock */ |
| 100 | |
| 101 | sb.dev_number=0; /* permanent identifier of this device - not role in raid */ |
| 102 | sb.cnt_corrected_read=0; /* number of read errors that were corrected by re-writing */ |
| 103 | random_uuid(sb.device_uuid); /* user-space setable, ignored by kernel U8[16] */ |
| 104 | sb.devflags=0; /* per-device flags. Only two defined...*/ |
| 105 | //#define WriteMostly1 1 /* mask for writemostly flag in above */ |
| 106 | //#define FailFast1 2 /* Should avoid retries and fixups and just fail */ |
| 107 | |
| 108 | /* Bad block log. If there are any bad blocks the feature flag is set. |
| 109 | * If offset and size are non-zero, that space is reserved and available |
| 110 | */ |
| 111 | sb.bblog_shift=9; /* shift from sectors to block size */ //FIXME: not sure with this! |
| 112 | sb.bblog_size=8; /* number of sectors reserved for list */ |
| 113 | sb.bblog_offset=16; /* sector offset from superblock to bblog, |
| 114 | * signed - not unsigned */ |
| 115 | |
| 116 | /* array state information - 64 bytes */ |
| 117 | sb.utime=0; /* 40 bits second, 24 bits microseconds */ |
| 118 | sb.events=0; /* incremented when superblock updated */ |
| 119 | sb.resync_offset=0; /* data before this offset (from data_offset) known to be in sync */ |
| 120 | sb.max_dev=sb.raid_disks; /* size of devs[] array to consider */ |
| 121 | //__u8 pad3[64-32]; /* set to 0 when writing */ |
| 122 | |
| 123 | /* device state information. Indexed by dev_number. |
| 124 | * 2 bytes per device |
| 125 | * Note there are no per-device state flags. State information is rolled |
| 126 | * into the 'roles' value. If a device is spare or faulty, then it doesn't |
| 127 | * have a meaningful role. |
| 128 | */ |
| 129 | //__le16 dev_roles[]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */ |
| 130 | |
| 131 | |
| 132 | //Calculate checksum |
| 133 | sb.sb_csum=calc_sb_1_csum(&sb); |
| 134 | |
| 135 | //Empty space before metadata (sector 0 - 7) |
| 136 | for(int i=0;i<(sb.super_offset*512);i++) putc(0, stdout); |
| 137 | |
| 138 | //Superblock and padding (sector 8 - 2048) |
| 139 | fwrite(&sb, sizeof(sb), 1, stdout); |
| 140 | for(int i=0;i<(((sb.data_offset-sb.super_offset)*512)-sizeof(sb));i++) putc(0, stdout); |
| 141 | |
| 142 | //Data (N sectors) |
| 143 | for(int i=0;i<(data_size*512);i++) putc(0, stdout); |
| 144 | } |