如何获取 FUSE 文件系统驱动程序的进程 ID?
例如,我目前在 Linux 机器上安装了两个 SSHFS 文件系统:
$ 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
我如何知道 15007 和 15031 哪个是 dir1,哪个是 dir2?理想情况下,我想自动执行该操作,即运行somecommand /home/gilles/net/dir1
并让它显示 15007(或 15031,或“不是 FUSE 安装点”,视情况而定)。
请注意,我正在寻找一个通用答案,而不是特定于 SSHFS 的答案,例如跟踪进程sshfs
连接到哪个主机和端口,以及服务器端进程打开了哪些文件 - 这甚至可能根本不可能由于连接共享。
我主要对 Linux 答案感兴趣,但适用于所有支持 FUSE 的系统的通用答案将是理想的。
为什么我想知道:跟踪它的操作,在出现问题时杀死它,等等。
答案1
我认为这是不可能的。原因如下。我采取了简单的方法,即将打开的进程的 pid 添加/dev/fuse
到 fusion 在挂载时创建的元数据中struct fuse_conn
。然后,我使用该信息pid=
在 mount 命令中显示一个字段。该补丁非常简单:
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
我启动了内核,安装了 sshfs,然后运行了 mount:
[email protected]:/tmp on /root/tmp type fuse.sshfs (rw,nosuid,nodev,relatime,pid=1549,user_id=0,group_id=0)
成功?不幸的是,没有:
root 1552 0.0 0.0 45152 332 ? Ssl 13:39 0:00 sshfs [email protected]:/tmp tmp
然后我意识到:剩余的 sshfs 进程是创建挂载的进程的子进程。它继承自fd。随着熔丝的实现,我们可以有多个继承自 fd 的进程。我们可以让 fd 在 UNIX 套接字中传递,完全脱离原始进程树。
我们可以获得“谁拥有这个 TCP 端口”信息,因为套接字具有此元数据,并且只需解析 /proc 即可告诉我们该信息。不幸的是,fuse fd 是 上的常规 fd /dev/fuse
。除非那个 fd 变得特别,否则我不知道如何实现它。
答案2
ps
我认为你可以使用和的组合lsof
来获取你想要的信息。
用户空间应用程序似乎总是将安装点参数作为参数。如果您通过 grep 遍历进程列表查找以挂载点作为参数的命令(例如ps -ef | egrep ' <mount>( |$)'
),您应该获得所有 FUSE 进程。当然,您也可能会得到其他进程,这些进程碰巧也将安装点作为参数(例如ls <mount>
)。如果您获取结果列表并运行它lsof
并查找与 开放连接的进程/dev/fuse
,您将找到与您的安装点 FUSE 相关的进程。
例如,我的系统上有一个 gvfs FUSE 进程:
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
如果我运行一个简单的 shell 命令来完成我所有的ps
工作lsof
,我会得到如下结果:
~$ 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
这似乎是做你想做的事。如果有一个 FUSE 级别的内核接口来告诉您 PID 或文件句柄与挂载点之间的映射,那就太好了,但这似乎不存在。