linux - tutorial - ¿Hay una buena manera de detectar un montaje NFS obsoleto
ubuntu sh variable (7)
Además de las respuestas anteriores, que se cuelgan en algunas circunstancias, este fragmento comprueba todos los montajes adecuados, mata con la señal KILL y también se prueba con CIFS:
grep -v tracefs /proc/mounts | cut -d'' '' -f2 | /
while read m; do /
timeout --signal=KILL 1 ls -d $m > /dev/null || echo "$m"; /
done
Tengo un procedimiento que quiero iniciar solo si varias pruebas se completan correctamente.
Una de las pruebas que necesito es que todos mis montajes NFS están vivos y bien.
¿Puedo hacerlo mejor que el enfoque de fuerza bruta:
mount | sed -n "s/^.* on /(.*/) type nfs .*$//1/p" |
while read mount_point ; do
timeout 10 ls $mount_point >& /dev/null || echo "stale $mount_point" ;
done
Aquí el timeout
es una utilidad que ejecutará el comando en segundo plano y lo eliminará después de un tiempo determinado, si no se SIGCHLD
un SIGCHLD
antes del límite de tiempo, lo que devuelve éxito / falla de la manera obvia.
En inglés: analice la salida del mount
, verifique (limitado por un tiempo de espera) cada punto de montaje NFS. Opcionalmente (no en el código anterior) rompiendo en el primer montaje obsoleto.
Escribí https://github.com/acdha/mountstatus que utiliza un enfoque similar al que UndeadKernel mencionó, que he encontrado que es el más robusto: es un demonio que analiza periódicamente todos los sistemas de archivos montados mediante el procesamiento de un proceso secundario que intenta listar el directorio de nivel superior y SIGKILL
si no responde en un cierto tiempo de espera, con tanto los éxitos como los fallos registrados en syslog. Eso evita problemas con ciertas implementaciones de clientes (por ejemplo, Linux más antiguo) que nunca activan tiempos de espera para ciertas clases de errores, servidores NFS que responden parcialmente pero que no responden a llamadas reales como listdir
, etc.
No los publico, pero el Makefile incluido usa fpm
para construir paquetes rpm y deb con un script Upstart.
Escribir un programa en C que compruebe si hay ESTALE es una buena opción si no le importa esperar a que finalice el comando debido al sistema de archivos obsoletos. Si desea implementar una opción de "tiempo de espera", la mejor manera que he encontrado para implementarla (en un programa C) es crear un proceso secundario que intente abrir el archivo. A continuación, verifica si el proceso hijo ha terminado de leer correctamente un archivo en el sistema de archivos dentro de un período de tiempo asignado.
Aquí hay una pequeña prueba del programa C para hacer esto:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
void readFile();
void waitForChild(int pid);
int main(int argc, char *argv[])
{
int pid;
pid = fork();
if(pid == 0) {
// Child process.
readFile();
}
else if(pid > 0) {
// Parent process.
waitForChild(pid);
}
else {
// Error
perror("Fork");
exit(1);
}
return 0;
}
void waitForChild(int child_pid)
{
int timeout = 2; // 2 seconds timeout.
int status;
int pid;
while(timeout != 0) {
pid = waitpid(child_pid, &status, WNOHANG);
if(pid == 0) {
// Still waiting for a child.
sleep(1);
timeout--;
}
else if(pid == -1) {
// Error
perror("waitpid()");
exit(1);
}
else {
// The child exited.
if(WIFEXITED(status)) {
// Child was able to call exit().
if(WEXITSTATUS(status) == 0) {
printf("File read successfully!/n");
return;
}
}
printf("File NOT read successfully./n");
return;
}
}
// The child did not finish and the timeout was hit.
kill(child_pid, 9);
printf("Timeout reading the file!/n");
}
void readFile()
{
int fd;
fd = open("/path/to/a/file", O_RDWR);
if(fd == -1) {
// Error
perror("open()");
exit(1);
}
else {
close(fd);
exit(0);
}
}
Me tomó algo de tiempo, pero aquí está lo que encontré que funciona en Python:
import signal, os, subprocess
class Alarm(Exception):
pass
def alarm_handler(signum, frame):
raise Alarm
pathToNFSMount = ''/mnt/server1/'' # or you can implement some function
# to find all the mounts...
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(3) # 3 seconds
try:
proc = subprocess.call(''stat ''+pathToNFSMount, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdoutdata, stderrdata = proc.communicate()
signal.alarm(0) # reset the alarm
except Alarm:
print "Oops, taking too long!"
Observaciones:
- Crédito a la respuesta aquí .
También podrías usar un esquema alternativo:
os.fork()
yos.stat()
comprueba si la horquilla ha terminado, si se ha agotado el tiempo, puedes matarla. Deberá trabajar con time.time()
y así sucesivamente.
Otra forma, utilizando shell script. Funciona bien para mí:
#!/bin/bash
# Purpose:
# Detect Stale File handle and remove it
# Script created: July 29, 2015 by Birgit Ducarroz
# Last modification: --
#
# Detect Stale file handle and write output into a variable and then into a file
mounts=`df 2>&1 | grep ''Stale file handle'' |awk ''{print ""$2"" }'' > NFS_stales.txt`
# Remove : ‘ and ’ characters from the output
sed -r -i ''s/://'' NFS_stales.txt && sed -r -i ''s/‘//'' NFS_stales.txt && sed -r -i ''s/’//'' NFS_stales.txt
# Not used: replace space by a new line
# stales=`cat NFS_stales.txt && sed -r -i '':a;N;$!ba;s/ //n /g'' NFS_stales.txt`
# read NFS_stales.txt output file line by line then unmount stale by stale.
# IFS='''' (or IFS=) prevents leading/trailing whitespace from being trimmed.
# -r prevents backslash escapes from being interpreted.
# || [[ -n $line ]] prevents the last line from being ignored if it doesn''t end with a /n (since read returns a non-zero exit code when it encounters EOF).
while IFS='''' read -r line || [[ -n "$line" ]]; do
echo "Unmounting due to NFS Stale file handle: $line"
umount -fl $line
done < "NFS_stales.txt"
#EOF
Podrías escribir un programa en C y verificar si hay ESTALE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iso646.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
struct stat st;
int ret;
ret = stat("/mnt/some_stale", &st);
if(ret == -1 and errno == ESTALE){
printf("/mnt/some_stale is stale/n");
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}
Un colega mío se topó con tu guión. Esto no evita un enfoque de "fuerza bruta", pero si puedo en Bash:
while read _ _ mount _; do
read -t1 < <(stat -t "$mount") || echo "$mount timeout";
done < <(mount -t nfs)
mount
puede listar montajes NFS directamente. read -t
(un shell incorporado) puede agotar un comando. stat -t
(salida tersa) todavía cuelga como un ls
*. ls
produce resultados innecesarios, arriesga falsos positivos en listas de directorios enormes / lentas y requiere permisos para acceder, lo que también generaría un falso positivo si no los tiene.
while read _ _ mount _; do
read -t1 < <(stat -t "$mount") || lsof -b 2>/dev/null|grep "$mount";
done < <(mount -t nfs)
Lo estamos utilizando con lsof -b
(sin bloqueo, por lo que no se bloquea) para determinar la fuente de los bloqueos.
Gracias por el puntero!
-
test -d
(un shell builtin) también funcionaría en lugar destat
(un estándar externo), peroread -t
devuelve el éxito solo si no se agota el tiempo de espera y lee una línea de entrada. Comotest -d
no usa stdout, sería necesario realizar una comprobación de nivel de error(( $? > 128 ))
, no vale la pena el impacto de legibilidad, OMI.