sshfs+LUKS 설정에서 fsync()의 의미

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

답변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것을 알 수 있습니다 . 저는 이 플래그가 "쓰기할 때마다 서버에서 fsync"가 아닌 "쓰기에서 돌아오기 전에 서버에 명령이 전송될 때까지 대기"를 의미한다고 sshfs_flush()생각합니다 . 왜냐하면 두 번째 의미가 매우 이상하기 때문입니다. sshfs.sync_write따라서 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의 네트워크 블록 장치 지원을 사용하는 것이 더 쉬울 수 있다고 생각합니다. 이 지원은 이 모든 것을 올바르게 지원한다고 생각합니다(비록 제가 직접 사용해 본 적이 없기 때문에 나쁠 수도 있습니다).

관련 정보