LINUX.ORG.RU

Виртуалка просирает данные.

 


1

5

У одного хостера работает C++ приложение, которое периодически делает следующее:

int fd = open(filename_tmp, O_CREAT | O_TRUNC | O_NOATIME | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);

// запишем несколько буферов:
for ( auto &buff : _buffchain ) {
   r = write(fd, buff.ptr, buff.size);
   // тут (r == buff.size) && (buff.size > 0)
}



fsync(fd); // возможно это надо сделать после close(), но не вижу причин почему, да это и невозможно, дескриптор будет закрыт.
close(fd);

// А пока не произойдёт этого rename, наша работа вообще никому не видна.
rename(filename_tmp, filename);

Иногда, когда после этой процедуры через пару МИНУТ следует внезапный ребут, содержимое файла становится испорченным. Как будто его порубили на куски и немного подвигали эти куски с копированием, обрезанием и наслоением этих кусков. Ошибки в buffchain быть точно не может, там всё мега-примитивно — блок заголовок, блок 1, блок 2. Порча данных случается ВНУТРИ блоков — внутри блока 2, например. И только в ситуациях с внезапным ребутом после некоторого времени после записи. Без ребутов - никогда никакой порчи данных за пару лет работы этого кода замечено не было.

Спасибо.

Вот так запущена виртуалка:

/usr/libexec/qemu-kvm
-name guest=zzzzzz,debug-threads=on
-S
-object secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-12-zzzzzz/master-key.aes
-machine pc-i440fx-rhel7.3.0,accel=kvm,usb=off
-m 2048
-realtime mlock=off
-smp 1,sockets=1,cores=1,threads=1
-uuid 4444-4444-4444-4444-4444
-no-user-config
-nodefaults
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/domain-12-zzzz/monitor.sock,server,nowait
-mon chardev=charmonitor,id=monitor,mode=control
-rtc base=utc
-no-shutdown
-boot menu=on,strict=on
-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2
-drive file=/vm/zzzz,format=qcow2,if=none,id=drive-virtio-disk0
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1
-netdev tap,fd=30,id=hostnet0,vhost=on,vhostfd=32
-device virtio-net-pci,netdev=hostnet0,id=net0,mac=11:22:33:44:55:66,bus=pci.0,addr=0x3
-chardev pty,id=charserial0
-device isa-serial,chardev=charserial0,id=serial0
-device usb-tablet,id=input2,bus=usb.0,port=1
-vnc 111.222.111.222:888,password
-device cirrus-vga,id=video0,bus=pci.0,addr=0x2
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
-msg timestamp=on 


Последнее исправление: hlamotron (всего исправлений: 9)
Ответ на: комментарий от I-Love-Microsoft

плюсирую, ибо если этого не сделать после write, то не дождавшись close - оно всё похерит

Что кого похерит? С чего бы? Что значит «не дождавшись close», при чём тут это? После серии write стоит fsync(). write делаются друг за другом в одном потоке с одним файловым дескриптором. fsync(fd) обязан довести весь поток (всю последовательность байтов) до устройства (которое может буферизовать, но это щас неважно).

hlamotron
() автор топика
Последнее исправление: hlamotron (всего исправлений: 1)
Ответ на: комментарий от hlamotron

Разве ребут машин на хостинге не предполагает некоторое время, данное пользователям на завершение процессов? Или это аварийный сброс питания? Тогда этот момент надо тестировать.

Если попробовать родить совет как это отладить, то я бы пытался имитировать эту ситуацию. Она проявляется на рабочем ПК, если так же рубануть? Известен тип накопителей у хостера или через виртуалку не видно? Может тогда в рекламке пишут.

P.S. А fflush где? Если поставить fflush перед fsync, я не знаю, может поможет, хз.

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)
Ответ на: комментарий от I-Love-Microsoft

У меня такая ситуация была, на OpenSUSE 11.3. Жесткие диски были WD Blue на 500гб. Проявлялось на десятках компов после внезапного отключения питалова. fsync не помогал (если ничего не путаю). Было в 2010 году примерно. Так и не решил проблему. Потом стало не нужно.

pozitiffcat ★★★
()
Последнее исправление: pozitiffcat (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

P.S. А fflush где? Если поставить fflush перед fsync, я не знаю, может поможет, хз.

fflush это stdio, вообще сюда никаким боком.

slovazap ★★★★★
()
Ответ на: комментарий от pozitiffcat

Подобное я видел на некоторых промышленных SSD дисках, которые вроде как для жестких условий эксплуатации спроектированы. Тем не менее, там что-то клинило так, что даже журналируемая ФС не спасала даже от однократного неправильного выключения питания, при том что не было интенсивных процессов записи. Просто крутилась ОС на компе и он просто выключался внезапно. Слетели системные файлы, которые read only были. Такие дела.

Если это проблема диска - тогда капец. Поэтому, если ТС воспроизводит сценарий на рабочем компе и всё окей, а на хостинге пичалька - тогда это может даже и не лечится...

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)

Не нужно никаких fflush, и не нужно fsync никуда двигать. Код правильный, за исключением того что нужно обязательно проверять статусы fsync и close.

Как будто его порубили на куски и немного подвигали эти куски с копированием, обрезанием и наслоением этих кусков

seek'и в коде есть? Если нет, так быть не может. Файл может не дописаться, но порядок блоков гарантирован. Иначе у хостера всё плохо, какое-то совсем больное дерьмо с хранилищем, возможно дедубликацией.

slovazap ★★★★★
()

Может это проблема носителя данных? Например flash память сама пор себе не любит внезапных отключений в момент записи, может загамачить не только модифицируемые данные, но и смежные на носителе. Хитрые контроллеры flash пытаются как-то исправить все это, но что они делают там делают, не знает никто, кроме создателей.

pathfinder ★★★★
()
Последнее исправление: pathfinder (всего исправлений: 1)
Ответ на: комментарий от slovazap

seek в коде нет. Код именно тот, что приведён. А точнее он такой:

bool posix_mem_to_file_buffchain(const char *_filename, const std::vector<fir::str::BuffPtr> &_buffchain, bool _fsync)
{
	int fd = open(_filename, O_CREAT | O_TRUNC | O_NOATIME | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
	if ( fd < 0 ) {
		LOG_ERROR("posix_mem_to_file, open(): " << strerror(errno));
		return false;
	}

	ssize_t r = 0;
	for ( auto &buff : _buffchain ) {
		r = write(fd, buff.ptr, buff.size);
		if ( r < 0 ) {
			LOG_ERROR("posix_mem_to_file, write(): " << strerror(errno));
			return false;
		}

		if ( r != (ssize_t)buff.size ) {
			LOG_ERROR("posix_mem_to_file, write(): " << r << " / " << buff.size);
			return false;
		}
	}

	if ( _fsync ) {
		r = fsync(fd);
		if ( r < 0 ) {
			LOG_ERROR("posix_mem_to_file, fsync(): " << strerror(errno));
			return false;
		}
	}

	r = close(fd);
	if ( r < 0 ) {
		LOG_ERROR("posix_mem_to_file, close(): " << strerror(errno));
		return false;
	}



	return true;
}
hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Да, в коде малость не хватает close(fd) на ошибках.

hlamotron
() автор топика
Последнее исправление: hlamotron (всего исправлений: 1)

когда после этой процедуры через пару МИНУТ следует внезапный ребут

Внезапный ребут чего? Системы внутри виртуальной машины без перезапуска самого гипервизора (qemu-kvm, например)? Перезапуск гипервизора (killall -9 qemu-kvm) или всего хоста, на котором у хостера виртуалки крутятся? Во втором случае возможно у хостера стоят небезопасные настройки кеширования записи для блочных устройств, шобы у юзеров больше иопсов было =).

Deleted
()

Порядок записи блоков на диск может отличатся от порядка вызова write. Тоесть похоже у вас ситуация такая:

Идет последовательность write команд, при этом данные реально не сбрасываются на диск, зато на диск сбрасывается мета информация (в том числе размер файла - файл какбы уже вырас, но внутри еще мусор).

Потом по немногу начинают сбрасыватся блоки на диск (не обязательно в том порядке в котором они записывались)

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

zaz ★★★★
()
Ответ на: комментарий от zaz

Нет, ребут происходит точно после fsync(). А если он произошёл до fsync(), значит он произошёл до rename() и этого временного файла никто не увидит - на него всем пофиг.

Т.е. файл становится кому-то важным уже после того, как мы дошли до rename(), а значит возвратились из fsync().

hlamotron
() автор топика
Ответ на: комментарий от Deleted

А вот как устроен ребут я не знаю... Вполне возможно что у хостера есть эти небезопасные настройки, т.к. на одном хосте толкается много таких как я.

hlamotron
() автор топика

Файлу O_DIRECT и O_SYNC в open, виртуалке nocache/directio на диск.

mv ★★★★★
()

Глюки с ренейм - выглядит как глюки твого линукса.

Глюки с порчей данных - это скорее всего глюки драйвера файловой системы на хосте или драйвера стораджа или самого стораджа.

Вообще неработоспособность fsync() это притча во языцех, и наиболее простым лекарством является umount().

cvv ★★★★★
()
Ответ на: комментарий от hlamotron

// А пока не произойдёт этого rename, наша работа вообще никому не видна.
rename(filename_tmp, filename);

А вообще - напиши больше о файлухах, стораджах и всякое такое.

cvv ★★★★★
()
Последнее исправление: cvv (всего исправлений: 1)
Ответ на: комментарий от cvv

А вообще - напиши больше о файлухах, стораджах и всякое такое.

Чё?

hlamotron
() автор топика

Включи флаг синхронной записи в вызов open(). Там вроде есть какой-то, типа O_SYNC.

dzidzitop ★★
()
Ответ на: комментарий от I-Love-Microsoft

Как могут read-only похериться - хз. Может, во время записи файла директории. Но это лучше у спецов по накопителям и файловым системам спрашивать. Может, придумают сценарии.

dzidzitop ★★
()
Ответ на: комментарий от I-Love-Microsoft

Я думаю что у него на сервере какойто дешовый PCIe SSD, а рид-онли блоки были на томже секторе NAND что и RW.

cvv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.