背景:我正在研究在不受信任的机器上加密存储的方法。我当前的设置使用 sshfs 访问 LUKS 加密的映像偏僻的机器,已解密本地并安装为 ext3。 (如果我仅使用 sshfs,则访问远程计算机的人可以看到我的数据。)这是我的示例设置:
# On the local machine:
sshfs remote:/home/crypt /home/crypt
cryptsetup luksOpen /home/crypt/container.img container
mount /dev/mapper/container /home/crypt-open
# Place cleartext files in /home/crypt-open,
# then reverse the above steps to unmount.
我想让它能够抵御网络故障。为此,我想了解此设置会发生什么缓存/缓冲。考虑这两个命令:
dd if=/dev/random of=/home/crypt-open/test.dat bs=1000000 count=100
dd if=/dev/random of=/home/crypt-open/test.dat bs=1000000 count=100 conv=fsync
第一个命令返回的速度非常快,从网络流量可以看出命令返回后数据仍在传输。第二个命令似乎要等到数据传输完成。
具体问题:fsync()
在此设置下有何保证?返回时fsync()
,这些层的数据保证同步到什么程度?我该怎么做才能保证它一直同步到远程计算机的硬盘驱动器?
--- /home/crypt-open on the local machine
|
| (ext3 fs)
|
--- /dev/mapper/container on the local machine
|
| (LUKS)
|
--- /home/crypt/container.img on the local machine
|
| (sshfs)
|
--- /home/crypt/container.img on the remote machine
|
| (ext3 fs)
|
--- hard drive on the remote machine
答案1
我假设这里最薄弱的环节是 SSHFS 代码——其余的东西都在内核中并且被大量使用,所以它可能没问题。我以前从未真正查看过任何 FUSE 代码,因此可能还有其他事情我错过了,但根据SSHFS源代码,SSHFS 的实现fsync()
并没有做很多事情,它只是调用flush()
IO 流。
static int sshfs_fsync(const char *path, int isdatasync,
struct fuse_file_info *fi)
{
(void) isdatasync;
return sshfs_flush(path, fi);
}
在 处sshfs.c:2551
,我们可以看到该sshfs_flush()
函数不会向强制执行 fsync 的远程计算机发送任何类型的同步命令。我相信该sshfs.sync_write
标志的意思是“在从写入返回之前等待命令发送到服务器”,而不是“每次写入时在服务器上进行 fsync”,因为第二个含义非常奇怪。因此,您的 fsync 测量速度较慢,因为它的瓶颈是网络速度,而不是远程磁盘速度。
static int sshfs_flush(const char *path, struct fuse_file_info *fi)
{
int err;
struct sshfs_file *sf = get_sshfs_file(fi);
struct list_head write_reqs;
struct list_head *curr_list;
if (!sshfs_file_is_conn(sf))
return -EIO;
if (sshfs.sync_write)
return 0;
(void) path;
pthread_mutex_lock(&sshfs.lock);
if (!list_empty(&sf->write_reqs)) {
curr_list = sf->write_reqs.prev;
list_del(&sf->write_reqs);
list_init(&sf->write_reqs);
list_add(&write_reqs, curr_list);
while (!list_empty(&write_reqs))
pthread_cond_wait(&sf->write_finished, &sshfs.lock);
}
err = sf->write_error;
sf->write_error = 0;
pthread_mutex_unlock(&sshfs.lock);
return err;
}
请注意,远程 SFTP 实现实际上可能会在写入时进行 fsync,但我认为实际上并非如此。据一位老SFTP标准草案(这是我能找到的最好的)有一种方法可以指定这种行为:
7.9. attrib-bits and attrib-bits-valid
...
SSH_FILEXFER_ATTR_FLAGS_SYNC
When the file is modified, the changes are written synchronously
to the disk.
这意味着这不是默认设置(因为不进行 fsync 速度更快)。根据该标准文档,似乎没有办法在远程文件上请求 fsync,但看起来 OpenSSH 支持将此作为 SFTP 的扩展
/* SSH2_FXP_EXTENDED submessages */
struct sftp_handler extended_handlers[] = {
...
{ "fsync", "[email protected]", 0, process_extended_fsync, 1 },
...
};
static void
process_extended_fsync(u_int32_t id)
{
int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED;
handle = get_handle();
debug3("request %u: fsync (handle %u)", id, handle);
verbose("fsync \"%s\"", handle_to_name(handle));
if ((fd = handle_to_fd(handle)) < 0)
status = SSH2_FX_NO_SUCH_FILE;
else if (handle_is_ok(handle, HANDLE_FILE)) {
ret = fsync(fd);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status);
}
我怀疑在 SSHFS 中查询该扩展并正确支持 fsync 会很困难,这似乎是一个相当合理的事情。也就是说,我认为使用 Linux 的网络块设备支持可能会更容易,我认为它可以正确支持所有这些东西(尽管我自己从未使用过它,所以它可能很糟糕)。