Significado de fsync () na configuração sshfs + LUKS

4

Plano de fundo: Estou investigando métodos de armazenamento criptografado em máquinas não confiáveis. Minha configuração atual usa o sshfs para acessar uma imagem criptografada pelo LUKS na máquina remota , que é descriptografada localmente e montada como ext3. (Se eu usasse apenas sshfs, alguém que tivesse acesso à máquina remota poderia ver meus dados.) Aqui está o meu exemplo de configuração:

# 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.

Eu quero fazer isso resiliente contra falhas de rede. Para fazer isso, eu gostaria de entender o que o armazenamento em cache / buffer acontece com essa configuração. Considere estes dois comandos:

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

O primeiro comando retorna muito rapidamente, e eu posso ver no tráfego de rede que os dados ainda estão sendo transmitidos após o retorno do comando. O segundo comando parece esperar até que os dados terminem de transferir.

Perguntas concretas: Que garantias o fsync() faz sob essa configuração? Quando fsync() retorna, até que ponto essas camadas são os dados com garantia de sincronização? E o que posso fazer para garantir que seja sincronizado até o disco rígido da máquina remota?

--- /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
    
por cberzan 14.10.2014 / 07:17

1 resposta

2

Eu diria que o elo mais fraco aqui é o código SSHFS - o resto do material está no kernel e muito usado, então provavelmente está tudo bem. Eu nunca realmente olhei para qualquer código FUSE antes, então poderia haver algo mais que eu perdi, mas de acordo com o Código-fonte SSHFS , a implementação do fsync() do SSHFS não faz muita coisa, apenas chama flush() no fluxo IO .

static int sshfs_fsync(const char *path, int isdatasync,
                       struct fuse_file_info *fi)
{
    (void) isdatasync;
    return sshfs_flush(path, fi);
}

Em sshfs.c:2551 , podemos ver que a função sshfs_flush() não envia nenhum tipo de comando de sincronização para a máquina remota que impõe um fsync. Eu acredito que o sinalizador sshfs.sync_write significa "esperar que os comandos vão para o servidor antes de retornar da gravação", não "fsync no servidor em cada gravação" porque esse segundo significado seria muito estranho. Assim, sua medição de fsync é mais lenta porque é limitada pela velocidade da rede, e não pela velocidade do disco remoto.

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;
}

Observe que é possível que a implementação do SFTP remoto realmente faça fsync nas gravações, mas acho que não é isso que realmente está acontecendo. De acordo com um antigo rascunho do padrão SFTP (que é o melhor que posso encontrar) existe uma maneira de especificar esse comportamento:

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.

que implicaria que este não é o padrão (como é mais rápido não fsync). De acordo com esse documento de padrões, não parece haver uma maneira de solicitar um fsync no arquivo remoto, mas parece que o OpenSSH suporta isso como uma extensão do 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);
}

Eu duvido que seja difícil consultar essa extensão e suportar corretamente o fsync no SSHFS, o que parece ser uma coisa bastante razoável de se fazer. Dito isso, acho que provavelmente seria mais fácil usar apenas o suporte de dispositivo de bloco de rede do Linux, que eu suponho que suporta tudo isso corretamente (embora eu nunca tenha usado isso sozinho, então pode ser horrível).

    
por 21.10.2014 / 05:43