From: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
To: yukuai@fygo.io, chengzhihao1@huawei.com,
blazej.kucman@graidtech.com, mtkaczyk@kernel.org,
ncroxon@redhat.com, xni@redhat.com, song@kernel.org
Cc: linux-raid@vger.kernel.org,
Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Subject: [PATCH 1/2] mdadm: add md_ioctl() for the md control device
Date: Mon, 28 Sep 2026 21:18:48 +0000 [thread overview]
Message-ID: <20260928211849.3602414-2-abd.masalkhi@gmail.com> (raw)
In-Reply-To: <20260928211849.3602414-1-abd.masalkhi@gmail.com>
Linux adds /dev/md-control, a misc character device for md management
ioctls. Each request names its array in the payload, so the caller
does not need to open the md block device. The kernel can then refuse
to stop an array that anyone still has open, which fixes a race
between STOP_ARRAY and writes from tasks that share the same file
descriptor table.
Update md_u.h with the new definitions from the kernel's
include/uapi/linux/raid/md_u.h.
Add md_ioctl(), which sends a management command to
/dev/md-control and identifies the array by its name.
The STOP_ARRAY_RO command is now handled via the MD_STOP_ARRAY
command with the MD_RO_FLAG set.
Suggested-by: Yu Kuai <yukuai@fygo.io>
Suggested-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
---
md_u.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mdadm.h | 8 ++++
util.c | 23 +++++++++++
3 files changed, 148 insertions(+)
diff --git a/md_u.h b/md_u.h
index b30893c0..f816ab87 100644
--- a/md_u.h
+++ b/md_u.h
@@ -15,6 +15,10 @@
#ifndef _MD_U_H
#define _MD_U_H
+#define MD_NAME_LEN 32
+#define MD_UUID_LEN 16
+#define MD_CTL_NODE "md-control"
+
/* ioctls */
/* status */
@@ -38,6 +42,29 @@
#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34)
#define CLUSTERED_DISK_NACK _IO (MD_MAJOR, 0x35)
+/* ioctl commands for the MD misc control driver */
+/* status */
+#define MD_RAID_VERSION _IOR(MD_MAJOR, 0x40, struct mdu_version64)
+#define MD_GET_ARRAY_INFO _IOWR(MD_MAJOR, 0x41, struct mdu_ioctl)
+#define MD_GET_DISK_INFO _IOWR(MD_MAJOR, 0x42, struct mdu_ioctl)
+#define MD_RAID_AUTORUN _IOWR(MD_MAJOR, 0x43, struct mdu_ioctl)
+#define MD_GET_BITMAP_FILE _IOWR(MD_MAJOR, 0x44, struct mdu_ioctl)
+
+/* configuration */
+#define MD_ADD_NEW_DISK _IOWR(MD_MAJOR, 0x50, struct mdu_ioctl)
+#define MD_HOT_ADD_DISK _IOWR(MD_MAJOR, 0x51, struct mdu_ioctl)
+#define MD_HOT_REMOVE_DISK _IOWR(MD_MAJOR, 0x52, struct mdu_ioctl)
+#define MD_SET_ARRAY_INFO _IOWR(MD_MAJOR, 0x53, struct mdu_ioctl)
+#define MD_SET_DISK_INFO _IOWR(MD_MAJOR, 0x54, struct mdu_ioctl)
+#define MD_SET_DISK_FAULTY _IOWR(MD_MAJOR, 0x55, struct mdu_ioctl)
+#define MD_SET_BITMAP_FILE _IOWR(MD_MAJOR, 0x56, struct mdu_ioctl)
+
+/* usage */
+#define MD_RUN_ARRAY _IOWR(MD_MAJOR, 0x60, struct mdu_ioctl)
+#define MD_STOP_ARRAY _IOWR(MD_MAJOR, 0x61, struct mdu_ioctl)
+#define MD_RESTART_ARRAY_RW _IOWR(MD_MAJOR, 0x62, struct mdu_ioctl)
+#define MD_CLUSTERED_DISK_NACK _IOWR(MD_MAJOR, 0x63, struct mdu_ioctl)
+
typedef struct mdu_version_s {
int major;
int minor;
@@ -112,4 +139,94 @@ typedef struct mdu_param_s
int max_fault; /* unused for now */
} mdu_param_t;
+/* structures for the MD misc control driver */
+struct mdu_version64 {
+ __u32 major;
+ __u32 minor;
+ __u32 patchlevel;
+ __u32 padding;
+};
+
+struct mdu_array_info64 {
+ /*
+ * Generic constant information
+ */
+ __u32 major_version;
+ __u32 minor_version;
+ __u32 patch_version;
+ __s32 level;
+
+ __u64 ctime;
+ __u64 size;
+
+ __u32 nr_disks;
+ __u32 raid_disks;
+ __u32 md_minor;
+ __u32 not_persistent;
+
+ /*
+ * Generic state information
+ */
+ __u64 utime; /* 0 Superblock update time */
+
+ __u32 state; /* 1 State bits (clean, ...) */
+ __u32 active_disks; /* 2 Number of currently active disks */
+ __u32 working_disks; /* 3 Number of working disks */
+ __u32 failed_disks; /* 4 Number of failed disks */
+ __u32 spare_disks; /* 5 Number of spare disks */
+ __u32 journal_disks; /* 6 Number of disks used for journaling */
+
+ /*
+ * Personality information
+ */
+ __s32 layout; /* 0 the array's physical layout */
+ __u32 chunk_size; /* 1 chunk size in bytes */
+
+};
+
+struct mdu_disk_info64 {
+ /*
+ * configuration/status of one particular disk
+ */
+ __u32 state;
+ __u32 major;
+ __u32 minor;
+ __u32 padding;
+
+ __s32 number;
+ __s32 raid_disk;
+};
+
+struct mdu_bitmap_file64 {
+ char pathname[4096];
+};
+
+struct mdu_param64 {
+ __s32 personality; /* 1,2,3,4 */
+ __u32 max_fault; /* unused for now */
+ __u32 chunk_size; /* in bytes */
+ __u32 padding;
+};
+
+struct mdu_ioctl {
+ char name[MD_NAME_LEN];
+ char uuid[MD_UUID_LEN];
+ __u64 dev;
+ __u32 flags;
+ __u32 padding;
+ union {
+ __u64 array;
+ __u64 disk;
+ __u64 param;
+ __u64 bitmap_file;
+ __u64 arg;
+ };
+};
+
+/*
+ * If set, MD_STOP_ARRAY will switch the array to read-only mode instead
+ * of fully stopping it.
+ */
+#define MD_RO_FLAG (1u << 0)
+
#endif
diff --git a/mdadm.h b/mdadm.h
index deac7a56..fb85ed6d 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1736,6 +1736,14 @@ extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt);
extern bool is_directory(const char *path);
extern bool is_file(const char *path);
extern int s_gethostname(char *buf, int buf_len);
+extern int md_do_ioctl(int fd, unsigned long cmd, __u64 arg, __u32 flags);
+
+#define md_ioctl0(fd, cmd) md_do_ioctl(fd, cmd, 0, 0)
+#define md_ioctl1(fd, cmd, arg) md_do_ioctl(fd, cmd, (uintptr_t)arg, 0)
+#define md_ioctl2(fd, cmd, arg, flag) md_do_ioctl(fd, cmd, (uintptr_t)arg, flag)
+#define __md_ioctl(a, b, c, d, e, ...) md_ioctl ## e
+#define md_ioctl(fd, cmd, ...) \
+ __md_ioctl(fd, cmd, ##__VA_ARGS__, 2, 1, 0)(fd, cmd, ##__VA_ARGS__)
#define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1))
#define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base))
diff --git a/util.c b/util.c
index 3bd4829a..5f0f401b 100644
--- a/util.c
+++ b/util.c
@@ -229,6 +229,29 @@ out:
return ret;
}
+int md_do_ioctl(int fd, unsigned long cmd, __u64 arg, __u32 flags)
+{
+ static int fd_ctl = -2;
+ struct mdu_ioctl mdctl = {.arg = arg, .flags = flags};
+ char *name;
+
+ if (fd_ctl == -2)
+ fd_ctl = open("/dev/" MD_CTL_NODE, O_RDWR | O_CLOEXEC);
+
+ if (fd_ctl == -1)
+ return -1;
+
+ if (cmd == MD_RAID_VERSION)
+ return ioctl(fd_ctl, cmd, arg);
+
+ name = fd2devnm(fd);
+ if (!name)
+ return -1;
+
+ strncpy(mdctl.name, name, MD_NAME_LEN);
+ return ioctl(fd_ctl, cmd, &mdctl);
+}
+
int md_array_valid(int fd)
{
struct mdinfo *sra;
--
2.43.0
next prev parent reply other threads:[~2026-09-28 21:24 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 21:18 [PATCH 0/2] mdadm: switch management ioctls to /dev/md-control Abd-Alrhman Masalkhi
2026-09-28 21:18 ` Abd-Alrhman Masalkhi [this message]
2026-09-28 21:18 ` [PATCH 2/2] mdadm: switch management ioctls to md_ioctl() Abd-Alrhman Masalkhi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260928211849.3602414-2-abd.masalkhi@gmail.com \
--to=abd.masalkhi@gmail.com \
--cc=blazej.kucman@graidtech.com \
--cc=chengzhihao1@huawei.com \
--cc=linux-raid@vger.kernel.org \
--cc=mtkaczyk@kernel.org \
--cc=ncroxon@redhat.com \
--cc=song@kernel.org \
--cc=xni@redhat.com \
--cc=yukuai@fygo.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox