%20%E7%9A%84%E6%84%8F%E6%80%9D.png)
背景:我正在研究在不受信任的機器上加密儲存的方法。我目前的設定使用 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 的網路區塊裝置支援可能會更容易,我認為它可以正確支援所有這些東西(儘管我自己從未使用過它,所以它可能很糟糕)。