/* Utility to re-connect two out of sync raid devices. This utility is used after drsync. */ #include #include #include #include #include #include "drraid.h" static u32 drraid_chksum (const SUPERBLOCK &sb) { //unsigned int disk_csum = sb.sb_csum; //sb.sb_csum = 0; unsigned size = ((char*)sb.devs-(char*)&sb) + sb.max_dev*2; unsigned size4 = size/4; u64 newcsum = 0; u32 *sb32 = (u32*)&sb; for (unsigned i = 0; i < size4 ; i++) newcsum += sb32[i]; //sb.sb_csum = disk_csum; newcsum -= sb.sb_csum; // printf ("COMP %u %u sizeof %lu\n",(unsigned)(newcsum & 0xffffffff),(unsigned)(newcsum>>32) // ,sizeof(u32)); u32 csum = (newcsum & 0xffffffff) + (newcsum>>32); return csum; } void drraid_dump ( const char *fname, const SUPERBLOCK &sb, const unsigned long long offset) { printf ("\n"); printf ("Raid device %s\n",fname); printf ("Superblock found at offset %Lx\n",offset); printf ("sizeof(sb)=%u sizeof(u32)=%u\n",(unsigned)sizeof(sb),(unsigned)sizeof(u32)); printf ("version=%u\n",sb.version); printf ("MDX UUID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n" ,sb.uuid[0],sb.uuid[1],sb.uuid[2],sb.uuid[3] ,sb.uuid[4],sb.uuid[5],sb.uuid[6],sb.uuid[7] ,sb.uuid[8],sb.uuid[9],sb.uuid[10],sb.uuid[11] ,sb.uuid[12],sb.uuid[13],sb.uuid[14],sb.uuid[15]); printf ("DEV UUID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n" ,sb.dev_uuid[0],sb.dev_uuid[1],sb.dev_uuid[2],sb.dev_uuid[3] ,sb.dev_uuid[4],sb.dev_uuid[5],sb.dev_uuid[6],sb.dev_uuid[7] ,sb.dev_uuid[8],sb.dev_uuid[9],sb.dev_uuid[10],sb.dev_uuid[11] ,sb.dev_uuid[12],sb.dev_uuid[13],sb.dev_uuid[14],sb.dev_uuid[15]); printf ("name=%32.32s\n",sb.name); printf ("pad0=%u\n",sb.pad0); printf ("level=%u\n",sb.level); printf ("raiddisks=%u\n",sb.raiddisks); printf ("features=%x\n",sb.features); printf ("ctime=%Lu.%06Lu\n",sb.ctime & 0xffffffffffLL ,(sb.ctime & 0xffffff0000000000LL)>>40); printf ("bitmap offset=%d\n",sb.bitmap_offset); printf ("size=%Lu\n",sb.size); printf ("chunksize=%u\n",sb.chunksize); printf ("events=%Lu\n",sb.events); printf ("utime=%Lu.%06Lu\n",sb.utime & 0xffffffffffLL ,(sb.utime & 0xffffff0000000000LL)>>40); printf ("reshape newlevel=%u nextadr=%Lu delta=%u new_layout=%u new_chunk=%u pad1=%u\n" ,sb.newlevel,sb.nextadr,sb.delta_disks,sb.new_layout,sb.new_chunk,sb.pad1); if (sb.resync_offset == (u64)-1){ printf ("resync_offset=idle recovery_offset=%Lu\n",sb.recovery_offset); }else{ printf ("resync_offset=%Lu recovery_offset=%Lu\n",sb.resync_offset,sb.recovery_offset); } printf ("data_offset=%Lu data_sectors=%Lu END=%Lx super_offset=%Lu\n" ,sb.data_offset,sb.data_sectors,(sb.data_sectors+sb.data_offset)*512 ,sb.super_offset); printf ("dev_number=%08x corrected_reads=%u dev_flags=%02x\n",sb.dev_number ,sb.corrected_reads,sb.dev_flags); printf ("pads=[%u,%u,%u,%u,%u,%u,%u]\n",sb.pad2[0],sb.pad2[1],sb.pad2[2] ,sb.pad2[3],sb.pad2[4],sb.pad2[5],sb.pad2[6]); printf ("max_dev=%u [%x %x ...]\n",sb.max_dev,sb.devs[0],sb.devs[1]); printf ("checksum=%u Computed checksum=%u\n",sb.sb_csum ,drraid_chksum(sb)); if ((sb.features & 0x1)!=0){ // There is a bitmap printf ("Bitmap\n"); #if 0 char bitmap[4096]; unsigned long long boff = offset + sb.bitmap_offset*512; if (fseeko64(fin,boff,SEEK_SET)==-1){ tlmp_error ("Can't seek at position %Lu (%s)\n" ,boff,strerror(errno)); }else if ((nb=fread(bitmap,1,sizeof(bitmap),fin))!=sizeof(bitmap)){ tlmp_error ("Can't read %lu bytes: %d read (%s)\n" ,sizeof(bitmap),nb,strerror(errno)); } #endif } } /* Read the RAID super block at a given offset Return 0 if found. Return -1 if any error. */ static int drraid_readsb ( FILE *fin, unsigned long long offset, SUPERBLOCK &sb) { int ret = -1; union { SUPERBLOCK sb; unsigned char buf[MD_SB_BYTES]; } u; int nb; if (fseeko64(fin,offset,SEEK_SET)==-1){ tlmp_error ("Can't seek at position %Lu (%s)\n" ,offset,strerror(errno)); }else if ((nb=fread(&u,1,sizeof(u),fin))!=sizeof(u)){ tlmp_error ("Can't read %lu bytes: %d read (%s)\n" ,sizeof(u),nb,strerror(errno)); }else{ if (u.sb.magic == 0xa92b4efc){ if (u.sb.version != 1){ tlmp_error ("Bad version %u for raid superblock\n",u.sb.version); }else if (u.sb.level != 1){ tlmp_error ("Raid device level %u found, not supported\n" ,u.sb.level); }else{ printf ("Superblock found at offset %Lx\n",offset); u32 computed_csum = drraid_chksum(u.sb); if (u.sb.sb_csum != computed_csum){ tlmp_error ("Invalid checksum: %08x != %08x\n" ,u.sb.sb_csum,computed_csum); }else{ sb = u.sb; ret = 0; } } } } return ret; } int drraid_findsb ( const char *fname, SUPERBLOCK &sb, unsigned long long &offset) { int ret = -1; FILE *fin = fopen (fname,"r"); if (fin == NULL){ tlmp_error ("Can't open file %s (%s)\n",fname,strerror(errno)); }else{ unsigned long long size; if (fseeko64 (fin,0,SEEK_END)==-1){ tlmp_error ("Can't seek to end of file %s (%s)\n" ,fname,strerror(errno)); }else if ((size=ftello64(fin))==(unsigned long long)-1){ tlmp_error ("Can't ftell file %s (%s)\n" ,fname,strerror(errno)); //struct stat64 st; //if (fstat64(fileno(fin),&st)==-1){ // tlmp_error ("Can't stat file %s (%s)\n" // ,fname,strerror(errno)); }else{ offset = size-8*1024; ret = drraid_readsb (fin,offset,sb); if (ret == -1){ tlmp_error ("No RAID 1 superblock found for device %s at offset %08Lx %08Lx\n" ,fname,offset,size); } } fclose (fin); } return ret; } int drraid_sync( const SUPERBLOCK &sb_src, SUPERBLOCK &sb_dst, const char *fname, unsigned long long offset) { int ret = -1; sb_dst.events = sb_src.events; sb_dst.utime = sb_src.utime; sb_dst.recovery_offset = sb_src.recovery_offset; sb_dst.resync_offset = sb_src.resync_offset; sb_dst.sb_csum = drraid_chksum (sb_dst); FILE *fout = fopen (fname,"r+"); if (fout == NULL){ tlmp_error ("Can't open file %s for writing (%s)\n" ,fname,strerror(errno)); }else{ if (fseeko64(fout,offset,SEEK_SET)==-1){ tlmp_error ("Can't seek in file %s at position %Lu (%s)\n" ,fname,offset,strerror(errno)); }else if (fwrite (&sb_dst,1,sizeof(sb_dst),fout)!=sizeof(sb_dst)){ tlmp_error ("Can't write to file %s (%s)\n" ,fname,strerror(errno)); }else{ ret = fclose (fout); fout = NULL; } if (fout != NULL) fclose (fout); } return ret; } /* Return -1 if two raid devices are unrelated (not part of the same array) */ int drraid_compat ( const char *fname_src, SUPERBLOCK &sb_src, const char *fname_dst, SUPERBLOCK &sb_dst) { int ret = -1; if (memcmp(sb_src.uuid,sb_dst.uuid,sizeof(sb_src.uuid))!=0){ tlmp_error ("UUID mismatch: The two raid devices are not part of the same array\n"); }else if (sb_src.ctime != sb_dst.ctime){ tlmp_error ("CTIME mismatch: The two raid devices are not parf of the same array\n"); }else if (sb_src.size != sb_dst.size){ tlmp_error ("SIZE mismatch: %s has %Lu, %s has %Lu\n" ,fname_src,sb_src.size,fname_dst,sb_dst.size); }else if (memcmp(sb_src.name,sb_dst.name,sizeof(sb_src.name))!=0){ tlmp_error ("Name mismatch: %s has %32.32s, %s has %32.32s\n" ,fname_src,sb_src.name,fname_dst,sb_dst.name); }else{ ret = 0; } return ret; } /* Tell if two RAID devices are in sync */ bool drraid_insync( SUPERBLOCK &sb_src, SUPERBLOCK &sb_dst) { return sb_dst.events == sb_src.events && sb_dst.utime == sb_src.utime && sb_dst.recovery_offset == sb_src.recovery_offset && sb_dst.resync_offset == sb_src.resync_offset; }