How to (try to) recover data from failed RAID0 array

How to (try to) recover data from failed RAID0 array

For experimental reasons I was running a RAID0 array (the speed!) off of two Sandisk Cruiser Mini USB sticks connected to a Raspberry PI.

As expected, due to wear and tear one of the flash memories eventually failed causing the array to go read-only and crash everything that was writing to it, including the array activation

Out of laziness, I didn’t want to look for and restore the lost data from its original source and preferred to simply somehow recover it, then migrate the volume to a single disk (a recycled SSD this time) and be done with it in a matter of minutes. Everything below was done on a Raspberry PI running Raspberry PI OS (so Debian) – on other Linux flavours commands and things in general may be different.

First off, examine if the disks are actually still usable (and mdadm still finds its array members on them). The raid members are partitions a single full-size partition on each of the disks – sdX1, sdY1, so I run the appropriate command:

mdadm --examine /dev/sd[X,Y]1
/dev/sdX1:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x0
     Array UUID : 41f1a962:cb87c516:45aedb09:982104cc
           Name : pi-raid:0  (local to host pi-raid)
  Creation Time : Tue May 19 18:02:01 2020
     Raid Level : raid0
   Raid Devices : 2

 Avail Dev Size : 58683393 (27.98 GiB 30.05 GB)
    Data Offset : 34816 sectors
   Super Offset : 8 sectors
   Unused Space : before=34736 sectors, after=0 sectors
          State : clean
    Device UUID : abeb438f:e5d1858a:a08c75c0:6324d680

    Update Time : Tue May 19 18:02:01 2020
  Bad Block Log : 512 entries available at offset 8 sectors
       Checksum : 97b7675 - correct
         Events : 0

     Chunk Size : 512K

   Device Role : Active device 1
   Array State : AA ('A' == active, '.' == missing, 'R' == replacing)


/dev/sdY1:
          Magic : a92b4efc
        Version : 1.2
    Feature Map : 0x0
     Array UUID : 41f1a962:cb87c516:45aedb09:982104cc
           Name : pi-raid:0  (local to host pi-raid)
  Creation Time : Tue May 19 18:02:01 2020
     Raid Level : raid0
   Raid Devices : 2

 Avail Dev Size : 58683393 (27.98 GiB 30.05 GB)
    Data Offset : 34816 sectors
   Super Offset : 8 sectors
   Unused Space : before=34736 sectors, after=0 sectors
          State : clean
    Device UUID : 9269e3ce:d3bfe7f5:0c6954c9:cd6c26bf

    Update Time : Tue May 19 18:02:01 2020
  Bad Block Log : 512 entries available at offset 8 sectors
       Checksum : fbac071f - correct
         Events : 0

     Chunk Size : 512K

   Device Role : Active device 0
   Array State : AA ('A' == active, '.' == missing, 'R' == replacing)

Then create images of both (or all) disks

dd if=/dev/sdX of=/disk-imageX.dd bs=10M status=progress
dd if=/dev/sdY of=/disk-imageY.dd bs=10M status=progress

If the data is (somehow) important, make a copy of these images before performing any actions on them.

Since the array members are partitions on the disk images the image files are not directly usable to assemble the array, but instead will need to mount the images as loops first:

losetup –find –show –partscan /disk-imageX.dd
losetup –find –show –partscan /disk-imageY.dd

The commands returns a partitions list in the format:

/dev/loopX
...
/dev/loopY

We can use fdisk to look at the disk structure and find the necessary partition identifiers:

fdisk -l
...
Disk /dev/loopX: 29.25 GiB, 31406948352 bytes, 61341969 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x960b5c8f

Device        Boot Start      End  Sectors Size Id Type
/dev/loopXp1        2048 58720256 58718209  28G 83 Linux
...
Disk /dev/loopY: 29.25 GiB, 32015679488 bytes, 62530624 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x6fcee283

Device        Boot Start      End  Sectors Size Id Type
/dev/loopYp1        2048 58720256 58718209  28G 83 Linux

This shows that the two array member partitions are /dev/loopXp1 and /dev/loopYp1, which can be used to (re)assemble the array:

mdadm --assemble /dev/mdZ /dev/loopXp1 /dev/loopYp1

You should get a confirmation similar to:

mdadm: /dev/mdZ has been started with 2 drives.

Check that the array actually gets mounted

mdadm --detail /dev/mdZ
/dev/mdZ:
           Version : 1.2
     Creation Time : Tue May 19 17:02:01 2020
        Raid Level : raid0
        Array Size : 58683392 (55.96 GiB 60.09 GB)
      Raid Devices : 2
     Total Devices : 2
       Persistence : Superblock is persistent

       Update Time : Tue May 19 17:02:01 2020
             State : clean
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 0

            Layout : -unknown-
        Chunk Size : 512K

Consistency Policy : none

              Name : pi-raid:0
              UUID : 41f1a962:cb87c516:45aedb09:982104cc
            Events : 0

    Number   Major   Minor   RaidDevice State
       0     259        0        0      active sync   /dev/loopXp1
       1     259        2        1      active sync   /dev/loopYp1

Finally mount the array to extract the data:

mount -o ro /dev/mdZ /myfolder

I mounted it read-only to avoid having any data written to the array.

When we’re done recovering the data, unmount the array and then stop it:

umount /dev/mdZ
mdadm --stop /dev/mdZ

Image credit

Leave a Reply