]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super1.c
Make '-x nnn' spares work for type-1 superblocks.
[thirdparty/mdadm.git] / super1.c
index 1f6cbe2e5b05aeac4016b2c80564a56246b96c4a..6391857611f83ee22fafa6b335f8e5111a6b6616 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -368,7 +368,7 @@ static __u64 event_super1(void *sbv)
        return __le64_to_cpu(sb->events);
 }
 
-static int init_super1(void **sbp, mdu_array_info_t *info)
+static int init_super1(struct supertype *st, void **sbp, mdu_array_info_t *info)
 {
        struct mdp_superblock_1 *sb = malloc(1024);
        int spares;
@@ -411,7 +411,7 @@ static int init_super1(void **sbp, mdu_array_info_t *info)
 
        sb->utime = sb->ctime;
        sb->events = __cpu_to_le64(1);
-       if (info->state & MD_SB_CLEAN)
+       if (info->state & (1<<MD_SB_CLEAN))
                sb->resync_offset = ~0ULL;
        else
                sb->resync_offset = 0;
@@ -432,20 +432,58 @@ static void add_to_super1(void *sbv, mdu_disk_info_t *dk)
        __u16 *rp = sb->dev_roles + dk->number;
        if (dk->state == 6) /* active, sync */
                *rp = __cpu_to_le16(dk->raid_disk);
-       else if (dk->state == 2) /* active -> spare */
+       else if ((dk->state & ~2) == 0) /* active or idle -> spare */
                *rp = 0xffff;
        else 
                *rp = 0xfffe;
 }
 
-static int store_super1(int fd, void *sbv)
+static int store_super1(struct supertype *st, int fd, void *sbv)
 {
        struct mdp_superblock_1 *sb = sbv;
        long long sb_offset;
        int sbsize;
+       long size;
+
+       if (ioctl(fd, BLKGETSIZE, &size))
+               return 1;
+
+
+       if (size < 24)
+               return 2;
+
+       /*
+        * Calculate the position of the superblock.
+        * It is always aligned to a 4K boundary and
+        * depending on minor_version, it can be:
+        * 0: At least 8K, but less than 12K, from end of device
+        * 1: At start of device
+        * 2: 4K from start of device.
+        */
+       switch(st->minor_version) {
+       case 0:
+               sb_offset = size;
+               sb_offset -= 8*2;
+               sb_offset &= ~(4*2-1);
+               break;
+       case 1:
+               sb->super_offset = __cpu_to_le64(0);
+               break;
+       case 2:
+               sb_offset = 4*2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
 
     
-       sb_offset = __le64_to_cpu(sb->super_offset) << 9;
+       if (sb_offset != (__le64_to_cpu(sb->super_offset) << 9 ) &&
+           0 != (__le64_to_cpu(sb->super_offset) << 9 )
+               ) {
+               fprintf(stderr, Name ": internal error - sb_offset is wrong\n");
+               abort();
+       }
 
        if (lseek64(fd, sb_offset, 0)< 0LL)
                return 3;
@@ -546,7 +584,7 @@ static int write_init_super1(struct supertype *st, void *sbv, mdu_disk_info_t *d
 
 
        sb->sb_csum = calc_sb_1_csum(sb);
-       rv = store_super1(fd, sb);
+       rv = store_super1(st, fd, sb);
        if (rv)
                fprintf(stderr, Name ": failed to write superblock to %s\n", devname);
        close(fd);