%20na%20configura%C3%A7%C3%A3o%20sshfs%2BLUKS.png)
Fundo:Estou investigando métodos para armazenamento criptografado em máquinas não confiáveis. Minha configuração atual usa sshfs para acessar uma imagem criptografada por LUKS nocontrolo remotomáquina, que é descriptografadalocalmentee montado como ext3. (Se eu usasse apenas sshfs, alguém que obtivesse acesso à máquina remota poderia ver meus dados.) Aqui está 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.
Quero tornar isso resiliente contra falhas de rede. Para fazer isso, gostaria de entender o que acontece com o cache/buffer nesta 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 posso ver pelo tráfego da rede que os dados ainda estão sendo transmitidos após o retorno do comando. O segundo comando parece esperar até que a transferência dos dados seja concluída.
Perguntas concretas:Que garantias fsync()
oferece nesta configuração? Quando fsync()
retornar, até que ponto nessas camadas os dados serão sincronizados? E o que posso fazer para garantir que ele 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
Responder1
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. Na verdade, nunca olhei nenhum código FUSE antes, então pode haver algo mais acontecendo que eu perdi, mas de acordo com oCódigo-fonte SSHFS, a implementação do SSHFS fsync()
não faz muita coisa, apenas chama flush()
o fluxo de 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 sshfs_flush()
a função não envia nenhum tipo de comando de sincronização para a máquina remota que impõe um fsync. Acredito que o sshfs.sync_write
sinalizador significa "aguardar que os comandos cheguem ao servidor antes de retornar da gravação", e não "fsync no servidor a cada gravação" porque esse segundo significado seria muito estranho. Portanto, sua medição fsync é mais lenta porque é prejudicada 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 remota do SFTP realmente sincronize nas gravações, mas acho que não é isso que está acontecendo. De acordo com um antigorascunho 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.
o que implicaria que este não é o padrão (já que é mais rápido não sincronizar). 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 para 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);
}
Duvido que seja difícil consultar essa extensão e oferecer suporte adequado ao fsync no SSHFS, o que parece uma coisa bastante razoável de se fazer. Dito isto, acho que provavelmente seria mais fácil usar apenas o suporte a dispositivos de bloco de rede do Linux, que presumo que suporta tudo isso corretamente (embora eu nunca tenha usado isso, então pode ser horrível).