Linux Watchdog Flags Explained-Free Linux Device Drivers Course

PREV_LECNEXT_LEC

Linux Watchdog Flags Explained
Understanding WDIOF capability flags and the watchdog_ops callback table in a free Linux kernel development course
15+ min read
Kernel 6.x
Hands-on demo

If you are following this free Linux kernel development course, you already know that a watchdog driver is only half the story. The other half is how that driver describes itself to user space and to the watchdog core — what it can do, what it cannot do, and which callbacks it implements. That description lives in two structures: struct watchdog_info (the capability flags) and struct watchdog_ops (the callback table). Get these wrong and tools like wdctl, systemd, or a monitoring daemon will either crash, silently fail, or make assumptions your hardware can’t back up.

This lecture is part of our free embedded Linux course and continues directly from the previous watchdog lecture, where we built ep_soft_wdt, a software watchdog based on an hrtimer. Here we stay purely at the “what am I capable of” layer before wiring registration in the next lecture.

watchdog_info watchdog_ops WDIOF flags free linux kernel development course free embedded linux course WDIOC_GETSUPPORT

What You Will Learn

  • Why the watchdog framework needs a separate “capabilities” struct at all
  • What each WDIOF_* flag actually promises to user space
  • The difference between a capability flag and a boot-status bit
  • Every callback in struct watchdog_ops, mandatory vs optional
  • How to write a small user-space tool that queries a live watchdog’s capabilities over ioctl

Prerequisites

  • Comfortable reading kernel C and basic ioctl-based user space code
  • Completed the previous lecture on the watchdog subsystem and struct watchdog_device
  • A Linux VM or board with the softdog module available (most distro kernels ship it)

Why Watchdog Capability Flags Exist

Watchdog hardware varies wildly. Some chips are dumb counters that can only be armed and disarmed. Others sit on a management controller that also tracks supply-voltage faults, fan failures, and SoC temperature, and can report exactly why the last reboot happened. Rather than forcing every driver to expose a fixed feature set — or forcing user space to probe each capability individually — the watchdog framework uses a single 32-bit bitmask, reported through struct watchdog_info.options, that a driver fills in once and user space reads through the WDIOC_GETSUPPORT ioctl.

This bitmask does two jobs depending on where it’s read from:

  • In watchdog_info.options: “here is what this hardware is capable of.”
  • In watchdog_device.bootstatus: “here is what actually happened on the last reset,” using the same bit definitions where they overlap.
Capability Flags vs Boot Status
struct watchdog_info.options –> “what can this hardware detect/do” struct watchdog_device.bootstatus –> “what actually caused the last reset” Same bit, two different meanings depending on which field you read it from.

The WDIOF Flags, One By One

Below is every commonly implemented flag, explained in plain terms rather than lifted from a manual page.

FlagMeaning in your own words
WDIOF_OVERHEATHardware can tell you the last reboot happened because a temperature sensor tripped a thermal limit.
WDIOF_FANFAULTA monitored cooling fan stopped spinning and the watchdog card noticed.
WDIOF_EXTERN1 / WDIOF_EXTERN2The board has one or two dedicated external reset-request pins wired into the watchdog; a signal on either pin is a distinct reset cause.
WDIOF_POWERUNDER / WDIOF_POWEROVERThe watchdog can distinguish a brown-out (under-voltage) from an over-voltage event as the reset trigger. Both bits can be set together if the supply glitched across both thresholds.
WDIOF_CARDRESETOnly ever appears in bootstatus, never as a static capability — it means the watchdog’s own countdown expired and it reset the board itself.
WDIOF_PRETIMEOUTThe device can fire an early warning (interrupt or NMI) before the real timeout, giving software one last chance to log something or fail gracefully.
WDIOF_KEEPALIVEPINGThe driver implements the WDIOC_KEEPALIVE ioctl. Without this bit set, user space pinging the watchdog will get -EOPNOTSUPP.
WDIOF_MAGICCLOSEWriting the single character ‘V’ to /dev/watchdog right before closing the file descriptor tells the driver “I meant to stop you,” so the next close actually disarms the watchdog instead of leaving it running.
Magic Close Behaviour
Normal close of /dev/watchdog –> watchdog keeps running (safety default) write(‘V’) then close –> watchdog is disarmed on close

Tip: The magic-close behaviour is a deliberate safety net. If a process holding /dev/watchdog open crashes or is killed without writing the ‘V’ character first, the box still reboots on timeout instead of silently losing its protection.

Note: Two fields sit alongside the flags in watchdog_info: firmware_version, a plain integer identifying the card’s firmware revision, and identity, a short human-readable string such as “ep-soft-wdt” that tools display to the user.

struct watchdog_ops — The Callback Table

Where watchdog_info advertises capabilities, watchdog_ops supplies the actual function pointers the core calls into. Two are mandatory, the rest are optional and each one you implement should have a matching capability flag set (or the core’s default handling kicks in).

CallbackMandatory?What it does
startYesArms the watchdog hardware.
stopYesDisarms the watchdog hardware.
pingNoSends a keep-alive. If you leave it NULL, the core falls back to calling start again on every keep-alive, which works but is wasteful on hardware with a cheaper dedicated ping register.
statusNoReturns the live status word answered back on WDIOC_GETSTATUS.
set_timeoutNoChanges the countdown length in seconds. Requires the driver to also advertise the settable-timeout flag or user space attempts will fail with -EOPNOTSUPP.
set_pretimeoutNoConfigures the early-warning point. Pairs with WDIOF_PRETIMEOUT.
get_timeleftNoReturns seconds remaining before a forced reset — useful for monitoring dashboards.
restartNoUses the watchdog hardware itself as a system restart handler, separate from its normal timeout-triggered reset path.
ioctlNoEscape hatch for vendor-specific ioctls the generic core doesn’t already handle. Return -ENOIOCTLCMD for anything you don’t recognise so the core’s default handling still runs.

Hands-On: Querying a Live Watchdog’s Capabilities

Rather than re-showing driver-side code from the previous lecture, let’s build a small, original user-space diagnostic tool, ep_wdt_info, that opens a watchdog device node and decodes exactly what we just covered. This is genuinely useful — it’s the same technique wdctl uses internally.

// ep_wdt_info.c — decode a watchdog device's capability flags
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/watchdog.h>
#include <sys/ioctl.h>

struct ep_flag_name {
    unsigned int bit;
    const char *label;
};

static const struct ep_flag_name ep_flags[] = {
    { WDIOF_OVERHEAT,     "OVERHEAT (thermal reset detection)" },
    { WDIOF_FANFAULT,     "FANFAULT (fan monitoring)" },
    { WDIOF_EXTERN1,      "EXTERN1 (external reset input 1)" },
    { WDIOF_EXTERN2,      "EXTERN2 (external reset input 2)" },
    { WDIOF_POWERUNDER,   "POWERUNDER (brown-out detection)" },
    { WDIOF_POWEROVER,    "POWEROVER (over-voltage detection)" },
    { WDIOF_CARDRESET,    "CARDRESET (last reset caused by watchdog)" },
    { WDIOF_PRETIMEOUT,   "PRETIMEOUT (early warning supported)" },
    { WDIOF_KEEPALIVEPING,"KEEPALIVEPING (ioctl-based ping supported)" },
    { WDIOF_MAGICCLOSE,   "MAGICCLOSE ('V' disarms on close)" },
    { WDIOF_SETTIMEOUT,   "SETTIMEOUT (timeout is configurable)" },
};

int main(int argc, char *argv[])
{
    const char *node = (argc > 1) ? argv[1] : "/dev/watchdog";
    int fd = open(node, O_RDWR);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    struct watchdog_info info;
    if (ioctl(fd, WDIOC_GETSUPPORT, &info) < 0) {
        perror("WDIOC_GETSUPPORT");
        close(fd);
        return 1;
    }

    printf("Identity        : %s\n", info.identity);
    printf("Firmware version: %u\n", info.firmware_version);
    printf("Capabilities    :\n");

    for (size_t i = 0; i < sizeof(ep_flags) / sizeof(ep_flags[0]); i++) {
        if (info.options & ep_flags[i].bit)
            printf("  [x] %s\n", ep_flags[i].label);
    }

    int timeout = 0;
    if (ioctl(fd, WDIOC_GETTIMEOUT, &timeout) == 0)
        printf("Current timeout : %d seconds\n", timeout);

    close(fd);
    return 0;
}

Build and Run

$ gcc -Wall -o ep_wdt_info ep_wdt_info.c
$ sudo modprobe softdog
$ ls -l /dev/watchdog*
crw------- 1 root root  10, 130 Aug  7 10:02 /dev/watchdog
crw------- 1 root root 245,   0 Aug  7 10:02 /dev/watchdog0

$ sudo ./ep_wdt_info /dev/watchdog0

Expected output on a stock softdog-backed system:

Identity        : Software Watchdog
Firmware version: 0
Capabilities    :
  [x] MAGICCLOSE ('V' disarms on close)
  [x] KEEPALIVEPING (ioctl-based ping supported)
Current timeout : 60 seconds

Notice what’s absent: no OVERHEAT, no FANFAULT, no POWERUNDER/POWEROVER. That’s expected — softdog is a pure timer, it has no sensors behind it, so it correctly does not claim capabilities it can’t back up. Run the same tool against real server management hardware and you will typically see several more bits set.

Real-World Use Cases

  • Server BMCs report POWERUNDER/POWEROVER/OVERHEAT so a monitoring stack can tell “watchdog reset” apart from “thermal shutdown” in post-mortem logs.
  • Embedded gateways in cabinets often wire EXTERN1 to a physical tamper or door switch, using the watchdog’s external-reset input rather than a separate GPIO interrupt.
  • Safety-critical control loops lean on PRETIMEOUT to flush state to non-volatile storage in the last milliseconds before a forced reset.

Common Mistakes and Troubleshooting

  • Setting a flag without the callback: advertising WDIOF_SETTIMEOUT but leaving set_timeout NULL — user space believes it can change the timeout, then gets a confusing failure.
  • Implementing a callback without the flag: writing a set_pretimeout callback but forgetting WDIOF_PRETIMEOUT — well-behaved tools will never call it because they never see the capability.
  • Assuming MAGICCLOSE if you didn’t add it: if your driver doesn’t explicitly implement the magic-close contract, do not set this bit — user space will trust it and may leave the box armed unexpectedly.
  • Reading bootstatus once at boot only: some drivers refresh bootstatus from hardware on every status() call rather than caching it — check your specific chip’s datasheet.

Best Practices

  • Only ever set a WDIOF_* bit for a capability you have actually implemented and tested.
  • Keep identity short, unique, and grep-friendly — it ends up in logs and monitoring dashboards.
  • Prefer a dedicated ping callback over relying on the start fallback if your hardware has a lighter-weight keep-alive register — it reduces bus/register traffic on tight keep-alive intervals.
  • Return -ENOIOCTLCMD, not a generic error, from a custom ioctl callback for anything you don’t handle, so the watchdog core’s default ioctl processing still runs.

Performance and Security Considerations

The capability query path itself is cheap — it’s a single struct copy, not a hardware transaction. The real cost concerns are in what you enable: a very short pretimeout combined with a slow set_pretimeout callback can itself eat into your safety margin. On the security side, treat /dev/watchdog access as privileged (it is, by default, root-only) — a compromised unprivileged process should never be able to disarm a watchdog protecting the system.

Summary and Key Takeaways

  • watchdog_info.options advertises hardware capability; the same bits in bootstatus report what actually happened.
  • Every WDIOF_* flag you set is a promise — back it with the matching watchdog_ops callback.
  • start and stop are the only mandatory callbacks; everything else is opt-in.
  • User space can self-discover all of this cheaply through WDIOC_GETSUPPORT, as our ep_wdt_info tool demonstrated.

Conclusion

Capability flags and the ops table are the contract between your driver and everyone else on the system — user space tools, init systems, and monitoring stacks all rely on that contract being accurate rather than aspirational. With the flags and callbacks clear, the next lecture in this free Linux kernel development course moves on to actually registering a watchdog device with the kernel, choosing a restart priority, and walking through a complete, original probe function.

FAQ

What happens if I don’t set any WDIOF flags at all?

Your driver still works for basic arm/disarm through start and stop, but user-space tools will show no advertised capabilities and will avoid calling optional ioctls like set_timeout or pretimeout queries.

Can WDIOF_POWERUNDER and WDIOF_POWEROVER both be set in bootstatus at the same time?

Yes — if the supply glitched across both thresholds during the same event, both bits can legitimately be set together.

Is WDIOF_CARDRESET ever set in watchdog_info.options?

No, it’s only meaningful as a bootstatus value describing why the last reset happened, not as a static capability.

Do I need to implement the ping callback?

No, it’s optional. If you leave it NULL, the watchdog core calls your start callback instead whenever a keep-alive is needed.

Why did softdog’s ep_wdt_info output show so few flags?

Because softdog is a pure software timer with no sensors or external inputs behind it, so it only truthfully advertises MAGICCLOSE and KEEPALIVEPING support.

What does the ioctl callback in watchdog_ops actually override?

It lets your driver handle extra, non-standard ioctl commands; if defined it takes priority over the watchdog core’s default ioctl handling unless you return -ENOIOCTLCMD.

Is set_timeout required for a working watchdog driver?

No, it’s optional — many drivers ship with a fixed compiled-in timeout and never implement set_timeout at all.

Continue Learning Linux Kernel Development, Free

Explore the full free Linux kernel development course, free Linux device drivers course, and free embedded Linux course on EmbeddedPathashala.

Browse the Course Index Next: Registering a Watchdog Device

PREV_LECNEXT_LEC

Leave a Reply

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