Значение fsync() в настройке sshfs+LUKS

Значение fsync() в настройке sshfs+LUKS

Фон:Я изучаю методы зашифрованного хранения на ненадежных машинах. Моя текущая настройка использует 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()поток ввода-вывода.

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). Согласно этому стандартному документу, похоже, нет способа запросить 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);
}

Я сомневаюсь, что будет сложно запросить это расширение и правильно поддерживать fsync в SSHFS, это кажется вполне разумным решением. Тем не менее, я думаю, что, вероятно, было бы проще просто использовать поддержку сетевых блочных устройств Linux, которая, как я предполагаю, поддерживает все это должным образом (хотя я сам никогда этим не пользовался, так что это может быть ужасно).

Связанный контент