배경:신뢰할 수 없는 컴퓨터에 암호화된 저장 방법을 조사 중입니다. 현재 설정에서는 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);
}
에서 함수가 fsync를 시행하는 원격 시스템에 어떤 종류의 동기화 명령도 보내지 않는다는 sshfs.c:2551
것을 알 수 있습니다 . sshfs_flush()
나는 플래그가 "쓰기에서 반환되기 전에 명령이 서버로 이동하기를 기다림"을 의미한다고 생각합니다 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의 네트워크 블록 장치 지원을 사용하는 것이 아마도 더 쉬울 것이라고 생각합니다(비록 나는 그것을 직접 사용해 본 적이 없으므로 끔찍할 수 있습니다).