Simular um processo não faturável no estado D

10

Para cenários de teste de catástrofe no ambiente de servidor, procuramos uma maneira fácil de manter um processo preso no estado D (ininterruptible sleep).

Quaisquer maneiras fáceis? Um exemplo de código de exemplo C seria um plus:)

Editar - a primeira resposta é semi-correta, pois o processo é mostrado no estado D, mas ainda recebe sinais e pode ser eliminado

    
por er453r 06.06.2014 / 17:43

3 respostas

2

Eu tive o mesmo problema e resolvi isso criando um módulo do kernel que fica preso no estado D.

Como não tenho experiência em módulos, peguei o código de este turorial com algumas modificações encontradas < href="http://www.makelinux.net/ldd3/chp-6-sect-2"> someplace esle .

O resultado é um dispositivo em / dev / memory que fica preso na leitura, mas pode ser ativado escrevendo (ele precisa de duas gravações, não sei por que, mas eu não me importo).

Para usá-lo apenas:

# make
# make mknod
# make install
# cat /dev/memory   # this gets blocked

Para desbloquear a partir de outro terminal:

# echo -n a > /dev/memory
# echo -n a > /dev/memory

Makefile:

obj-m += memory.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

install:
    sudo insmod memory.ko

uninstall:
    sudo rmmod memory

mknod:
    sudo mknod /dev/memory c 60 0
    sudo chmod 666 /dev/memory

Código para memory.c:

/* Necessary includes for device drivers */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/sched.h>

MODULE_LICENSE("Dual BSD/GPL");

/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);

/* Structure that declares the usual file */
/* access functions */
ssize_t memory_write( struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
struct file_operations memory_fops = {
    .read = memory_read,
    .write = memory_write,
    .open = memory_open,
    .release = memory_release
};

/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);

/* Global variables of the driver */
/* Major number */
int memory_major = 60;
/* Buffer to store data */
char *memory_buffer;

int memory_init(void) {
    int result;

    /* Registering device */
    result = register_chrdev(memory_major, "memory", &memory_fops);
    if (result < 0) {
        printk(
                "<1>memory: cannot obtain major number %d\n", memory_major);
        return result;
    }

    /* Allocating memory for the buffer */
    memory_buffer = kmalloc(1, GFP_KERNEL); 
    if (!memory_buffer) { 
        result = -ENOMEM;
        goto fail; 
    } 
    memset(memory_buffer, 0, 1);

    printk("<1>Inserting memory module\n"); 
    return 0;

fail: 
    memory_exit(); 
    return result;
}

void memory_exit(void) {
    /* Freeing the major number */
    unregister_chrdev(memory_major, "memory");

    /* Freeing buffer memory */
    if (memory_buffer) {
        kfree(memory_buffer);
    }

    printk("<1>Removing memory module\n");

}

int memory_open(struct inode *inode, struct file *filp) {

    /* Success */
    return 0;
}

int memory_release(struct inode *inode, struct file *filp) {

    /* Success */
    return 0;
}
static DECLARE_WAIT_QUEUE_HEAD(wq);
static volatile int flag = 0;

ssize_t memory_read(struct file *filp, char *buf, 
        size_t count, loff_t *f_pos) { 

    printk("<1>going to sleep\n");
    flag = 0;
    //wait_event_interruptible(wq, flag != 0);
    wait_event(wq, flag != 0);

    printk("<1>Reading from memory module\n");
    /* Transfering data to user space */ 
    copy_to_user(buf,memory_buffer,1);

    /* Changing reading position as best suits */ 
    if (*f_pos == 0) { 
        *f_pos+=1; 
        return 1; 
    } else { 
        return 0; 
    }
}

ssize_t memory_write( struct file *filp, char *buf,
        size_t count, loff_t *f_pos) {

    char *tmp;

    printk("<1>wake someone up\n");
    flag = 1;
    //wake_up_interruptible(&wq);
    wake_up(&wq);

    printk("<1>Writting to memory module\n");
    tmp=buf+count-1;
    copy_from_user(memory_buffer,tmp,1);
    return 1;
}
    
por 25.08.2016 / 10:48
9

De link

Um processo é colocado em um sono ininterrupto (STAT D) quando ele precisa esperar por algo (normalmente I / O) e não deve estar manipulando sinais enquanto espera . Isso significa que você não pode kill , porque tudo o que mata é enviar sinais. Isso pode acontecer no mundo real se você desconectar seu servidor NFS enquanto outras máquinas tiverem conexões de rede abertas para ele.

Podemos criar nossos próprios processos ininterruptos de duração limitada aproveitando a chamada do sistema vfork . vfork é como fork , exceto que o espaço de endereço não é copiado do pai para o filho, em antecipação de um exec que simplesmente jogaria fora os dados copiados. Convenientemente para nós, quando você vfork o pai espera ininterruptamente (por meio de wait_on_completion ) na exec ou exit :

da criança
jesstess@aja:~$ cat uninterruptible.c 
int main() {
    vfork();
    sleep(60);
    return 0;
}
jesstess@aja:~$ gcc -o uninterruptible uninterruptible.c
jesstess@aja:~$ echo $$
13291
jesstess@aja:~$ ./uninterruptible
and in another shell:

jesstess@aja:~$ ps -o ppid,pid,stat,cmd $(pgrep -f uninterruptible)

13291  1972 D+   ./uninterruptible
 1972  1973 S+   ./uninterruptible

Nós vemos o filho ( PID 1973, PPID 1972 ) em um sono interrompível e o pai ( PID 1972, PPID 13291 - a concha) em um sono ininterrupto enquanto espera por 60 segundos na criança.

Uma coisa interessante (maliciosa?) sobre este script é que os processos em um sono ininterrupto contribuem para a média de carga de uma máquina. Assim, você poderia executar este script 100 vezes para dar temporariamente a uma máquina uma média de carga elevada por 100, conforme relatado por uptime .

    
por 06.06.2014 / 19:28
2

Basicamente, você não pode. Leia este artigo, intitulado: TASK_KILLABLE: Novo estado do processo no Linux .

trecho

Linux® kernel 2.6.25 introduced a new process state for putting processes to sleep called TASK_KILLABLE, which offers an alternative to the efficient but potentially unkillable TASK_UNINTERRUPTIBLE and the easy-to-awaken but safer TASK_INTERRUPTIBLE.

Este SO Q & A intitulado: O que é um processo ininterrupto? também explica isso.

Eu descobri isso neste livro muito interessante intitulado: A interface de programação Linux: Um manual de programação do sistema Linux e UNIX .

    
por 22.10.2014 / 01:26