BaffaloのTeraStation(テラステーション)のディスクにエラーがでた。4台でRAID5を組んでいた。
Disk1に赤ランプがついた。
なので、Disk1を交換してリビルドを開始したらDisk2に赤ランプがついた。
リビルド中の故障という最悪の事態。
テラステーションの電源を再投入すると、RAIDセットが見当たらない。
すべてのファイルを失うかと思ったが、以下の手法で幸いほとんどすべてのファイルを救うことが出来た。
ただし、手順を間違えるととどめを刺す可能性もあるので注意。
※ファイルを救える条件は、Diskがエラーカウントが増えてRAID的にはfailしただけで、物理的にはまだ完全には壊れていないこと。
※ここに書いてあることをやって、うまくいかなくても責任は取りません。
先人たちの努力に感謝したい。以下、参考にしたページたち。
1.Linux PCの準備
適当なLinux PCを用意する。今回の場合はCentosLive 6.8を使った。この場合、OSはDVDでブートするので、LinuxをHDDにインストー ルする必要が無い。
テラステーションのディスクを取り出し、今回は全部のディスク、Disk1, Disk2, Disk3, Disk4を繋げた。
2. RAID5の状態の確認
cat /etc/mdstat
でRAID状態の確認。md126が実際にデータが入っている領域。
RAIDを止める。
mdadm --stop /dev/md126
各Diskの状態の確認
mdadm --examine /dev/sda6
mdadm --examine /dev/sdb6
mdadm --examine /dev/sdc6
mdadm --examine /dev/sdd6
今回の場合、sdc6とsdd6は正しくRAID5の情報が見れた。
sda6の場合はsuper blockが無いと言われた。
sdbについてはパーティション情報も消えていた。
念のためsdbにpartedを使って他のsdc6と同じ容量でパーティションを切ってみたところ、まだディスクの中にはRAID5のデータは残され ているようであった。
ここではDisk1 (sda6), Disk3 (sdc6), Disk4 (sdd6)の3台を使ってデータの復旧を試みる。
※3台以上のディスクでsuper blockが確認できるのであれば、mdadm -A /dev/md126 -u UUID --run --force で強制的にRAID5を起動出来 ると思われる。super blockが消えているものがある場合、または--forceで強制起動できない場合は、Super blockの復旧を行う必要があ る。
以下に正しく取得できたsuper blockの情報を書いた。NameとArrayy UUIDとDevice UUIDは伏せてある。
Disk3とDisk4はActiveであるが、Disk1とDisk2がmissingになっている。
/dev/sdd6:
Magic : a92b4efc
Version : 1.2
Feature Map : 0x0
Array UUID : XXXXXXXX:XXXXXXXX:XXXXXXXX:XXXXXXXX
Name : HOGEHOGE
Creation Time : Wed Jul 27 02:04:37 2011
Raid Level : raid5
Raid Devices : 4
Avail Dev Size : 1923500032 (917.20 GiB 984.83 GB)
Array Size : 2885248512 (2751.59 GiB 2954.49 GB)
Used Dev Size : 1923499008 (917.20 GiB 984.83 GB)
Data Offset : 2048 sectors
Super Offset : 8 sectors
Unused Space : before=1968 sectors, after=1024 sectors
State : clean
Device UUID : YYYYYYYY:YYYYYYYY:YYYYYYYY:YYYYYYYY
Update Time : Wed Dec 28 01:14:21 2016
Checksum : df1f1fcf - correct
Events : 34982066
Layout : left-symmetric
Chunk Size : 512K
Device Role : Active device 2
Array State : ..AA ('A' == active, '.' == missing, 'R' == replacing)
3. 健全なSuper Blockの抽出
mdadm --examineでRAID情報を見るとバージョンは1.2であった。
これはSuper blockのversionが1であることを示していて、以下ではSuper block version 1の場合について書く。
他のWebサイトではversion 0のSuper blockであったとの報告もあるようなので、その場合は別サイトを参照願いたい。
まずは健全なSuper Blockを抽出する。
mdadm --examineの情報によると、Super Offset は8 sectorsなので、512 * 8 = 4096 BytesからSuper blockが書かれていることがわかる。
また、Super block version 1の場合は、一般に最大1KBytesの領域を使うので、ここをごっそりコピーしてくる。
bs1dump.cというプログラムを作成した。コンパイルして、 ./bs1dump /dev/sdd6 のようにして使う。
dump1.datというファイルにバイナリが出力される。 od -X dump1.dat でバイナリを確認できる。
bs1show.cを使うと、わかり易い内容で表示できる。./bs1show dump1.dat
※今回作ったプログラムはこのページの最後にまとめて載せておきます。
4. Super Blockの改変
RAID5の4台のディスク中3台は生きていますよ、という情報を作ってあげないとならない。
Disk3とDisk4の場合は、Super blockが生きているので、Disk1も元気ですよという情報に改変する。
Disk1も同様なのだが、Super blockが消えているので、dev_numberとdevice_UUIDを適当に決めてあげる必要がある。今回は dev_numberは0にして、device_UUIDはuuidegenというコマンドから適当に作ったUUIDを使った。
Disk3とDisk4用のプログラムは bs1renew.c で、./bs1renew sdd6org.dat sdd6new.dat
のようにする。sdd6org.datは先ほどbs1dump.cで抽出したdump1.datをコピーしたもの。
Disk1用のプログラムはbs1recre.cで./bs1recre sdd6org.dat sda6new.dat とやる。
ベースとなるSuper blockのdev_numberとdevice_UUIDを改変して新しいSuper blockを作る。
変えるべきdev_numberとdevice_UUIDの値はプログラムの上部で直接書くようにしているので、そこを編集すべし。
5. Super Blockの上書きとRAIDの起動
bs1update.cを使って、改変したSuper blockを書き込んでいく。
./bs1update /dev/sda6 sda6new.dat
./bs1update /dev/sdc6 sdc6new.dat
./bs1update /dev/sdd6 sdd6new.dat
これでmdadm --examine /dev/sdda6 等やって、
Device Role : Active device 0
Array State : A.AA ('A' == active, '.' == missing, 'R' == replacing)
となれば良い。その他Check SumやUUID等に間違えが無いかも確認。
ここまで来たら、mdadm -A /dev/md126 -u Array_UUID
とやって、RAIDを起動させる。
場合によってはxfsファイルシステムがおかしい場合もあるので、
/sbin/xfs_repair /dev/md126
をやる。ただし、repairしてとどめを刺す可能性もあるので、やらない方が良いかもしれない。運まかせ。
※centosliveにはxfs_repairが見当たらなかったので、別のLinuxからバイナリをコピーして使いました。
※xfs_repair -nをやると診断だけ行う。今回の場合は、xfsには問題はなかった。
で、最後にマウント。
mount /dev/md126 /raid 等。
これで、/raid以下のファイルが見えたら成功。
rsync 等でごっそり別コンピュータや別ディスクにコピーするのも良いが、ファイルによってはディスクのダメなブロックに当たる可能性 もあるので、特に重要なファイルからコピーして、その後rsyncをかけると良いと思われる。
今回の場合は、上記の方法ですべてのファイルを救い出すことが出来た。ディスクが完全には壊れていなかったのがラッキーであった。
ちなみにパーティション情報が消えていたDisk2のSMART情報を見てみるとPre-failが出ていた。それでもまだ完全には壊れていない。 Disk1は特に何も出ていなかった。
6. プログラムたち
bs1dump.c
/*
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, see <http://www.gnu.org/licenses/>.
*/
#define
_LARGEFILE64_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/types.h>
#include <string.h>
static
void dump1(char *dev){
int
ifd, ofd;
char
buff[1024], name[256]={0};
sprintf(name, "dump1.dat");
if((ifd = open(dev,O_RDONLY) ) > 0 ) {
lseek64(ifd,4096,SEEK_SET);
read(ifd, buff, 1024);
close(ifd);
}else{
printf("faild to open %s\n", dev);
return;
}
if((ofd = open(name,O_WRONLY|O_CREAT, 0644)) > 0 ){
write(ofd,buff,1024);
close(ofd);
}else{
printf("failed to write %s\n", name);
}
}
int main(int argc, char *argv[]){
if(argc < 2){
printf("bs1dump DEVICE\n");
return 0;
}
dump1(argv[1]);
return 0;
}
bs1show.c
/*
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, see <http://www.gnu.org/licenses/>.
*/
#define
_LARGEFILE64_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/types.h>
#include <libgen.h>
#include <string.h>
#include "super1.h"
static
void show1(char *file){
int
ifd, i;
char
buff[1024], name[256]={0};
struct mdp_superblock_1 super;
if((ifd = open(file,O_RDONLY) ) > 0 ) {
read(ifd, buff, 1024);
close(ifd);
}else{
printf("faild to open %s\n", file);
return;
}
memcpy((char *)&super, buff, sizeof(super));
printf("%-20s : %08x\n", "magic", super.magic);
printf("%-20s : %u\n", "major_version", super.major_version);
printf("%-20s : %u\n", "feature_map", super.feature_map);
printf("%-20s : %u\n", "pad0", super.pad0);
printf("%-20s : ", "set_uuid");
for(i=0;i<16;i++){
printf("%02x", super.set_uuid[i]);
if(i==3 || i==5 || i==7 || i==9){
printf("-");
}
}
printf("\n");
printf("%-20s : %s\n", "set_name", super.set_name);
printf("%-20s : %llu\n", "ctime", super.ctime);
printf("%-20s : %u\n", "level", super.level);
printf("%-20s : %u\n", "layout", super.layout);
printf("%-20s : %llu\n", "size", super.size);
printf("%-20s : %u\n", "chunksize", super.chunksize);
printf("%-20s : %u\n", "raid_disks", super.raid_disks);
printf("%-20s : %u\n", "bitmap_offset", super.bitmap_offset);
printf("%-20s : %u\n", "new_level", super.new_level);
printf("%-20s : %llu\n", "reshape_position", super.reshape_position);
printf("%-20s : %u\n", "delta_disks", super.delta_disks);
printf("%-20s : %u\n", "new_layout", super.new_layout);
printf("%-20s : %u\n", "new_chunk", super.new_chunk);
printf("%-20s : %u\n", "new_offset", super.new_offset);
printf("%-20s : %llu\n", "data_offset", super.data_offset);
printf("%-20s : %llu\n", "data_size", super.data_size);
printf("%-20s : %llu\n", "super_offset", super.super_offset);
printf("%-20s : %llu\n", "recovery_offset", super.recovery_offset);
printf("%-20s : %u\n", "dev_number", super.dev_number);
printf("%-20s : %u\n", "cnt_corrected_read", super.cnt_corrected_read);
printf("%-20s : ", "device_uuid");
for(i=0;i<16;i++){
printf("%02x", super.device_uuid[i]);
if(i==3 || i==5 || i==7 || i==9){
printf("-");
}
}
printf("\n");
printf("%-20s : %u\n", "devflags", super.devflags);
printf("%-20s : %u\n", "bblog_shift", super.bblog_shift);
printf("%-20s : %u\n", "bblog_size", super.bblog_size);
printf("%-20s : %u\n", "bblog_offset", super.bblog_offset);
printf("%-20s : %llu\n", "utime", super.utime);
printf("%-20s : %llu\n", "events", super.events);
printf("%-20s : %llu\n", "resync_offset", super.resync_offset);
printf("%-20s : %x\n", "sb_csum", super.sb_csum);
printf("%-20s : %u\n", "max_dev", super.max_dev);
printf("%-20s : ", "pad3");
for(i=0;i<32;i++){
printf("%u", super.pad3[i]);
}
printf("\n");
printf("%-20s : %x\n", "dev_roles", super.dev_roles[0]);
}
int main(int argc, char *argv[]){
if(argc < 2){
printf("bs1show FILE\n");
return 0;
}
show1(argv[1]);
return 0;
}
super1.h
/*
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, see <http://www.gnu.org/licenses/>.
*/
/* originaly from mdadm-3.3.4 super1.c */
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 (sectors) */
__u32 new_offset; /* signed number to add to data_offset in new
* layout. 0 == no-change. This can be
* different on each device in the array.
*/
/* 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 */
/* bad block log. If there are any bad blocks the feature flag is set.
* if offset and size are non-zero, that space is reserved and available.
*/
__u8 bblog_shift; /* shift from sectors to block size for badblocklist */
__u16 bblog_size; /* number of sectors reserved for badblocklist */
__u32 bblog_offset; /* sector offset from superblock to bblog, signed */
/* 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 dev_roles[max_dev] */
__u32 max_dev; /* size of dev_roles[] 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 */
};
bs1renew.c
/*
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, see <http://www.gnu.org/licenses/>.
*/
#define
_LARGEFILE64_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <linux/types.h>
#include <libgen.h>
#include <string.h>
#include "super1.h"
#define __cpu_to_le16(_x) (unsigned int)(_x)
#define __cpu_to_le32(_x) (unsigned int)(_x)
#define __cpu_to_le64(_x) (unsigned long long)(_x)
#define __le16_to_cpu(_x) (unsigned int)(_x)
#define __le32_to_cpu(_x) (unsigned int)(_x)
#define __le64_to_cpu(_x) (unsigned long long)(_x)
// specify your disks and device state
// 0xfffe = fail, numerical numbers = active
#define NOFDISK 4
const __u16 devstate[NOFDISK] = {0, 0xfffe, 2, 3};
/* originaly from mdadm-3.3.4 super1.c */
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;
/* 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 (; 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 renew1(char *file, char *out){
int
ifd, ofd, i;
char
buff[1024], name[256]={0};
struct mdp_superblock_1 super;
__u32 revcsum;
if((ifd = open(file,O_RDONLY) ) > 0 ) {
read(ifd, buff, 1024);
close(ifd);
}else{
printf("faild to open %s\n", file);
return;
}
memcpy((char *)&super, buff, sizeof(super));
printf("%-20s : %08x\n", "magic", super.magic);
printf("%-20s : %u\n", "major_version", super.major_version);
printf("%-20s : %u\n", "feature_map", super.feature_map);
printf("%-20s : %u\n", "pad0", super.pad0);
printf("%-20s : ", "set_uuid");
for(i=0;i<16;i++){
printf("%02x", super.set_uuid[i]);
if(i==3 || i==5 || i==7 || i==9){
printf("-");
}
}
printf("\n");
printf("%-20s : %s\n", "set_name", super.set_name);
printf("%-20s : %llu\n", "ctime", super.ctime);
printf("%-20s : %u\n", "level", super.level);
printf("%-20s : %u\n", "layout", super.layout);
printf("%-20s : %llu\n", "size", super.size);
printf("%-20s : %u\n", "chunksize", super.chunksize);
printf("%-20s : %u\n", "raid_disks", super.raid_disks);
printf("%-20s : %u\n", "bitmap_offset", super.bitmap_offset);
printf("%-20s : %u\n", "new_level", super.new_level);
printf("%-20s : %llu\n", "reshape_position", super.reshape_position);
printf("%-20s : %u\n", "delta_disks", super.delta_disks);
printf("%-20s : %u\n", "new_layout", super.new_layout);
printf("%-20s : %u\n", "new_chunk", super.new_chunk);
printf("%-20s : %u\n", "new_offset", super.new_offset);
printf("%-20s : %llu\n", "data_offset", super.data_offset);
printf("%-20s : %llu\n", "data_size", super.data_size);
printf("%-20s : %llu\n", "super_offset", super.super_offset);
printf("%-20s : %llu\n", "recovery_offset", super.recovery_offset);
printf("%-20s : %u\n", "dev_number", super.dev_number);
printf("%-20s : %u\n", "cnt_corrected_read", super.cnt_corrected_read);
printf("%-20s : ", "device_uuid");
for(i=0;i<16;i++){
printf("%02x", super.device_uuid[i]);
if(i==3 || i==5 || i==7 || i==9){
printf("-");
}
}
printf("\n");
printf("%-20s : %u\n", "devflags", super.devflags);
printf("%-20s : %u\n", "bblog_shift", super.bblog_shift);
printf("%-20s : %u\n", "bblog_size", super.bblog_size);
printf("%-20s : %u\n", "bblog_offset", super.bblog_offset);
printf("%-20s : %llu\n", "utime", super.utime);
printf("%-20s : %llu\n", "events", super.events);
printf("%-20s : %llu\n", "resync_offset", super.resync_offset);
printf("%-20s : %08x\n", "sb_csum", super.sb_csum);
printf("%-20s : %u\n", "max_dev", super.max_dev);
printf("%-20s : ", "pad3");
for(i=0;i<32;i++){
printf("%u", super.pad3[i]);
}
printf("\n");
printf("%-20s : %x\n", "dev_roles", super.dev_roles[0]);
memset(buff, 0xff, sizeof(buff));
memcpy(buff, (char *)&super, sizeof(super));
for(i=0;i<super.raid_disks;i++){
memcpy(buff+sizeof(super)+i*2, (char *)&devstate[i], 2);
}
revcsum = calc_sb_1_csum((struct mdp_superblock_1 *)buff);
printf("%-20s : %08x\n", "sb_csum org ", super.sb_csum);
printf("%-20s : %08x\n", "sb_csum reviced", revcsum);
super.sb_csum = revcsum;
memcpy(buff, (char *)&super, sizeof(super));
if((ofd = open(out,O_WRONLY|O_CREAT, 0644) ) > 0 ) {
write(ofd, (char *)&buff, 1024);
close(ofd);
}else{
printf("faild to write %s\n", file);
return;
}
}
int main(int argc, char *argv[]){
if(argc < 2){
printf("bs1show IN-FILE OUT-FILE\n");
return 0;
}
renew1(argv[1], argv[2]);
return 0;
}
bs1recre.c
/*
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, see <http://www.gnu.org/licenses/>.
*/
#define
_LARGEFILE64_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <linux/types.h>
#include <libgen.h>
#include <string.h>
#include "super1.h"
#define __cpu_to_le16(_x) (unsigned int)(_x)
#define __cpu_to_le32(_x) (unsigned int)(_x)
#define __cpu_to_le64(_x) (unsigned long long)(_x)
#define __le16_to_cpu(_x) (unsigned int)(_x)
#define __le32_to_cpu(_x) (unsigned int)(_x)
#define __le64_to_cpu(_x) (unsigned long long)(_x)
// specify your disks and device state
// 0xfffe = fail, numerical numbers = active
#define NOFDISK 4
const __u16 devstate[NOFDISK] = {0, 0xfffe, 2, 3};
// specify your number and device uuid
const __u32 new_dev_number = 0;
const __u8 new_device_uuid[16] =
{0xc9, 0x7b, 0x4b, 0x36, 0xc4, 0x5a, 0x41, 0x51,
0x95, 0x74, 0xb7, 0x18, 0xa6, 0x31, 0x3f, 0x89};
/* originaly from mdadm-3.3.4 super1.c */
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;
/* 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 (; 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 recre1(char *file, char *out){
int
ifd, ofd, i;
char
buff[1024], name[256]={0};
struct mdp_superblock_1 super;
__u32 revcsum;
if((ifd = open(file,O_RDONLY) ) > 0 ) {
read(ifd, buff, 1024);
close(ifd);
}else{
printf("faild to open %s\n", file);
return;
}
memcpy((char *)&super, buff, sizeof(super));
printf("%-20s : %08x\n", "magic", super.magic);
printf("%-20s : %u\n", "major_version", super.major_version);
printf("%-20s : %u\n", "feature_map", super.feature_map);
printf("%-20s : %u\n", "pad0", super.pad0);
printf("%-20s : ", "set_uuid");
for(i=0;i<16;i++){
printf("%02x", super.set_uuid[i]);
if(i==3 || i==5 || i==7 || i==9){
printf("-");
}
}
printf("\n");
printf("%-20s : %s\n", "set_name", super.set_name);
printf("%-20s : %llu\n", "ctime", super.ctime);
printf("%-20s : %u\n", "level", super.level);
printf("%-20s : %u\n", "layout", super.layout);
printf("%-20s : %llu\n", "size", super.size);
printf("%-20s : %u\n", "chunksize", super.chunksize);
printf("%-20s : %u\n", "raid_disks", super.raid_disks);
printf("%-20s : %u\n", "bitmap_offset", super.bitmap_offset);
printf("%-20s : %u\n", "new_level", super.new_level);
printf("%-20s : %llu\n", "reshape_position", super.reshape_position);
printf("%-20s : %u\n", "delta_disks", super.delta_disks);
printf("%-20s : %u\n", "new_layout", super.new_layout);
printf("%-20s : %u\n", "new_chunk", super.new_chunk);
printf("%-20s : %u\n", "new_offset", super.new_offset);
printf("%-20s : %llu\n", "data_offset", super.data_offset);
printf("%-20s : %llu\n", "data_size", super.data_size);
printf("%-20s : %llu\n", "super_offset", super.super_offset);
printf("%-20s : %llu\n", "recovery_offset", super.recovery_offset);
super.dev_number = new_dev_number;
printf("%-20s : %u\n", "dev_number", super.dev_number);
printf("%-20s : %u\n", "cnt_corrected_read", super.cnt_corrected_read);
for(i=0;i<16;i++){
super.device_uuid[i] = new_device_uuid[i];
}
printf("%-20s : ", "device_uuid");
for(i=0;i<16;i++){
printf("%02x", super.device_uuid[i]);
if(i==3 || i==5 || i==7 || i==9){
printf("-");
}
}
printf("\n");
printf("%-20s : %u\n", "devflags", super.devflags);
printf("%-20s : %u\n", "bblog_shift", super.bblog_shift);
printf("%-20s : %u\n", "bblog_size", super.bblog_size);
printf("%-20s : %u\n", "bblog_offset", super.bblog_offset);
printf("%-20s : %llu\n", "utime", super.utime);
printf("%-20s : %llu\n", "events", super.events);
printf("%-20s : %llu\n", "resync_offset", super.resync_offset);
printf("%-20s : %08x\n", "sb_csum", super.sb_csum);
printf("%-20s : %u\n", "max_dev", super.max_dev);
printf("%-20s : ", "pad3");
for(i=0;i<32;i++){
printf("%u", super.pad3[i]);
}
printf("\n");
printf("%-20s : %x\n", "dev_roles", super.dev_roles[0]);
memset(buff, 0xff, sizeof(buff));
memcpy(buff, (char *)&super, sizeof(super));
for(i=0;i<super.raid_disks;i++){
memcpy(buff+sizeof(super)+i*2, (char *)&devstate[i], 2);
}
revcsum = calc_sb_1_csum((struct mdp_superblock_1 *)buff);
printf("%-20s : %08x\n", "sb_csum org ", super.sb_csum);
printf("%-20s : %08x\n", "sb_csum reviced", revcsum);
super.sb_csum = revcsum;
memcpy(buff, (char *)&super, sizeof(super));
if((ofd = open(out,O_WRONLY|O_CREAT, 0644) ) > 0 ) {
write(ofd, (char *)&buff, 1024);
close(ofd);
}else{
printf("faild to write %s\n", file);
return;
}
}
int main(int argc, char *argv[]){
if(argc < 2){
printf("bs1show IN-FILE OUT-FILE\n");
return 0;
}
recre1(argv[1], argv[2]);
return 0;
}
bs1update.c
/*
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, see <http://www.gnu.org/licenses/>.
*/
#define
_LARGEFILE64_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/types.h>
#include <libgen.h>
#include <string.h>
static void update1(char *dev, char *file){
int
ifd, ofd;
char
buff[1024];
if((ifd = open(file,O_RDONLY) ) > 0 ) {
read(ifd, buff, 1024);
close(ifd);
}else{
printf("faild to open %s\n", file);
return;
}
if((ofd = open(dev,O_WRONLY) ) > 0 ) {
lseek64(ifd,4096,SEEK_SET);
write(ofd, buff, 1024);
close(ifd);
}else{
printf("faild to write %s\n", dev);
return;
}
}
int main(int argc, char *argv[]){
if(argc < 3){
printf("bs1update DEVICE FILE\n");
return 0;
}
update1(argv[1], argv[2]);
return 0;
}