(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
linux_raid.c
       1  /*
       2   * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
       3   *
       4   * Inspired by libvolume_id by
       5   *     Kay Sievers <kay.sievers@vrfy.org>
       6   *
       7   * This file may be redistributed under the terms of the
       8   * GNU Lesser General Public License.
       9   */
      10  #include <stdio.h>
      11  #include <stdlib.h>
      12  #include <unistd.h>
      13  #include <string.h>
      14  #include <stdint.h>
      15  
      16  #include "superblocks.h"
      17  
      18  struct mdp0_super_block {
      19  	uint32_t	md_magic;
      20  	uint32_t	major_version;
      21  	uint32_t	minor_version;
      22  	uint32_t	patch_version;
      23  	uint32_t	gvalid_words;
      24  	uint32_t	set_uuid0;
      25  	uint32_t	ctime;
      26  	uint32_t	level;
      27  	uint32_t	size;
      28  	uint32_t	nr_disks;
      29  	uint32_t	raid_disks;
      30  	uint32_t	md_minor;
      31  	uint32_t	not_persistent;
      32  	uint32_t	set_uuid1;
      33  	uint32_t	set_uuid2;
      34  	uint32_t	set_uuid3;
      35  };
      36  
      37  /*
      38   * Version-1, little-endian.
      39   */
      40  struct mdp1_super_block {
      41  	/* constant array information - 128 bytes */
      42  	uint32_t	magic;		/* MD_SB_MAGIC: 0xa92b4efc - little endian */
      43  	uint32_t	major_version;	/* 1 */
      44  	uint32_t	feature_map;	/* 0 for now */
      45  	uint32_t	pad0;		/* always set to 0 when writing */
      46  
      47  	uint8_t		set_uuid[16];	/* user-space generated. */
      48  	unsigned char	set_name[32];	/* set and interpreted by user-space */
      49  
      50  	uint64_t	ctime;		/* lo 40 bits are seconds, top 24 are microseconds or 0*/
      51  	uint32_t	level;		/* -4 (multipath), -1 (linear), 0,1,4,5 */
      52  	uint32_t	layout;		/* only for raid5 currently */
      53  	uint64_t	size;		/* used size of component devices, in 512byte sectors */
      54  
      55  	uint32_t	chunksize;	/* in 512byte sectors */
      56  	uint32_t	raid_disks;
      57  	uint32_t	bitmap_offset;	/* sectors after start of superblock that bitmap starts
      58  					 * NOTE: signed, so bitmap can be before superblock
      59  					 * only meaningful of feature_map[0] is set.
      60  					 */
      61  
      62  	/* These are only valid with feature bit '4' */
      63  	uint32_t	new_level;	/* new level we are reshaping to		*/
      64  	uint64_t	reshape_position;	/* next address in array-space for reshape */
      65  	uint32_t	delta_disks;	/* change in number of raid_disks		*/
      66  	uint32_t	new_layout;	/* new layout					*/
      67  	uint32_t	new_chunk;	/* new chunk size (bytes)			*/
      68  	uint8_t		pad1[128-124];	/* set to 0 when written */
      69  
      70  	/* constant this-device information - 64 bytes */
      71  	uint64_t	data_offset;	/* sector start of data, often 0 */
      72  	uint64_t	data_size;	/* sectors in this device that can be used for data */
      73  	uint64_t	super_offset;	/* sector start of this superblock */
      74  	uint64_t	recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
      75  	uint32_t	dev_number;	/* permanent identifier of this  device - not role in raid */
      76  	uint32_t	cnt_corrected_read; /* number of read errors that were corrected by re-writing */
      77  	uint8_t		device_uuid[16]; /* user-space setable, ignored by kernel */
      78          uint8_t		devflags;        /* per-device flags.  Only one defined...*/
      79  	uint8_t		pad2[64-57];	/* set to 0 when writing */
      80  
      81  	/* array state information - 64 bytes */
      82  	uint64_t	utime;		/* 40 bits second, 24 bits microseconds */
      83  	uint64_t	events;		/* incremented when superblock updated */
      84  	uint64_t	resync_offset;	/* data before this offset (from data_offset) known to be in sync */
      85  	uint32_t	sb_csum;	/* checksum up to dev_roles[max_dev] */
      86  	uint32_t	max_dev;	/* size of dev_roles[] array to consider */
      87  	uint8_t		pad3[64-32];	/* set to 0 when writing */
      88  
      89  	/* device state information. Indexed by dev_number.
      90  	 * 2 bytes per device
      91  	 * Note there are no per-device state flags. State information is rolled
      92  	 * into the 'roles' value.  If a device is spare or faulty, then it doesn't
      93  	 * have a meaningful role.
      94  	 */
      95  	uint16_t	dev_roles[0];	/* role in array, or 0xffff for a spare, or 0xfffe for faulty */
      96  };
      97  
      98  
      99  #define MD_RESERVED_BYTES		0x10000
     100  #define MD_SB_MAGIC			0xa92b4efc
     101  
     102  static int probe_raid0(blkid_probe pr, uint64_t off)
     103  {
     104  	struct mdp0_super_block *mdp0;
     105  	union {
     106  		uint32_t ints[4];
     107  		uint8_t bytes[16];
     108  	} uuid;
     109  	uint32_t ma, mi, pa;
     110  	uint64_t size;
     111  
     112  	if (pr->size < MD_RESERVED_BYTES)
     113  		return 1;
     114  	mdp0 = (struct mdp0_super_block *)
     115  			blkid_probe_get_buffer(pr,
     116  				off,
     117  				sizeof(struct mdp0_super_block));
     118  	if (!mdp0)
     119  		return errno ? -errno : 1;
     120  
     121  	memset(uuid.ints, 0, sizeof(uuid.ints));
     122  
     123  	if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
     124  		uuid.ints[0] = swab32(mdp0->set_uuid0);
     125  		if (le32_to_cpu(mdp0->minor_version) >= 90) {
     126  			uuid.ints[1] = swab32(mdp0->set_uuid1);
     127  			uuid.ints[2] = swab32(mdp0->set_uuid2);
     128  			uuid.ints[3] = swab32(mdp0->set_uuid3);
     129  		}
     130  		ma = le32_to_cpu(mdp0->major_version);
     131  		mi = le32_to_cpu(mdp0->minor_version);
     132  		pa = le32_to_cpu(mdp0->patch_version);
     133  		size = le32_to_cpu(mdp0->size);
     134  
     135  	} else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
     136  		uuid.ints[0] = mdp0->set_uuid0;
     137  		if (be32_to_cpu(mdp0->minor_version) >= 90) {
     138  			uuid.ints[1] = mdp0->set_uuid1;
     139  			uuid.ints[2] = mdp0->set_uuid2;
     140  			uuid.ints[3] = mdp0->set_uuid3;
     141  		}
     142  		ma = be32_to_cpu(mdp0->major_version);
     143  		mi = be32_to_cpu(mdp0->minor_version);
     144  		pa = be32_to_cpu(mdp0->patch_version);
     145  		size = be32_to_cpu(mdp0->size);
     146  	} else
     147  		return 1;
     148  
     149  	size <<= 10;	/* convert KiB to bytes */
     150  
     151  	if (pr->size < size + MD_RESERVED_BYTES)
     152  		/* device is too small */
     153  		return 1;
     154  
     155  	if (off < size)
     156  		/* no space before superblock */
     157  		return 1;
     158  
     159  	/*
     160  	 * Check for collisions between RAID and partition table
     161  	 *
     162  	 * For example the superblock is at the end of the last partition, it's
     163  	 * the same position as at the end of the disk...
     164  	 */
     165  	if ((S_ISREG(pr->mode) || blkid_probe_is_wholedisk(pr)) &&
     166  	    blkid_probe_is_covered_by_pt(pr,
     167  			off - size,				/* min. start  */
     168  			size + MD_RESERVED_BYTES)) {		/* min. length */
     169  
     170  		/* ignore this superblock, it's within any partition and
     171  		 * we are working with whole-disk now */
     172  		return 1;
     173  	}
     174  
     175  	if (blkid_probe_sprintf_version(pr, "%u.%u.%u", ma, mi, pa) != 0)
     176  		return 1;
     177  	if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
     178  		return 1;
     179  	if (blkid_probe_set_magic(pr, off, sizeof(mdp0->md_magic),
     180  				(unsigned char *) &mdp0->md_magic))
     181  		return 1;
     182  	return 0;
     183  }
     184  
     185  static int raid1_verify_csum(blkid_probe pr, off_t off,
     186  		const struct mdp1_super_block *mdp1)
     187  {
     188  	size_t csummed_size = sizeof(struct mdp1_super_block)
     189  		+ le32_to_cpu(mdp1->max_dev) * sizeof(mdp1->dev_roles[0]);
     190  	unsigned char *csummed = blkid_probe_get_buffer(pr, off, csummed_size);
     191  	if (!csummed)
     192  		return 1;
     193  
     194  	memset(csummed + offsetof(struct mdp1_super_block, sb_csum), 0,
     195  			sizeof(mdp1->sb_csum));
     196  
     197  	uint64_t csum = 0;
     198  
     199  	while (csummed_size >= 4) {
     200  		csum += le32_to_cpu(*(uint32_t *) csummed);
     201  		csummed_size -= 4;
     202  		csummed += 4;
     203  	}
     204  	if (csummed_size == 2)
     205  		csum += le16_to_cpu(*(uint16_t *) csummed);
     206  
     207  	csum = (csum >> 32) + (uint32_t) csum;
     208  	return blkid_probe_verify_csum(pr, csum, le32_to_cpu(mdp1->sb_csum));
     209  }
     210  
     211  static int probe_raid1(blkid_probe pr, off_t off)
     212  {
     213  	struct mdp1_super_block *mdp1;
     214  
     215  	mdp1 = (struct mdp1_super_block *)
     216  			blkid_probe_get_buffer(pr,
     217  				off,
     218  				sizeof(struct mdp1_super_block));
     219  	if (!mdp1)
     220  		return errno ? -errno : 1;
     221  	if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
     222  		return 1;
     223  	if (le32_to_cpu(mdp1->major_version) != 1U)
     224  		return 1;
     225  	if (le64_to_cpu(mdp1->super_offset) != (uint64_t) off >> 9)
     226  		return 1;
     227  	if (!raid1_verify_csum(pr, off, mdp1))
     228  		return 1;
     229  	if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
     230  		return 1;
     231  	if (blkid_probe_set_uuid_as(pr,
     232  			(unsigned char *) mdp1->device_uuid, "UUID_SUB") != 0)
     233  		return 1;
     234  	if (blkid_probe_set_label(pr, mdp1->set_name,
     235  				sizeof(mdp1->set_name)) != 0)
     236  		return 1;
     237  	if (blkid_probe_set_magic(pr, off, sizeof(mdp1->magic),
     238  				(unsigned char *) &mdp1->magic))
     239  		return 1;
     240  	return 0;
     241  }
     242  
     243  static int probe_raid(blkid_probe pr,
     244  		const struct blkid_idmag *mag __attribute__((__unused__)))
     245  {
     246  	const char *ver = NULL;
     247  	int ret = BLKID_PROBE_NONE;
     248  
     249  	if (pr->size > MD_RESERVED_BYTES) {
     250  		/* version 0 at the end of the device */
     251  		uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
     252  			- MD_RESERVED_BYTES;
     253  		ret = probe_raid0(pr, sboff);
     254  		if (ret < 1)
     255  			return ret;	/* error */
     256  
     257  		/* version 1.0 at the end of the device */
     258  		sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
     259  		ret = probe_raid1(pr, sboff);
     260  		if (ret < 0)
     261  			return ret;	/* error */
     262  		if (ret == 0)
     263  			ver = "1.0";
     264  	}
     265  
     266  	if (!ver) {
     267  		/* version 1.1 at the start of the device */
     268  		ret = probe_raid1(pr, 0);
     269  		if (ret == 0)
     270  			ver = "1.1";
     271  
     272  		/* version 1.2 at 4k offset from the start */
     273  		else if (ret == BLKID_PROBE_NONE) {
     274  			ret = probe_raid1(pr, 0x1000);
     275  			if (ret == 0)
     276  				ver = "1.2";
     277  		}
     278  	}
     279  
     280  	if (ver) {
     281  		blkid_probe_set_version(pr, ver);
     282  		return BLKID_PROBE_OK;
     283  	}
     284  	return ret;
     285  }
     286  
     287  
     288  const struct blkid_idinfo linuxraid_idinfo = {
     289  	.name		= "linux_raid_member",
     290  	.usage		= BLKID_USAGE_RAID,
     291  	.probefunc	= probe_raid,
     292  	.magics		= BLKID_NONE_MAGIC
     293  };
     294  
     295