Como garantir que todos os processos sejam eliminados antes de desmontar um sistema de arquivos?

Como garantir que todos os processos sejam eliminados antes de desmontar um sistema de arquivos?

Estou tentando desmontar um sistema de arquivos ocupado no qual leituras e gravações contínuas de E/S estão acontecendo por um programa multithread devido à falha do comando umount.

root@ubuntu:~ # umount /mount/v1
umount: /mount/v1: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))

Agora, tentei matar todos os processos usando

/sbin/fuser -m /mount/v1 -k

Mas conformeComando do fusor

fuser -k ou -K pode não ser capaz de detectar e eliminar novos processos criados imediatamente após o início da execução do programa.

que é o que acontece no meu caso, pois alguns dos threads podem ter emitido uma solicitação de IO ao mesmo tempo. Quando desmonto novamente o sistema de arquivos, ele novamente diz que está ocupado e isso se torna um loop.

Minha pergunta é: como posso garantir que nenhum processo novo seja capaz de ler/gravar no sistema de arquivos uma vez?

/sbin/fuser -m /mount/v1 -k

O comando é emitido para que o sistema de arquivos possa ser desmontado normalmente.

Responder1

Aqui estão dois métodos. Se você não confia em seus aplicativos, pode ir diretamente para o segundo método.

1.umount --lazy

Se esses processos interferentes não chdir()entrarem no ponto de montagem (use caminhos absolutos, por exemplo) e você sabe que eles acabarão desistindo, então no Linux você pode usar umount --lazy: o kernel irá desmapear o sistema de arquivos da arborescência dos diretórios, tornando-o inacessível para novos acessa e irá desmontá-lo automaticamente quando a última referência desaparecer. A referência pode ser um fd aberto, um cwd, um ponto de montagem interno (este último seria ruim)...

Mas isso não afetará os processos/threads que mantêm uma referência "dentro", por exemplo, descritores de arquivos ainda abertos ou tendocwddentro. Então isso seria ainda mais difícil, pois agora o sistema de arquivos não está mais acessível e fica ainda mais difícil rastrear processos/threads ofensivos (por exemplo: fuser -mnão os encontrarei mais). Então, de alguma forma, você precisa que os processos se comportem corretamente para esse método.

2.grupo congelador

Solução alternativa que deve funcionar paramau comportamentoprocessos: agrupe todos esses processos (e threads) no mesmo cgroup do freezer. Congele todos eles, evitando que adicionem uso de recursos ao ponto de montagem (bifurcando/clonando/abrindo novos fds). Mesmo que você perca alguns no primeiro loop, você acabará capturando todos os novos nas iterações subsequentes. Como eles agora estão congelados, nenhuma atividade nova acontecerá: agora você pode matar todos eles. Para cgroups v1, já inicializado pelo SO (ex.: porsistemaoucgmanager, caso contrário você terá que descobrir comomonte o subsistema cgroup do freezer), algo assim deve funcionar. Observe que, aparentemente, escrever para cgroup.procsdeve incluir todos os threads que deveriam aparecer, tasksmas houve relatos de comportamento não confiável, então, apenas no caso de eu também iterar sobre os threads, mesmo que isso provavelmente não seja necessário (ou seja: tasksprovavelmente já está preenchido corretamente com threads, então o for tloop é redundante).

mkdir -p /sys/fs/cgroup/freezer/prepareumount

echo FROZEN > /sys/fs/cgroup/freezer/prepareumount/freezer.state

for i in $(seq 1 10); do
    for p in $(fuser -m /mount/v1 2>/dev/null); do
        echo $p > /sys/fs/cgroup/freezer/prepareumount/cgroup.procs
        for t in $(ps -L -o tid= -p $p); do
            echo $t > /sys/fs/cgroup/freezer/prepareumount/tasks
        done
    done
done

#give time to an overloaded kernel to freeze everything (FREEZING->FROZEN)
while ! cat /sys/fs/cgroup/freezer/prepareumount/freezer.state | grep -q FROZEN; do
    sleep 0.1
done

# kills, delayed
for i in $(cat /sys/fs/cgroup/freezer/prepareumount/cgroup.procs); do
    kill -KILL $i
done

# actual kills happen now, at once
echo THAWED > /sys/fs/cgroup/freezer/prepareumount/freezer.state

sleep 1
umount /mount/v1

Isso teria que ser adaptado se estiver usando cgroups v2.

informação relacionada