LibreELEC RAID support

Published on Author Artem Butusov4 Comments

Why?

LibreELEC will not support RAID, either hardware or software configurations, as it is considered out of scope for this project. Consider a NAS.

But LibreELEC is Linux-based and it is open, so we could bring RAID support and customize it for our needs.

Requirements

Here are my requirements for RAID and my configuration:

  • RAID mirror for two usb hard drives
  • email notifications about RAID state
  • build everything on OS X
  • run S905-based media box with LibreELEC

If you have a different media box, windows you will need to slightly alter installation workflow.

Prerequisites

  • working LibreELEC installed on SD card
  • Docker for OS X to run Linux toolchain
  • knowledge of mdadm

Build LibreELEC

Technically, you could use cross compiler to build LibreELEC on OS X, but I didn’t try it.

I will do that in Debian within Docker container.

Prepare Linux Docker container

I will use Debian as example below.

Create docker and log into it:

docker run -dit --name libreelec-build debian

Log into it:

docker attach libreelec-build

Upgrade repos:

apt-get update && apt-get upgrade

Install build toolchain:

apt-get install gcc make git wget

Install some other build dependencies:

apt-get install bc patchutils bzip2 gawk gperf zip unzip lzop g++ default-jre u-boot-tools texinfo xfonts-utils xsltproc libncurses5-dev xz-utils

To make x86 dtbTool work on x86_64:

dpkg --add-architecture i386
apt-get update
apt-get install libc6-i386 lib32stdc++6

Checkout LibreELEC sources

Firstly you need to find repo with LibreELEC source related to your architecture.

In my case it is (for S905 fork): https://github.com/kszaq/LibreELEC.tv.git

Download repo:

cd ~
git clone https://github.com/kszaq/LibreELEC.tv.git

Checkout specific version:

cd ~/LibreELEC.tv
git tag | less
git checkout X.X.Xy

Build LibreELEC without patches

Build the same version of LibreELEC you have already installed to test if it works well. If it will work well then you could move to next step, if it doesn’t work then you are doing something wrong (wrong platform, architecture, version, repo etc).

Original compilation process is documented here: https://wiki.libreelec.tv/index.php?title=Compile

Download package sources:

PROJECT=S905 ARCH=arm tools/download-tool

Build image:

PROJECT=S905 ARCH=arm make image

Leave it compiling for a night 🙂 Once it will finish you could continue.

Result *.tar.gz image will be in: ~/LibreELEC.tv/target

Copy image to host from Docker container

Find needed image file.

find ~/LibreELEC.tv/target

Run on host (replace {path} with actual *.tar.gz image path) to copy LibreELEC image to ~/Downloads OS X folder:

docker cp libreelec-build:{path} ~/Downloads

Upgrade LibreELEC media and test it

Below is instruction for S905, OS X and for scenario when LibreELEC is installed on SD card.

Unpack new image:

open ~/Downloads/{path}.tar.gz

Insert LibreELEC SD Card. It should be mounted as /Volumes/LIBREELEC.

Mount new LibreELEC image:

hdiutil attach -imagekey diskimage-class=CRawDiskImage {path}.img

Copy all files except dtb.img from mounted image to SD card.

Don’t forget to create /opt folder in SYSTEM image root again if you already have optware-like installed:

cd /Volumes/LIBREELEC
mkdir -p new/opt
mksquashfs new SYSTEM -all-root
rm -rf new

Unmount both LibreELEC SD card and image.

Boot your media box with SD card.

If it works well then you could move to next step.

Patch LibreELEC sources

Fix kernel config

We will need to update this kernel config file (for S905): ~/LibreELEC.tv/projects/S905/linux/linux.arm.conf

Below is the diff file you need to save somewhere, for example, in ~/LibreELEC.tv/projects/S905/linux/linux.arm.conf.patch:

--- .config 2017-05-24 03:03:17.557759250 +0000
+++ .config 2017-05-24 03:17:54.506204792 +0000
@@ -1416,7 +1416,18 @@
 # CONFIG_SCSI_OSD_INITIATOR is not set
 CONFIG_HAVE_PATA_PLATFORM=y
 # CONFIG_ATA is not set
-# CONFIG_MD is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_AUTODETECT is not set
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID10=y
+CONFIG_MD_RAID456=y
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_BCACHE is not set
+# CONFIG_BLK_DEV_DM is not set
 # CONFIG_TARGET_CORE is not set
 CONFIG_NETDEVICES=y
 CONFIG_MII=y
@@ -3317,6 +3328,7 @@
 # CONFIG_INTERVAL_TREE_TEST is not set
 # CONFIG_PERCPU_TEST is not set
 # CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_ASYNC_RAID6_TEST is not set
 # CONFIG_TEST_STRING_HELPERS is not set
 # CONFIG_TEST_KSTRTOX is not set
 # CONFIG_DMA_API_DEBUG is not set
@@ -3342,7 +3354,12 @@
 CONFIG_SECURITYFS=y
 CONFIG_DEFAULT_SECURITY_DAC=y
 CONFIG_DEFAULT_SECURITY=""
-CONFIG_XOR_BLOCKS=m
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_ASYNC_PQ=y
+CONFIG_ASYNC_RAID6_RECOV=y
 CONFIG_CRYPTO=y

 #
@@ -3459,7 +3476,7 @@
 #
 # Library routines
 #
-CONFIG_RAID6_PQ=m
+CONFIG_RAID6_PQ=y
 CONFIG_BITREVERSE=y
 CONFIG_RATIONAL=y
 CONFIG_GENERIC_STRNCPY_FROM_USER=y

Apply patch:

patch ~/LibreELEC.tv/projects/S905/linux/linux.arm.conf ~/LibreELEC.tv/projects/S905/linux/linux.arm.conf.patch

Add mdadm package

mdadm building from source code is well described in Linux From Scratch documentation: http://www.linuxfromscratch.org/blfs/view/cvs/postlfs/mdadm.html

mkdir -p ~/LibreELEC.tv/packages/sysutils/mdadm
nano ~/LibreELEC.tv/packages/sysutils/mdadm/package.mk

Put this content into ~/LibreELEC.tv/packages/sysutils/mdadm/package.mk:

PKG_NAME="mdadm"
PKG_VERSION="3.4"
PKG_ARCH="any"
PKG_LICENSE="LGPLv2"
PKG_SITE="http://neil.brown.name/blog/mdadm"
PKG_URL="http://www.kernel.org/pub/linux/utils/raid/$PKG_NAME/$PKG_NAME-$PKG_VERSION.tar.gz"
PKG_DEPENDS_TARGET="toolchain systemd"
PKG_SECTION="system"
PKG_SHORTDESC="mdadm: manager for raid arrays"
PKG_LONGDESC="mdadm is a tool for managing Linux Software RAID arrays."

PKG_IS_ADDON="no"
PKG_AUTORECONF="no"

STRIP="--strip --strip-program=$STRIP"

PKG_MAKE_OPTS_TARGET="SYSCONFDIR=/storage/.config CC=$CC CWFLAGS="
PKG_MAKEINSTALL_OPTS_TARGET="SYSTEMD_DIR=/usr/lib/systemd/system BINDIR=/usr/sbin install-systemd"

Make busybox package depend on mdadm package:

nano ~/LibreELEC.tv/packages/sysutils/busybox/package.mk

Add mdadm in the end of PKG_DEPENDS_TARGET variable:

PKG_DEPENDS_TARGET="... mdadm"

Rebuild LibreELEC

LibreELEC build system will be able to rebuild only your changes without rebuilding everything.

cd ~/LibreELEC.tv

Clear kernel build (we upgraded kernel configuration, so we need to rebuild it):

rm -rf build.*/linux-*
PROJECT=S905 ARCH=arm make image

Result *.tar.gz image will be in: ~/LibreELEC.tv/target

Upgrade LibreELEC media

Upgrade LibreELEC media again in the same way as you already did that but in this case we will have LibreELEC with RAID-capable Linux kernel and mdadm installed.

Configure RAID

Build raid array with mdadm, create partitions, format partitions and mount them via system.d. This out of scope for this article.

System.d unit could be like below.

nano /storage/.config/system.d/storage-mirror.mount

For example:

[Unit]
Requires=local-fs.target
After=local-fs.target

[Mount]
What=/dev/disk/by-uuid/2adbab97-d22e-4fbf-bb74-40520155c52e
Where=/storage/mirror
Type=ext4
Options=noatime

[Install]
WantedBy=multi-user.target

You could find partition UUID with:

blkid

You need to also enable service and start service:

systemctl enable storage-mirror.mount
systemctl start storage-mirror.mount

Note: unit name should be equal to mount point: /storage/mirror -> storage-mirror.mount

Setup email notifications

Install sendmail-like MTA

Install optware-like opkg package manager. Follow this article: https://www.artembutusov.com/libreelec-entware-ng-installation/

Install and configure sendmail. Follow this article: http://www.artembutusov.com/libreelec-sendmail/

Configure mdadm

Here we assume that you have mdadm installed and patched to look for mdadm.conf file in /storage/.config/mdadm.conf.

Mdadm monitor by default will search for sendmail in /usr/sbin/sendmail and will not be able to find sendmail installed as /opt/sbin/sendmail, so MAILADDR, MAILFROM will not work by default.

But PROGRAM will still work and we could create shell wrapper which will do wherever we want.

Edit mdadm config:

nano /storage/.config/mdadm.conf

Put this content:

PROGRAM /storage/.config/mdadm-program.sh

Edit mdadm event handler:

nano /storage/.config/mdadm-program.sh

Put this content (change to your email):

#!/bin/sh

EVENT=$1
DEV=$2
COMPDEV=$3

PROGRAM=mdadm
HOST=$(hostname)
SENDMAIL=/opt/sbin/sendmail
EMAIL=your.email@domain.com

SUBJECT="$PROGRAM@$HOST: $EVENT $DEV $COMPDEV"

BODY="$(cat /proc/mdstat)"

echo -e "Subject: $SUBJECT\n\n$BODY" | $SENDMAIL -t $EMAIL

Make handler executable:

chmod +x /storage/.config/mdadm-program.sh

Each time you will restart media box you will get a new message from mdadm that RAID array was successfully assembled.

If it is not what you want you could slightly fix program (wrap in if condition):

if [ $EVENT != "NewArray" ]; then
    echo -e "Subject: $SUBJECT\n\n$BODY" | $SENDMAIL -t $EMAIL
fi

Test mdadm notifications

Run mdadm --monitor --scan --test to get test message from mdadm monitor.

You will need to temporarily stop mdmonitor service if it is running to to do that:

systemctl stop mdmonitor
mdadm --monitor --scan --test
# press CTRL+C once you get email
systemctl start mdmonitor

But anyway you should be able to get message from mdadm monitor even if your just restart mdadm monitor (email about NewArray event).

Conclusion

You should get a stable RAID support in LibreELEC without any impact on media capabilities.

Unfortunately most LibreELEC media boxes with S905 have slow USB2 so your RAID will not be so fast as it could be on better media box but it is still acceptable if you don’t need super speed. You could share this volume over Samba (Windows), NFS (Linux) or AFP (OS X) and use it over network. You could install software on LibreELEC which will in background download something on the disk.

Please note, RAID5 and RAID6 could be significantly heavier for your media box so I don’t recommend them, but RAID0 (stripe), RAID1 (mirror) and JBOD should be fine.

Please note, most cheap media boxes will have just one or two USB2 host controllers, each USB2 host controller has bandwidth of 450Mbps which will be shared between all connected devices. In my case I got real disk bandwidth around 250Mbps, 125Mbps per each disk in USB docking stating.

If you have media box with USB3 then you should be totally fine.

If somebody is interested I used this cheap USB HDD docking station to connect two hard drives to media box over USB: Inateck FD2002 https://www.amazon.com/gp/product/B00N1KXE9K (this device 100% supports mounting of both drives in the same time). I created RAID mirror on them to be sure that I will not loose any data if one drive will fail. This RAID mirror is shared over network via Samba and AFP and I’m using it also as Time Machine backup disk. See this article: http://www.artembutusov.com/libreelec-as-time-machine-backup-network-device/

I tested it on my media box and it is very stable. Much much more stable than the same disks worked in RAID mirror in NAS Western Digital MyBook DUO. Actually, buggy WD NAS firmware was the main reason for me to run soft RAID on LibreELEC and use LibreELEC as NAS 🙂

The only possible disadvantage of your custom LibreELEC build is that you will have rebuild image manually if you need to update LibreELEC’s version.

4 Responses to LibreELEC RAID support

  1. Make busybox package depend on mdadm package:
    nano ~/LibreELEC.tv/packages/sysutils/mdadm/package.mk

    It’s misspelling? Correct path to the file “~/LibreELEC.tv/packages/sysutils/busybox/package.mk”?

  2. Hello everybody,
    excuse my bad English.
    If I specify the UUID, I get the following error in the log:

    dev-disk-by\x2duuid-7e01f6c9:e0eac9a1:51300482:f1addd84.device: Job dev-disk-by\x2duuid-7e01f6c9:e0eac9a1:51300482:f1addd84.device/start timed out.
    Jun 03 18:17:54 H2 systemd[1]: Timed out waiting for device dev-disk-by\x2duuid-7e01f6c9:e0eac9a1:51300482:f1addd84.device.
    Jun 03 18:17:54 H2 systemd[1]: Dependency failed for /storage/mirror.
    Jun 03 18:17:54 H2 systemd[1]: storage-mirror.mount: Job storage-mirror.mount/start failed with result ‘dependency’.
    Jun 03 18:17:54 H2 systemd[1]: dev-disk-by\x2duuid-7e01f6c9:e0eac9a1:51300482:f1addd84.device: Job dev-disk-by\x2duuid-7e01f6c9:e0eac9a1:51300482:f1addd84.device/start failed with result ‘timeout’.

    At “blkid” I get.

    /dev/nvme0n1p1: LABEL=”System” UUID=”5CF4-B914″ TYPE=”vfat” PARTLABEL=”primary” PARTUUID=”d72d59a1-5814-4210-afb6-b59204b8a42c”

    /dev/nvme0n1p2: LABEL=”Storage” UUID=”be3f7335-2b94-48ef-988c-3179b73c9e32″ TYPE=”ext4″ PARTLABEL=”primary” PARTUUID=”9cd29391-0d36-494f-ad59-4c5252f350e0″

    /dev/sda1: UUID=”7e01f6c9-e0ea-c9a1-5130-0482f1addd84″ UUID_SUB=”adfa7e0e-3284-176c-2741-7985ec7f0ed4″ LABEL=”odroid-h2:0″ TYPE=”linux_raid_member” PARTUUID=”e7f17b56-01″

    /dev/sdc1: UUID=”7e01f6c9-e0ea-c9a1-5130-0482f1addd84″ UUID_SUB=”a49404c6-fcec-37cc-23f2-73a433d802e7″ LABEL=”odroid-h2:0″ TYPE=”linux_raid_member” PARTUUID=”25d74589-01″

    /dev/loop0: TYPE=”squashfs”

    /dev/nvme0n1: PTUUID=”4b870414-c07d-45e7-a9ea-ec1faac6980d” PTTYPE=”gpt”

    What am I doing wrong?

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.