sshfs+LUKS 設置中 fsync() 的含義
**背景:**我正在研究在不受信任的機器上加密儲存的方法。我目前的設置使用 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
我假設這裡最薄弱的環節是 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,但看起來 OpenSSH 支持將此作為 SFTP 的擴展
/* SSH2_FXP_EXTENDED submessages */ struct sftp_handler extended_handlers[] = { ... { "fsync", "fsync@openssh.com", 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 的網路塊設備支持可能會更容易,我認為它可以正確支持所有這些東西(儘管我自己從未使用過它,所以它可能很糟糕)。