2

I’ve got a Synology NAS that I’m trying to reduce a RAID6 array from 12 drives down to 11 drives.

I’ve already reduced the size of the file system and logical volume, but when I try to reduce the size of the RAID array to 11 drives, mdadm just gives me an error.

root@DiskStation:~# mdadm -V
mdadm - v3.4 - 28th January 2016

root@DiskStation:~# mdadm -D /dev/md2
/dev/md2:
        Version : 1.2
  Creation Time : Sat Jul 12 13:24:29 2014
     Raid Level : raid6
     Array Size : 19487796480 (18585.01 GiB 19955.50 GB)
  Used Dev Size : 1948779648 (1858.50 GiB 1995.55 GB)
   Raid Devices : 12
  Total Devices : 12
    Persistence : Superblock is persistent

    Update Time : Tue Feb  4 10:14:55 2020
          State : clean
 Active Devices : 12
Working Devices : 12
 Failed Devices : 0
  Spare Devices : 0

         Layout : left-symmetric
     Chunk Size : 64K

           Name : DiskStation:2  (local to host DiskStation)
           UUID : 263bdad7:eed15299:ff0c7a70:c97ee595
         Events : 414186

    Number   Major   Minor   RaidDevice State
      15       8        5        0      active sync   /dev/sda5
       1       8       21        1      active sync   /dev/sdb5
       8       8       37        2      active sync   /dev/sdc5
       9       8       53        3      active sync   /dev/sdd5
       4       8       69        4      active sync   /dev/sde5
       7       8      117        5      active sync   /dev/sdh5
       6       8      101        6      active sync   /dev/sdg5
       5       8       85        7      active sync   /dev/sdf5
      11       8      133        8      active sync   /dev/sdi5
      12       8      149        9      active sync   /dev/sdj5
      13       8      165       10      active sync   /dev/sdk5
      14       8      181       11      active sync   /dev/sdl5

root@DiskStation:~# mdadm --grow -n11 /dev/md2
mdadm: Not allowed to reduce the number of devices.

I have very little experience with this sort of thing, and the fact that I can’t find anything online regarding that particular error has left me at a dead end.

I’ve been following these instructions here, and they say I should be prompted to reduce the array size. Do I just need to go ahead and reduce the array size anyway without being prompted? How do I know what size to make it?

Scibit
  • 21
  • 1

1 Answers1

0

I know this question was asked years ago, but for posterity: this is a custom patch that Synology applied to their fork of mdadm.

I suspect the reason why you weren't able to find any info on this is a combination of the fact that RAID shrinkage is something that Synology tries very hard to claim is not possible (the post you link to is the ONLY info on the net that I'm aware of that doesn't just say "backup your data, delete the RAID, create a new one") and the fact that this patch has been introduced after that post had been written.

Since mdadm is GPL-licensed, all modifications have to be open sourced, and Synology distributes their tarballs here. I'm looking at DSM 7.2 and mdadm 3.4 here. As far as I can tell, the mdadm tarballs all have the same contents, but the files are archived in different order, so the hashes of the tarballs are all different - because of course they are.

If you download and of those mdadm tarballs and compare it to upstream mdadm 3.4, you'll see this in Grow.c:

screenshot of file diff

In other words, if you're using a RAID configuration other than RAID-0 or RAID-1 and the requested amount of drives is smaller than the current amount of drives, the tool refuses. Why? Good question.
There's a very similar check right above it that is also there in the original code, but that only applies if an old Linux kernel version is detected, and it is overridable by environment variable - the Synology check has no override.

At this point, your options are:

  • Compile upstream mdadm from source.
  • Remove this check from the Synology mdadm source and compile that.
  • Apply a binary patch to the stock mdadm binary to skip the check.

I think the downloads offered here should be enough to put together an SDK with which you can compile for DSM, but I haven't tried that. I do know however that just static x86_64 Linux ELF binaries work fine on DSM (in my case built with clang and musl).

But ultimately I went for the binary patch, since that was the least amount of hassle for me.

I'm on DSM 7.2.1-69057 Update 5 and my mdadm has the following sha256 sum:

85a0b4c7bc615aef003e3fb6c368b583928c492cb02f51d58d1b23380ba469d6  /sbin/mdadm

If you just want the patched binary, I've uploaded it here, and this is the checksum:

44b463e565ad0afad77ba35957c0160bb6078ccbe30fa0afa7e0df09e6105f7e  mdadm-3.4-patched

I suggest you DO NOT overwrite the original binary with this, but simply place it in your home folder and run it with ./mdadm. Using this, I was able to successfully shrink a RAID-6 pool from 8 drives to 5 drives.


If you care about the process, I'm using radare2 for this.

First, get the binary from your NAS:

ssh user@nas 'cat /sbin/mdadm' >mdadm

Open the binary for writing:

r2 -w mdadm

Once in the r2 shell, we're gonna look for our error string:

iz~Not allowed to reduce the number of devices.

This will print something like:

1010 0x00075188 0x00075188 49   50   .rodata ascii %s: Not allowed to reduce the number of devices.\n

So our string is at address 0x00075188 (if the two addresses differ, take the second one). Then we run analysis on the binary and print all references to that string:

aaaa
axt 0x00075188

This should give you only a single hit:

fcn.0002e920 0x2ece2 [DATA:r--] lea rdx, str._s:_Not_allowed_to_reduce_the_number_of_devices._n

So we seek to that address and print some surrounding instructions:

0x2ece2
pd -5
pd 5

This should give you something like this:

0x0002ecc0      0f8ffa060000   jg 0x2f3c0
0x0002ecc6      83bc249000..   cmp dword [rsp + 0x90], 1
0x0002ecce      0f8e57fdffff   jle 0x2ea2b
0x0002ecd4      488b3d6535..   mov rdi, qword [obj.stderr]
0x0002ecdb      488d0dbaf0..   lea rcx, str.mdadm
0x0002ece2      488d159f64..   lea rdx, str._s:_Not_allowed_to_reduce_the_number_of_devices._n
0x0002ece9      31c0           xor eax, eax
0x0002eceb      be02000000     mov esi, 2
0x0002ecf0      e8cb7bfdff     call sym.imp.__fprintf_chk
0x0002ecf5      e9e7fcffff     jmp 0x2e9e1

The cmp and jle you can see at the top correspond to the array.level > 1 check in the diff I showed above. What we want to do is turn that jle 0x2ea2b into an unconditional jmp 0x2ea2b. So we seek to that address and do that:

0x0002ecce
"wa jmp 0x2ea2b; nop"

I'm appending a single NOP instruction here to match the size of the original jle instruction - functionally that's not needed, but it makes disassembly a bit cleaner.

And then all that's left to do is quit out of r2:

q

And you have a patched binary.

Siguza
  • 473