Encontre o processo que implementa um sistema de arquivos FUSE

5

Como posso obter o ID do processo do driver de um sistema de arquivos FUSE?

Por exemplo, atualmente tenho dois sistemas de arquivos SSHFS montados em uma máquina Linux:

$ grep sshfs /proc/mounts
host:dir1 /home/gilles/net/dir1 fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0
host:dir2 /home/gilles/net/dir2 fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0
$ pidof sshfs
15031 15007

Como posso saber qual de 15007 e 15031 é dir1 e qual é dir2? Idealmente, gostaria de automatizar isso, ou seja, executar somecommand /home/gilles/net/dir1 e exibir 15007 (ou 15031, ou “não um ponto de montagem FUSE”, conforme apropriado).

Observe que estou procurando uma resposta genérica, não uma resposta específica do SSHFS, como o rastreamento de qual host e porta os processos sshfs estão conectados e quais arquivos o processo do lado do servidor está aberto - o que pode nem ser possível devido ao compartilhamento de conexão.

Estou principalmente interessado em uma resposta do Linux, mas uma resposta genérica que funcione em todos os sistemas que suportam o FUSE seria ideal.

Por que eu quero saber: para rastrear sua operação, para matá-lo em caso de problemas, etc.

    
por Gilles 22.03.2015 / 17:46

2 respostas

1

Eu não acho que seja possível. Aqui está o porquê. Tomei a abordagem ingênua, que era adicionar o pid do processo que abre /dev/fuse aos metadados que o fusível cria no momento da montagem, struct fuse_conn . Em seguida, usei essa informação para exibir um campo pid= no comando mount. O patch é muito simples:

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 7354dc1..32b05ca 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -402,6 +402,9 @@ struct fuse_conn {
        /** The group id for this mount */
        kgid_t group_id;

+       /** The pid mounting process */
+       pid_t pid;
+
        /** The fuse mount flags for this mount */
        unsigned flags;

diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e8799c1..23a27be 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -554,6 +554,7 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
        struct super_block *sb = root->d_sb;
        struct fuse_conn *fc = get_fuse_conn_super(sb);

+       seq_printf(m, ",pid=%u", fc->pid);
        seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id));
        seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id));
        if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
@@ -1042,6 +1043,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)

        fc->release = fuse_free_conn;
        fc->flags = d.flags;
+       fc->pid = current->pid;
        fc->user_id = d.user_id;
        fc->group_id = d.group_id;
        fc->max_read = max_t(unsigned, 4096, d.max_read);
def@fractal [6:37] ~/p/linux -- master

Eu inicializei o kernel, montei sshfs, montei:

[email protected]:/tmp on /root/tmp type fuse.sshfs (rw,nosuid,nodev,relatime,pid=1549,user_id=0,group_id=0)

Sucesso? Infelizmente não:

root      1552  0.0  0.0  45152   332 ?        Ssl  13:39   0:00 sshfs [email protected]:/tmp tmp                                                                

Então percebi: o processo sshfs restante é filho daquele que criou a montagem. Herdou do fd. Como o fusível é implementado, poderíamos ter uma infinidade de processos herdados do fd. Poderíamos ter o fd sendo passado em soquetes UNIX, completamente fora da árvore de processos original.

Podemos obter as informações 'quem possui esta porta TCP', porque os sockets têm esses metadados e simplesmente parsing / proc nos informa essa informação. Infelizmente, o fusível fd é um fd normal em /dev/fuse . A menos que o fd de alguma forma se torne especial, não vejo como isso pode ser implementado.

    
por 29.04.2015 / 15:47
1

Acho que você pode usar uma combinação de ps e lsof para obter as informações desejadas.

O aplicativo userspace parece sempre ter o argumento do ponto de montagem como um argumento. Se você percorrer sua lista de processos procurando comandos com o ponto de montagem como um argumento (por exemplo, ps -ef | egrep ' <mount>( |$)' ), deverá obter todos os processos do FUSE. Naturalmente, você também pode obter outros processos que também possuem o ponto de montagem como um argumento (por exemplo, ls <mount> ). Se você pegar a lista resultante e executá-la em lsof e procurar processos com uma conexão aberta para /dev/fuse , você encontrará processos relacionados ao FUSE para o seu ponto de montagem.

Então, por exemplo, eu tenho um processo FUSE gvfs no meu sistema:

gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)

Se eu executar um comando shell simples que faça todos os meus ps e lsof funcionarem para mim, obtenho algo assim:

~$ for pid in \
     $(ps -ef | egrep ' /run/user/1000/gvfs( |$)' | awk '{print $2}')
   do 
     ps -f -p $(lsof -p "$pid" | fgrep /dev/fuse | awk '{print $2}')
   done
UID        PID  PPID  C STIME TTY          TIME CMD
username  2241  1997  0 Apr25 ?        00:00:00 /usr/lib/gvfs/gvfsd-fuse /run/user/1000/gvfs -f -o big_writes

Isso parece fazer o que você quer. Seria bom se houvesse uma interface de kernel no nível do FUSE para informar os mapeamentos entre o PID ou o filehandle e o ponto de montagem, mas isso não parece existir.

    
por 29.04.2015 / 05:37

Tags