Using the Linux parted utility to re-create a lost partition table

I ran into an issue last week where two nodes using shared storage lost the partition table on one of the storage devices they were accessing. This was extremely evident in the output from fdisk:

$ fdisk -l /dev/sdb

Disk /dev/sdb: 107.3 GB, 107374182400 bytes
255 heads, 63 sectors/track, 13054 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System

Fortunately the system in question still had the /proc/partition data in tact, so I stashed that in a safe location and came up with a plan to re-recreate the partition tables using this data. Given the following /proc/partitions data for the device listed above:

$ grep sdb /proc/partitions

   8    16  104857600 sdb
   8    17   99161148 sdb1
   8    18    5695042 sdb2

I can see that the device had two partion table entries, and the device was approximately 100GB in size. To re-create the partition tables, I used the parted mkpart command passing it the starting and ending sector numbers I wanted written to the partition table:

$ mkpart /dev/sdb

(parted) mkpart primary ext3 128s 198322424s

(parted) mkpart primary ext3 198322425s 209712509s

Now you may be asking yourself where did I get the starting and ending sectors from? In my specific case I start the partition tables at sector 128 to ensure alignment with the storage arrays we use, and the end sector was calculated by taking the partion table entry from /proc/partitions and multiplying it by 2 (the /proc/partitions sizes are in 1k chunks). I also had to add the 128 sector offset to this value, giving the resulting end sector for sdb1:

99161148 * 2 + 128 = 198322424 end sector for sdb1

To get the values for sdb2, I added one to the number produced above, and then multiplied the sdb2 value from /proc/partitions by two to get the following numbers:

198322424 + 1 = 198322425 start sector or sdb2

198322425 + 11390084 = 209712509 end sector of sdb2

Once I wrote out my changes, I verified that they were correct with sfdisk:

$ sfdisk -uS -l /dev/sdb

Disk /dev/sdb: 13054 cylinders, 255 heads, 63 sectors/track
Units = sectors of 512 bytes, counting from 0

   Device Boot    Start       End   #sectors  Id  System
/dev/sdb1           128 198322424  198322297  83  Linux
/dev/sdb2     198322425 209712509   11390085  83  Linux
/dev/sdb3             0         -          0   0  Empty
/dev/sdb4             0         -          0   0  Empty

And verified that /proc/partitions matched up with what was previously there:

$ grep sdb /proc/partitions

   8    16  104857600 sdb
   8    17   99161148 sdb1
   8    18    5695042 sdb2

Now that the partition table was restored, I used the fsck “-n” option to verify the file system was complete (make sure to read the fsck manual page before running it, as the “-n” option WILL modify some file systems!!):

$ fsck -n /dev/sdb1
fsck 1.39 (29-May-2006)
e2fsck 1.39 (29-May-2006)
/dev/sdb1: clean, 11/12402688 files, 437281/24790287 blocks

$ fsck -n /dev/sdb2
fsck 1.39 (29-May-2006)
e2fsck 1.39 (29-May-2006)
/dev/sdb2: clean, 11/712448 files, 57952/1423760 blocks

And then proceeded to mount them up:

$ mount /dev/sdb1 /a

$ mount /dev/sdb2 /b

$ df -h | grep sdb

/dev/sdb1              94G  188M   89G   1% /a
/dev/sdb2             5.4G  139M  5.0G   3% /b

I’m not a data recovery person / service (just a guy who reads a lot and understands the internals of how file systems and devices are structured), so use this information at your own risk!

3 thoughts on “Using the Linux parted utility to re-create a lost partition table”

  1. Very nice post. I suspect you used shared disks (probably iscsi?) in ESX. Where did you find info about this 128 sector offset?

  2. Hey Hubert,

    I learned about storage offsets in my EMC Clariion class a few years back. Now when I work with a new storage vendor, the first thing I ask is how to make the host-devices align with the storage on the array.

    – Ryan

Leave a Reply

Your email address will not be published. Required fields are marked *