Skip to content

Conversation

@ean365
Copy link

@ean365 ean365 commented Jan 10, 2026

Odroid HC4 is a NAS. Needs to park HDD heads prior to reboot or shutdown. This simple PR adds the already existing odroid.shutdown bsp script (originally used for the XU4) to the meson-sm1.conf file for the HC4.

I have successfully tested the odroid.shutdown script on the HC4 with HDDs, and it properly parks the heads. Without this, the heads are forced to do an emergency retract, which is a violent action that degrades the HDD over time.

Summary by CodeRabbit

  • Chores
    • Added system-level configuration enhancements for improved shutdown handling on select devices.

✏️ Tip: You can customize this high-level summary in your review settings.

Odroid HC4 is a NAS.  Needs to park HDD heads prior to reboot or shutdown.
@ean365 ean365 requested a review from igorpecovnik as a code owner January 10, 2026 05:02
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 10, 2026

📝 Walkthrough

Walkthrough

A new shell function family_tweaks_bsp() is added to the meson-sm1 configuration file. This function creates a systemd shutdown directory and installs an odroid shutdown script with specific permissions when the board is odroidhc4. No existing logic was modified.

Changes

Cohort / File(s) Summary
ODroid HC4 Board Support
config/sources/families/meson-sm1.conf
Added family_tweaks_bsp() function that creates systemd shutdown directory and installs odroid.shutdown script with 0755 permissions for odroidhc4 board variant

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A shutdown script hops in place,
For odroidhc4's special case,
With permissions set just right,
The system shuts down through the night! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main change: adding HDD park functionality at shutdown for the Odroid HC4.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

Hey @ean365! 👋

Thanks for submitting your first pull request to the Armbian project — we're excited to have you contributing! 🧡
Your effort doesn’t just improve Armbian — it benefits the entire community of users and developers.

If you'd like to stay informed about project updates or collaborate more closely with the team,
you can optionally share some personal contact preferences at armbian.com/update-data.
This helps us keep in touch without relying solely on GitHub notifications.

Also, don’t forget to ⭐ star the repo if you haven’t already — and welcome aboard! 🚀

@github-actions github-actions bot added size/small PR with less then 50 lines 02 Milestone: First quarter release Needs review Seeking for review Hardware Hardware related like kernel, U-Boot, ... labels Jan 10, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
config/sources/families/meson-sm1.conf (1)

20-26: Excellent approach: reusing existing shutdown script for HC4.

The implementation correctly gates HDD parking functionality to the odroidhc4 board and follows proper systemd shutdown hook conventions. The permissions (0755) and ownership (root:root) are appropriate. The family_tweaks_bsp() function is automatically invoked during BSP package creation, $destination is properly initialized in the build context, and the odroid.shutdown script exists and is compatible with HC4's SATA hardware.

Optional: Add defensive quoting for path variables

While the current implementation works correctly, quoting variables is a defensive coding best practice for shell scripts:

Suggested improvement
 family_tweaks_bsp() {
 	if [[ $BOARD == odroidhc4 ]]; then
 		# park HDD heads on shutdown
-		mkdir -p $destination/lib/systemd/system-shutdown
-		install -o root -g root -m 0755 $SRC/packages/bsp/odroid/odroid.shutdown $destination/lib/systemd/system-shutdown/odroid.shutdown
+		mkdir -p "$destination/lib/systemd/system-shutdown"
+		install -o root -g root -m 0755 "$SRC/packages/bsp/odroid/odroid.shutdown" "$destination/lib/systemd/system-shutdown/odroid.shutdown"
 	fi
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cbfbfb6 and 432df82.

📒 Files selected for processing (1)
  • config/sources/families/meson-sm1.conf
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: igorpecovnik
Repo: armbian/build PR: 8849
File: config/boards/radxa-e54c.csc:14-28
Timestamp: 2025-11-02T20:49:56.719Z
Learning: In Armbian board configuration files (config/boards/*.conf, *.csc, etc.), do not use kernel_config_set, kernel_config_set_m, kernel_config_set_y, or custom_kernel_config__* functions to modify kernel configuration. Kernel configuration is associated with LINUXFAMILY/BOARDFAMILY, not individual BOARD. Board-specific kernel modifications cause inconsistency in kernel packages published to the apt repository because boards within a family share the same kernel packages. Kernel configuration changes must be made in the appropriate kernel config file (e.g., config/kernel/linux-*-*.config) or in family configuration files (config/sources/families/*.conf, *.inc) instead.
Learnt from: igorpecovnik
Repo: armbian/build PR: 8720
File: lib/functions/rootfs/distro-specific.sh:38-47
Timestamp: 2025-11-09T22:30:27.163Z
Learning: In lib/functions/rootfs/distro-specific.sh, the systemd sleep.conf.d override that disables suspend/hibernation is intentionally applied system-wide to all Armbian images (desktop, CLI, and minimal), not gated to desktop-only builds, because suspend/resume is fragile on most boards.
📚 Learning: 2025-11-02T20:49:56.719Z
Learnt from: igorpecovnik
Repo: armbian/build PR: 8849
File: config/boards/radxa-e54c.csc:14-28
Timestamp: 2025-11-02T20:49:56.719Z
Learning: In Armbian board configuration files (config/boards/*.conf, *.csc, etc.), do not use kernel_config_set, kernel_config_set_m, kernel_config_set_y, or custom_kernel_config__* functions to modify kernel configuration. Kernel configuration is associated with LINUXFAMILY/BOARDFAMILY, not individual BOARD. Board-specific kernel modifications cause inconsistency in kernel packages published to the apt repository because boards within a family share the same kernel packages. Kernel configuration changes must be made in the appropriate kernel config file (e.g., config/kernel/linux-*-*.config) or in family configuration files (config/sources/families/*.conf, *.inc) instead.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-11-09T22:30:27.163Z
Learnt from: igorpecovnik
Repo: armbian/build PR: 8720
File: lib/functions/rootfs/distro-specific.sh:38-47
Timestamp: 2025-11-09T22:30:27.163Z
Learning: In lib/functions/rootfs/distro-specific.sh, the systemd sleep.conf.d override that disables suspend/hibernation is intentionally applied system-wide to all Armbian images (desktop, CLI, and minimal), not gated to desktop-only builds, because suspend/resume is fragile on most boards.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-09-14T06:32:29.806Z
Learnt from: amazingfate
Repo: armbian/build PR: 8619
File: config/sources/families/rockchip.conf:222-230
Timestamp: 2025-09-14T06:32:29.806Z
Learning: In the Armbian build system, the write_uboot_platform() function implementations follow different patterns across Rockchip family files. The newer standard (used in rockchip64_common.inc and rk3506) includes 'status=none' parameter in dd commands, while older implementations (rk3288, rk322x) use an older pattern without this parameter. The rk3506 implementation correctly follows the current Rockchip family standard.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-07-23T07:30:52.265Z
Learnt from: EvilOlaf
Repo: armbian/build PR: 8417
File: config/boards/orangepi5pro.csc:57-58
Timestamp: 2025-07-23T07:30:52.265Z
Learning: In the Armbian build system, BOOTPATCHDIR can contain board-specific subdirectories (e.g., board_orangepi5pro) for applying patches to specific boards only. The framework automatically checks if such board-specific subdirectories exist for the board being built and applies those patches accordingly.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-09-12T19:28:38.491Z
Learnt from: Grippy98
Repo: armbian/build PR: 8622
File: config/sources/families/k3.conf:66-66
Timestamp: 2025-09-12T19:28:38.491Z
Learning: In the Armbian k3 family build system (config/sources/families/k3.conf), builds do not fail when TIBOOT3_BOOTCONFIG is unset, even though tiboot3.bin is still listed in UBOOT_TARGET_MAP. The gating mechanism in pre_config_uboot_target__build_first_stage function works as intended to conditionally build/copy tiboot3.bin only when TIBOOT3_BOOTCONFIG is defined.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-10-14T05:08:11.785Z
Learnt from: EvilOlaf
Repo: armbian/build PR: 8754
File: config/boards/bestv-r3300-l.csc:14-16
Timestamp: 2025-10-14T05:08:11.785Z
Learning: In the Armbian build system, BOOTBRANCH_BOARD is a valid framework variable used as a fallback when BOOTBRANCH is unset. The framework checks BOOTBRANCH_BOARD before applying the default bootloader branch value (see config/sources/common.conf). Board configuration files can use BOOTBRANCH_BOARD to specify the bootloader branch.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-08-03T15:21:20.148Z
Learnt from: pyavitz
Repo: armbian/build PR: 8455
File: config/sources/families/sun50iw1.conf:19-24
Timestamp: 2025-08-03T15:21:20.148Z
Learning: In the Armbian build system, when copying firmware files during family_tweaks_s(), use /lib/firmware/updates/ instead of /lib/firmware/ to avoid conflicts with the Armbian firmware package. The /lib/firmware/updates directory takes precedence in Linux firmware loading hierarchy and is the proper location for user-installed firmware files.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-12-16T12:22:20.156Z
Learnt from: tabrisnet
Repo: armbian/build PR: 9085
File: lib/functions/rootfs/rootfs-create.sh:303-306
Timestamp: 2025-12-16T12:22:20.156Z
Learning: The post_debootstrap_customize hook concept in lib/functions/rootfs/rootfs-create.sh has been tested in PR #9000. The hook placement after package installations (including desktop packages) and before cleanup operations (autoremove, qemu undeploy) is validated as appropriate for rootfs customization.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-09-07T17:39:32.272Z
Learnt from: EvilOlaf
Repo: armbian/build PR: 8586
File: config/boards/nanopi-r76s.conf:15-21
Timestamp: 2025-09-07T17:39:32.272Z
Learning: In the Armbian build system, the variables $BOARD and $SDCARD are always set by the build framework, so guard checks for these variables are unnecessary in board configuration files and hook functions.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-10-26T10:41:35.118Z
Learnt from: HackingGate
Repo: armbian/build PR: 8665
File: config/boards/photonicat2.csc:4-4
Timestamp: 2025-10-26T10:41:35.118Z
Learning: In the Armbian build system, rk3576 boards consistently use BOARDFAMILY="rk35xx" for both vendor and edge kernel targets. The rk35xx family configuration sources rockchip64_common.inc, which provides edge and current kernel branch definitions, making these branches available even though they're not defined directly in rk35xx.conf.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-12-13T11:39:08.046Z
Learnt from: pyavitz
Repo: armbian/build PR: 9058
File: patch/u-boot/legacy/u-boot-spacemit-k1/003-SpacemiT-K1X-Fixups.patch:28-67
Timestamp: 2025-12-13T11:39:08.046Z
Learning: In the Armbian build system for SpacemiT U-Boot patches (patch/u-boot/legacy/u-boot-spacemit-k1/), alignment with mainline U-Boot behavior is prioritized. For example, in boot mode handling, leaving devnum unchanged in the default case (when devtype is cleared) follows mainline conventions rather than explicitly clearing it to handle edge cases.

Applied to files:

  • config/sources/families/meson-sm1.conf
📚 Learning: 2025-12-12T23:09:56.813Z
Learnt from: tabrisnet
Repo: armbian/build PR: 9058
File: config/sources/families/spacemit.conf:39-45
Timestamp: 2025-12-12T23:09:56.813Z
Learning: In Armbian build configs for vendor kernel sources, prefer the following branch naming conventions: use 'vendor' or 'vendor-rt' for stable vendor releases, and 'vendor-edge' for bleeding-edge/pre-release vendor versions. The 'edge' naming without the 'vendor-' prefix is reserved for mainline kernel branches. Apply this pattern to family config files under config/sources/families (e.g., spacemit.conf) to ensure consistent vendor kernel sourcing naming across the repository.

Applied to files:

  • config/sources/families/meson-sm1.conf

Copy link
Member

@rpardini rpardini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, but please do board-specific stuff in the board file, not the family file.
You can use a hook called post_family_tweaks_bsp.

@igorpecovnik
Copy link
Member

Also perhaps replacing the script with something like this (needs testing):

#!/bin/bash
# Minimal disk quiesce + detach
# Dependencies: bash, sync, sleep, sysfs

set -u
exec </dev/null >/dev/null 2>/dev/null
export LANG=C LC_ALL=C

# Flush all buffers
sync

# Wait for MD arrays to become clean if mdadm exists (optional)
if [ -x /sbin/mdadm ]; then
    /sbin/mdadm --wait-clean --scan || true
elif command -v mdadm >/dev/null 2>&1; then
    mdadm --wait-clean --scan || true
fi

park_disks() {
    local dev base delete

    for dev in /sys/block/sd*; do
        [ -e "$dev" ] || continue
        base="${dev##*/}"
        delete="/sys/class/block/$base/device/delete"

        # Remove disk from kernel (forces final flush + shutdown path)
        if [ -w "$delete" ]; then
            echo 1 >"$delete" || true
        fi
    done
}

case "${1:-}" in
    reboot|kexec)
        # Skip on reboot/kexec
        ;;
    *)
        park_disks
        ;;
esac

@ean365
Copy link
Author

ean365 commented Jan 10, 2026

Thanks.

@rpardini, are you saying that it should be added to odroidhc4.csc instead? I put it in meson-sm1.conf because I'm not totally familiar with Armbian practice, thought it needed to be in a conf file, and because I already saw multiple device specific stuff in there. I can switch it into the .csc, if that is what you are recommending??

@igorpecovnik, I was trying to reuse the existing odroid.shutdown script, since it is used by the XU4 as well, and it is working. Do you see a big difference between them? If so, and you prefer the new one above, then I can put in a separate PR to update the script as you suggest.

I have been chasing/fixing this issue all night into the wee hours. I'm going to bed, but will check your responses tomorrow (well later today).

@EvilOlaf
Copy link
Member

@rpardini, are you saying that it should be added to odroidhc4.csc instead? I put it in meson-sm1.conf because I'm not totally familiar with Armbian practice, thought it needed to be in a conf file, and because I already saw multiple device specific stuff in there. I can switch it into the .csc, if that is what you are recommending??

Correct. The board config file can also contain hooks to modify aspects. Hooks in the board family file (meson-sm1.conf in this case) would affect all boards depending on this family config (like odroid n2 for example).

@igorpecovnik
Copy link
Member

Do you see a big difference between them?

less dependencies. hdparm is not present in minimal image. If it works on HC4 it will also work on XU4. Also it can be moved to extensions.

@ean365
Copy link
Author

ean365 commented Jan 10, 2026

Hmmm. I hadn't realized it, but it looks like mdadm is not present in minimal image either. Although, I've just been using JBOD for backups, so it hasn't been an issue for me. Is mdadm definitely installed when running RAID? Maybe the bsp for this feature should install both necessary commands? I'll have to test your code, because the hdparm -y command specifically parks the HDD heads nicely. I'm not sure if skipping that and just deleting from the kernel does that (or I would have assumed this wouldn't be needed in the first place if the heads were parked nicely). But I'll check it out...

It's strange that the kernel driver for the HDD doesn't have this built-in -- total miss on that.

Also, I'm not quite sure what you meant by moving to extensions, you have way more to say in how you want to structure the project, but it seems like it is part of bsp to me, where it has been for XU4.

@rpardini
Copy link
Member

rpardini commented Jan 10, 2026

Hey, it's me again. As you noted, there's two parts to this: one script laying around somewhere, and the board-related code (legacy "tweaks", which is usually family code) that activates it.

"Extensions" are a mechanism where we can define both in a single place (using heredocs, or declare -f tricks) and have boards share it. Take a look at the docs and extensions/ directory plus their usages (grep for enable_extension).

Ref "minimal images don't have xxx": then don't do xxx for minimals. With an extension you can test for BUILD_MINIMAL (or whatever) and complain/warn/break/avoid-it etc.

@igorpecovnik
Copy link
Member

Is mdadm definitely installed when running RAID?

Yes. So the script looks for its existence and only then proceed. mdadm is thus not a dependency and nor require package if you don't intend to have raid setup.

Also, I'm not quite sure what you meant by moving to extensions, you have way more to say in how you want to structure the project, but it seems like it is part of bsp to me, where it has been for XU4.

This is just an idea as parking HDD is not something that is only tied to those boards. Extension is clean(er) way for sorting out those things. As with next board that might need this kind of functionality its only one line of code:

Example:
https://github.com/armbian/build/blob/main/config/boards/luckfox-lyra-ultra-w.csc#L11
https://github.com/armbian/build/blob/main/extensions/radxa-aic8800.sh

IMO if this part is getting attention, lets do it better?

@iav
Copy link
Contributor

iav commented Jan 12, 2026

Such an improvement would benefit both official NAS — Helios4, Helios64, ODroidHC4, and other pets that use USB rotational drives. Will it work for USB drives?

@ean365
Copy link
Author

ean365 commented Jan 13, 2026

Such an improvement would benefit both official NAS — Helios4, Helios64, ODroidHC4, and other pets that use USB rotational drives. Will it work for USB drive's.

If by "USB drive's" you mean USB connected HDDs, then yes I think it should work just the same to command them to park the heads (idle-immediate), but of course this implementation would need to be tested to be certain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

02 Milestone: First quarter release Hardware Hardware related like kernel, U-Boot, ... Needs review Seeking for review size/small PR with less then 50 lines

Development

Successfully merging this pull request may close these issues.

5 participants