forked from vitalif/vitastor
Compare commits
1 Commits
data-resiz
...
lrc-matrix
Author | SHA1 | Date | |
---|---|---|---|
42ae8f91ee |
@@ -96,5 +96,5 @@ Vitastor Network Public License 1.1, основанная на GNU GPL 3.0 с д
|
||||
и также на условиях GNU GPL 2.0 или более поздней версии. Так сделано в целях
|
||||
совместимости с таким ПО, как QEMU и fio.
|
||||
|
||||
Вы можете найти полный текст VNPL 1.1 на английском языке в файле [VNPL-1.1.txt](VNPL-1.1.txt),
|
||||
VNPL 1.1 на русском языке в файле [VNPL-1.1-RU.txt](VNPL-1.1-RU.txt), а GPL 2.0 в файле [GPL-2.0.txt](GPL-2.0.txt).
|
||||
Вы можете найти полный текст VNPL 1.1 в файле [VNPL-1.1.txt](VNPL-1.1.txt),
|
||||
а GPL 2.0 в файле [GPL-2.0.txt](GPL-2.0.txt).
|
||||
|
680
VNPL-1.1-RU.txt
680
VNPL-1.1-RU.txt
@@ -1,680 +0,0 @@
|
||||
СЕТЕВАЯ ПУБЛИЧНАЯ ЛИЦЕНЗИЯ VITASTOR
|
||||
VITASTOR NETWORK PUBLIC LICENSE
|
||||
Версия 1.1, от 6 февраля 2021
|
||||
|
||||
Автор лицензии: Виталий Филиппов <vitalif@yourcmc.ru>, 2021 год
|
||||
Каждый имеет право копировать и распространять точные копии этой
|
||||
лицензии, но без внесения изменений.
|
||||
|
||||
ПРЕАМБУЛА
|
||||
|
||||
Сетевая Публичная Лицензия Vitastor - это свободная "копилефт" лицензия для
|
||||
для программного обеспечения (ПО) и других видов произведений, специально
|
||||
разработанная, чтобы гарантировать кооперацию с сообществом при разработке
|
||||
сетевых приложений.
|
||||
|
||||
Большинство лицензий на программное обеспечение и другие произведения
|
||||
спроектированы так, чтобы лишить Вас свободы делиться ими и изменять их.
|
||||
Сетевая Публичная Лицензия Vitastor, напротив, разработана с целью
|
||||
гарантировать Ваше право распространять и вносить изменения во все версии
|
||||
программного обеспечения -- для уверенности, что ПО останется свободным для
|
||||
всех пользователей.
|
||||
|
||||
Когда мы говорим о свободном ПО, мы имеем в виду свободу использования, а не
|
||||
бесплатность. Свободные лицензии, такие, как Сетевая Публичная Лицензия
|
||||
Vitastor, составлены для того, чтобы убедиться, что у Вас есть право
|
||||
распространять копии свободного ПО (и взимать плату за них, если Вы хотите),
|
||||
что Вы получаете исходные тексты или можете получить их, если захотите, что Вы
|
||||
можете изменять программное обеспечение или использовать его части в новых
|
||||
свободных программах, и что Вы знаете о своем праве делать всё это.
|
||||
|
||||
Разработчики, использующие Сетевую Публичную Лицензию Vitastor, гарантируют
|
||||
Ваши права при помощи следующих мер: (1) закрепляют авторское право на
|
||||
программное обеспечение, и (2) предлагают Вам принять условия настоящей
|
||||
Лицензии, закрепляющей Ваше право на создание копий, распространение и (или)
|
||||
модификацию программного обеспечения.
|
||||
|
||||
Еще одно преимущество защиты свободы всех пользователей заключается в том,
|
||||
что улучшения, сделанные в разных версиях программы, при их широком
|
||||
распространении становятся доступными для использования другими разработчиками.
|
||||
Многие разработчики программного обеспечения воодушевляются этим
|
||||
сотрудничеством и пользуются его преимуществами. Однако, если программное
|
||||
обеспечение используется на сетевых серверах, данный результат не всегда
|
||||
достигается. Генеральная публичная лицензия GNU разрешает создание измененных
|
||||
версий и предоставление неограниченного доступа к ним, не делая общедоступным
|
||||
их исходный текст. Даже генеральная публичная лицензия GNU Affero разрешает
|
||||
использование модифицированной версии свободной программы в закрытой среде, где
|
||||
внешние пользователи взаимодействуют с ней только через закрытый промежуточный
|
||||
интерфейс (прокси), опять же, без открытия в свободный публичный доступ как
|
||||
самой программы, так и прокси.
|
||||
|
||||
Сетевая Публичная Лицензия Vitastor разработана специально чтобы
|
||||
гарантировать, что в таких случаях и модифицированная версия программы, и
|
||||
прокси оставались доступными сообществу. Для этого лицензия требует от
|
||||
операторов сетевых серверов предоставлять исходный код оригинальной программы,
|
||||
а также всех других программ, взаимодействующих с ней на их серверах,
|
||||
пользователям этих серверов, на условиях свободных лицензий. Таким образом,
|
||||
публичное использование изменённой версии ПО на сервере, прямо или косвенно
|
||||
доступном пользователям, даёт пользователям доступ к исходным кодам изменённой
|
||||
версии.
|
||||
|
||||
Детальные определения используемых терминов и описание условий копирования,
|
||||
распространения и внесения изменений приведены ниже.
|
||||
|
||||
ТЕРМИНЫ И УСЛОВИЯ
|
||||
|
||||
0. Определения.
|
||||
|
||||
"Настоящая Лицензия" -- версия 1.1 Сетевой Публичной Лицензии Vitastor.
|
||||
|
||||
Под "Авторским правом" понимаются все законы, сходные с авторско-правовыми,
|
||||
которые применяются к любым видам работ, например, к топологиям микросхем.
|
||||
|
||||
Термином "Программа" обозначается любое охраноспособное произведение,
|
||||
используемое в соответствии с настоящей Лицензией. Лицензиат именуется "Вы".
|
||||
"Лицензиаты" и "получатели" могут быть как физическими лицами, так и
|
||||
организациями.
|
||||
|
||||
"Внесение изменений" в произведение означает копирование или адаптацию
|
||||
произведения целиком или в части, способом, требующим разрешения
|
||||
правообладателя, за исключением изготовления его точной копии. Получившееся
|
||||
произведение называется "измененной версией" предыдущего произведения или
|
||||
произведением, "основанным на" более ранней работе.
|
||||
|
||||
Термином "Лицензионное произведение" обозначается неизмененная Программа или
|
||||
произведение, основанное на Программе.
|
||||
|
||||
"Распространение" произведения означает совершение с ним действий, которые
|
||||
при отсутствии разрешения сделают Вас прямо или косвенно ответственным за
|
||||
нарушение действующего закона об авторском праве, за исключением запуска на
|
||||
компьютере или изменения копии, созданной в личных целях. Распространение
|
||||
включает в себя копирование, раздачу копий (с изменениями или без них),
|
||||
доведение до всеобщего сведения, а в некоторых странах -- и другие действия.
|
||||
|
||||
"Передача" произведения означает любой вид распространения, который позволяет
|
||||
другим лицам создавать или получать копии произведения. Обычное взаимодействие
|
||||
с пользователем через компьютерную сеть без создания копии передачей не
|
||||
является.
|
||||
|
||||
Интерактивный интерфейс пользователя должен отображать "Информация об
|
||||
авторском праве", достаточную для того, чтобы (1) обеспечить отображение
|
||||
соответствующего уведомления об авторских правах и (2) сообщить пользователю
|
||||
о том, что ему не предоставляются никакие гарантии на произведение (за
|
||||
исключением явным образом предоставленных гарантий), о том, что лицензиаты
|
||||
могут передавать произведение на условиях, описанных в настоящей Лицензии,
|
||||
а также о том, как ознакомиться с текстом настоящей Лицензии. Если интерфейс
|
||||
предоставляет собой список пользовательских команд или настроек, наподобие
|
||||
меню, это требование считается выполненным при наличии явно выделенного
|
||||
пункта в таком меню.
|
||||
|
||||
1. Исходный текст.
|
||||
|
||||
Под "Исходным текстом" понимается произведение в форме, которая более всего
|
||||
подходит для внесения в него изменений. "Объектным кодом" называется
|
||||
произведение в любой иной форме.
|
||||
|
||||
"Стандартный интерфейс" -- интерфейс, который либо является общепринятым
|
||||
стандартом, введенным общепризнанным органом по стандартизации, либо, в случае
|
||||
интерфейсов, характерных для конкретного языка программирования -- тот,
|
||||
который широко используется разработчиками, пишущими программы на этом языке.
|
||||
|
||||
"Системные библиотеки" исполняемого произведения включают в себя то, что не
|
||||
относится к произведению в целом и при этом (a) входит в обычный комплект
|
||||
Основного компонента, но при этом не является его частью и (b) служит только
|
||||
для обеспечения работы с этим Основным компонентом или для реализации
|
||||
Стандартного интерфейса, для которого существует общедоступная реализация,
|
||||
опубликованная в виде исходного текста. "Основным компонентом" в данном
|
||||
контексте назван главный существенный компонент (ядро, оконная система и т.д.)
|
||||
определенной операционной системы (если она используется), под управлением
|
||||
которой функционирует исполняемое произведение, либо компилятор, используемый
|
||||
для создания произведения или интерпретатор объектного кода, используемый для
|
||||
его запуска.
|
||||
|
||||
"Полный исходный текст" для произведения в форме объектного кода -- весь
|
||||
исходный текст, необходимый для создания, установки и (для исполняемого
|
||||
произведения) функционирования объектного кода, а также модификации
|
||||
произведения, включая сценарии, контролирующие эти действия. Однако он не
|
||||
включает в себя Системные библиотеки, необходимые для функционирования
|
||||
произведения, инструменты общего назначения или общедоступные свободные
|
||||
программы, которые используются в неизменном виде для выполнения этих
|
||||
действий, но не являются частью произведения. Полный исходный текст включает
|
||||
в себя, например, файлы описания интерфейса, прилагаемые к файлам исходного
|
||||
текста произведения, а также исходные тексты общих библиотек и динамически
|
||||
связанных подпрограмм, которые требуются для функционирования произведения
|
||||
и разработаны специально для этого, например, для прямой передачи данных
|
||||
или управления потоками между этими подпрограммами и другими частями
|
||||
произведения. Полный исходный текст не включает в себя то, что пользователи
|
||||
могут сгенерировать автоматически из других частей Полного исходного текста.
|
||||
Полным исходным текстом для произведения в форме исходных текстов является
|
||||
само это произведение.
|
||||
|
||||
2. Основные права.
|
||||
|
||||
Все права, предоставленные на основании настоящей Лицензии, действуют в
|
||||
течение срока действия авторских прав на Программу и не могут быть отозваны
|
||||
при условии, что сформулированные в ней условия соблюдены. Настоящая Лицензия
|
||||
однозначно подтверждает Ваши неограниченные права на запуск неизмененной
|
||||
Программы. Настоящая Лицензия распространяется на результаты функционирования
|
||||
Лицензионного произведения только в том случае, если они, учитывая их
|
||||
содержание, сами являются частью Лицензионного произведения. Настоящая
|
||||
Лицензия подтверждает Ваши права на свободное использование произведения
|
||||
или другие аналогичные полномочия, предусмотренные действующим
|
||||
законодательством об авторском праве.
|
||||
|
||||
Если Вы не осуществляете обычную передачу Лицензионного произведения, то
|
||||
можете как угодно создавать, запускать и распространять его копии до тех пор,
|
||||
пока ваша Лицензия сохраняет силу. Вы можете передавать Лицензионные
|
||||
произведения третьим лицам исключительно для того, чтобы они внесли в них
|
||||
изменения для Вас или предоставили Вам возможность их запуска, при условии,
|
||||
что Вы соглашаетесь с условиями настоящей Лицензии при передаче всех
|
||||
материалов, авторскими правами на которые Вы не обладаете. Лица, создающие
|
||||
или запускающие Лицензионные произведения для Вас, должны делать это
|
||||
исключительно от Вашего имени, под Вашим руководством и контролем, на
|
||||
условиях, которые запрещают им создание без Вашей санкции каких-либо копий
|
||||
материалов, на которые Вы обладаете авторским правом.
|
||||
|
||||
Любая другая передача разрешается исключительно при соблюдении описанных
|
||||
ниже условий. Сублицензирование не допускается; раздел 10 делает его не нужным.
|
||||
|
||||
3. Защита прав пользователей от законов, запрещающих обход технических средств.
|
||||
|
||||
Ни одно Лицензионное произведение не должно считаться содержащим эффективные
|
||||
технические средства, удовлетворяющие требованиям любого действующего закона,
|
||||
принятого для исполнения обязательств, предусмотренных статьей 11 Договора ВОИС
|
||||
по авторскому праву от 20 декабря 1996 года или аналогичных законов,
|
||||
запрещающих или ограничивающих обход таких технических средств.
|
||||
|
||||
При передаче Лицензионного произведения Вы отказываетесь от всех
|
||||
предоставляемых законом полномочий по запрету обхода технических средств,
|
||||
используемых авторами в связи с осуществлением их прав, признавая, что такой
|
||||
обход находится в рамках осуществления прав на использование Лицензионного
|
||||
произведения, предоставленных настоящей Лицензией; также Вы отказываетесь
|
||||
от любых попыток ограничить функционирование произведения или внесение в него
|
||||
изменений, направленных на реализацию предоставленных Вам законом прав на
|
||||
запрет пользователю обхода технических средств.
|
||||
|
||||
4. Передача неизмененных копий.
|
||||
|
||||
Вы можете передавать точные копии исходных текстов Программы в том виде,
|
||||
в котором Вы их получили, на любом носителе, при условии, что Вы прилагаете
|
||||
к каждой копии соответствующее уведомление об авторских правах способом,
|
||||
обеспечивающим ознакомление с ним пользователя; сохраняете все уведомления
|
||||
о том, что к тексту применима настоящая Лицензия и любые ограничения,
|
||||
добавленные в соответствии с разделом 7; сохраняете все уведомления об
|
||||
отсутствии каких-либо гарантий; предоставляете всем получателям вместе с
|
||||
Программой копию настоящей Лицензии.
|
||||
|
||||
Вы можете установить любую цену за каждую копию, которую Вы передаете,
|
||||
или распространять копии бесплатно; также Вы можете предложить поддержку
|
||||
или гарантию за отдельную плату.
|
||||
|
||||
5. Передача измененных исходных текстов.
|
||||
|
||||
Вы можете передавать исходный текст произведения, основанного на Программе,
|
||||
или изменений, необходимых для того, чтобы получить его из Программы, на
|
||||
условиях, описанных в разделе 4, при соблюдении следующих условий:
|
||||
|
||||
а) Произведение должно содержать уведомления о произведенных Вами
|
||||
изменениях с указанием их даты, сделанные способом, обеспечивающим
|
||||
ознакомление с ними пользователя.
|
||||
|
||||
b) Произведение должно содержать уведомление о том, что оно
|
||||
распространяется на условиях настоящей Лицензии, а также об условиях,
|
||||
добавленных в соответствии с разделом 7, сделанное способом,
|
||||
обеспечивающим ознакомление с ним пользователя. Данное требование имеет
|
||||
приоритет над требованиями раздела 4 "оставлять нетронутыми все
|
||||
уведомления".
|
||||
|
||||
c) Вы должны передать на условиях настоящей Лицензии всю работу целиком
|
||||
любому лицу, которое приобретает копию. Таким образом, настоящая Лицензия
|
||||
вместе с любыми применимыми условиями раздела 7 будет применяться к
|
||||
произведению в целом и всем его частям, независимо от их комплектности.
|
||||
Настоящая Лицензия не дает права на лицензирование произведения на любых
|
||||
других условиях, но это не лишает законной силы такое разрешение, если Вы
|
||||
получили его отдельно.
|
||||
|
||||
d) Если произведение имеет интерактивные пользовательские интерфейсы,
|
||||
каждый из них должен отображать Информацию об авторском праве; однако,
|
||||
если Программа имеет пользовательские интерфейсы, которые не отображают
|
||||
информацию об авторском праве, от Вашего произведения этого также не
|
||||
требуется.
|
||||
|
||||
Включение Лицензионного произведения в подборку на разделе хранения данных
|
||||
или на носителе, на котором распространяется произведение, вместе с другими
|
||||
отдельными самостоятельными произведениями, которые по своей природе не
|
||||
являются переработкой Лицензионного произведения и не объединены с ним,
|
||||
например, в программный комплекс, называется "набором", если авторские права
|
||||
на подборку не используются для ограничения доступа к ней или законных прав
|
||||
её пользователей сверх того, что предусматривают лицензии на отдельные
|
||||
произведения. Включение Лицензионного произведения в набор не влечет применения
|
||||
положений настоящей Лицензии к остальным его частям.
|
||||
|
||||
6. Передача произведения в формах, не относящихся к исходному тексту.
|
||||
|
||||
Вы можете передавать Лицензионное произведение в виде объектного кода в
|
||||
соответствии с положениями разделов 4 и 5, при условии, что Вы также передаете
|
||||
машиночитаемый Полный исходный текст в соответствии с условиями настоящей
|
||||
Лицензии, одним из следующих способов:
|
||||
|
||||
а) Передавая объектный код или содержащий его материальный продукт (включая
|
||||
распределенный материальный носитель), с приложением Полного исходного
|
||||
текста наматериальном носителе, обычно используемом для обмена программным
|
||||
обеспечением.
|
||||
|
||||
b) Передавая объектный код или содержащий его материальный продукт (включая
|
||||
носитель, на котором распространяется произведение), с письменным
|
||||
предложением, действительным в течение не менее трех лет либо до тех пор,
|
||||
пока Вы предоставляете запасные части или поддержку для данного продукта,
|
||||
о передаче любому обладателю объектного кода (1) копии Полного исходного
|
||||
текста для всего программного обеспечения, содержащегося в продукте, на
|
||||
которое распространяется действие настоящей Лицензии, на физическом
|
||||
носителе, обычно используемом для обмена программным обеспечением, по цене,
|
||||
не превышающей разумных затрат на передачу копии, или (2) доступа к Полному
|
||||
исходному тексту с возможностью его копирования с сетевого сервера без
|
||||
взимания платы.
|
||||
|
||||
с) Передавая отдельные копии объектного кода с письменной копией предложения
|
||||
о предоставлении Полного исходного текста. Этот вариант допускается только
|
||||
в отдельных случаях при распространении без извлечения прибыли, и только
|
||||
если Вы получили объектный код с таким предложением в соответствии
|
||||
с пунктом 6b.
|
||||
|
||||
d) Передавая объектный код посредством предоставления доступа к нему по
|
||||
определенному адресу (бесплатно или за дополнительную плату), и предлагая
|
||||
эквивалентный доступ к Полному исходному тексту таким же способом по тому же
|
||||
адресу без какой-либо дополнительной оплаты. От Вас не требуется принуждать
|
||||
получателей копировать Полный исходный текст вместе с объектным кодом. Если
|
||||
объектный код размещен на сетевом сервере, Полный исходный текст может
|
||||
находиться на другом сервере (управляемом Вами или третьим лицом), который
|
||||
предоставляет аналогичную возможность копирования; при этом Вы должны четко
|
||||
указать рядом с объектным кодом способ получения Полного исходного текста.
|
||||
Независимо от того, на каком сервере расположен Полный исходный текст, Вы
|
||||
обязаны убедиться в том, что он будет распространяться в течение времени,
|
||||
необходимого для соблюдения этих требований.
|
||||
|
||||
e) Передавая объектный код с использованием одноранговой (пиринговой) сети,
|
||||
при условии информирования других пользователей сети о том, где можно
|
||||
бесплатно получить объектный код и Полный исходный текст произведения
|
||||
способом, описанным в пункте 6d.
|
||||
|
||||
Не нужно включать в передаваемый объектный код его отделимые части, исходные
|
||||
тексты которых не входят в состав Полного исходного текста, такие как Системные
|
||||
библиотеки.
|
||||
|
||||
"Потребительский товар" это либо (1) "товар, предназначенный для личных нужд",
|
||||
под которым понимается любое материальное личное имущество, которое обычно
|
||||
используется для личных, семейных или домашних целей, или (2) что-либо
|
||||
спроектированное или продающееся для использования в жилище. При определении
|
||||
того, предназначен ли товар для личных нужд, сомнения должны толковаться в
|
||||
пользу положительного ответа на этот вопрос. Применительно к конкретному
|
||||
товару, используемому конкретным пользователем, под выражением "обычно
|
||||
используется" имеется в виду способ, которым данный вид товаров преимущественно
|
||||
или как правило используется, независимо от статуса конкретного пользователя
|
||||
или способа, которым конкретный пользователь использует, предполагает или
|
||||
будет использовать товар. Товар относится к предназначенным для личных нужд
|
||||
независимо от того, насколько часто он используется в коммерческой
|
||||
деятельности, промышленности или иной сфере, не относящейся к личным нуждам,
|
||||
за исключением случая, когда использование в этой сфере представляет собой
|
||||
единственный основной способ использования такого товара.
|
||||
|
||||
"Информация, необходимая для установки" Потребительского товара -- любые
|
||||
методы, процедуры, сведения, необходимые для авторизации, или другая
|
||||
информация, необходимая для установки и запуска в Потребительском товаре
|
||||
измененных версий Лицензионного произведения, полученных при изменении
|
||||
Полного исходного текста. Данная информация должна быть достаточной для
|
||||
того, чтобы обеспечить возможность внесения в исходный текст изменений,
|
||||
не приводящих к ограничению или нарушению его дальнейшей работоспособности.
|
||||
|
||||
Если вместе с Потребительским товаром или специально для использования
|
||||
в нём Вы передаете произведение в виде объектного кода на условиях, описанных
|
||||
в данном разделе, и такая передача является частью сделки, по которой право
|
||||
владения и пользования Потребительским товаром переходит к получателю
|
||||
пожизненно или на определенный срок (независимо от признаков сделки), Полный
|
||||
исходный текст, передаваемый согласно данному разделу, должен сопровождаться
|
||||
Информацией, необходимой для установки. Но это требование не применяется,
|
||||
если ни Вы, ни какое-либо третье лицо не сохраняет за собой возможности
|
||||
установки измененного объектного кода на Потребительский товар (например,
|
||||
произведение было установлено в постоянную память).
|
||||
|
||||
Требование о предоставлении Информации, необходимой для установки, не
|
||||
включает в себя требование продолжения оказания услуг по поддержке,
|
||||
предоставления гарантии или обновлений для произведения, которое было изменено
|
||||
или установлено получателем, либо для Потребительского товара, в котором оно
|
||||
было изменено или на который оно было установлено. В доступе к сети может быть
|
||||
отказано, если само внесение изменений существенно и негативно влияет на
|
||||
работу сети, нарушает правила обмена данными или не поддерживает протоколы для
|
||||
обмена данными по сети.
|
||||
|
||||
Передаваемый в соответствии с данным разделом Полный исходный текст и
|
||||
предоставленная Информация, необходимая для установки, должны быть записаны в
|
||||
формате, который имеет общедоступное описание (и общедоступную реализацию,
|
||||
опубликованную в форме исходного текста) и не должны требовать никаких
|
||||
специальных паролей или ключей для распаковки, чтения или копирования.
|
||||
|
||||
7. Дополнительные условия.
|
||||
|
||||
"Дополнительными разрешениями" называются условия, которые дополняют условия
|
||||
настоящей Лицензии, делая исключения из одного или нескольких её положений.
|
||||
Дополнительные разрешения, которые применимы ко всей Программе, должны
|
||||
рассматриваться как часть настоящей Лицензии, в той степени, в которой они
|
||||
соответствуют действующему законодательству. Если дополнительные разрешения
|
||||
применяются только к части Программы, эта часть может быть использована отдельно
|
||||
на измененных условиях, но вся Программа продолжает использоваться на условиях
|
||||
настоящей Лицензии без учета дополнительных разрешений.
|
||||
|
||||
Когда Вы передаете копию Лицензионного произведения, Вы можете по своему
|
||||
усмотрению исключить любые дополнительные разрешения, примененные к этой копии
|
||||
или к любой её части. (Для дополнительных разрешений может быть заявлено
|
||||
требование об их удалении в определенных случаях, когда Вы вносите изменения в
|
||||
произведение.) Вы можете добавлять дополнительные разрешения к добавленным Вами
|
||||
в Лицензионное произведение материалам, на которые Вы обладаете авторскими
|
||||
правами или правом выдачи соответствующего разрешения.
|
||||
|
||||
Независимо от любых других положений настоящей Лицензии, Вы можете дополнить
|
||||
следующими условиями положения настоящей Лицензии в отношении материала,
|
||||
добавленного к Лицензионному произведению (если это разрешено обладателями
|
||||
авторских прав на материал):
|
||||
|
||||
a) отказом от гарантий или ограничением ответственности, отличающимися от
|
||||
тех, что описаны в разделах 15 и 16 настоящей Лицензии; либо
|
||||
|
||||
b) требованием сохранения соответствующей информации о правах или об
|
||||
авторстве материала, или включения её в Информацию об авторском праве,
|
||||
отображаемую содержащим его произведением; либо
|
||||
|
||||
c) запретом на искажение информации об источнике происхождения материала
|
||||
или требованием того, чтобы измененные версии такого материала содержали
|
||||
корректную отметку об отличиях от исходной версии; либо
|
||||
|
||||
d) ограничением использования в целях рекламы имен лицензиаров или авторов
|
||||
материала; либо
|
||||
|
||||
e) отказом от предоставления прав на использование в качестве товарных
|
||||
знаков некоторых торговых наименований, товарных знаков или знаков
|
||||
обслуживания; либо
|
||||
|
||||
f) требованием от каждого, кто по договору передает материал (или его
|
||||
измененные версии), предоставления компенсации лицензиарам и авторам
|
||||
материала в виде принятия на себя любой ответственности, которую этот
|
||||
договор налагает на лицензиаров и авторов.
|
||||
|
||||
Все остальные ограничительные дополнительные условия считаются "дополнительными
|
||||
запретами" по смыслу раздела 10. Если программа, которую Вы получили, или любая
|
||||
её часть содержит уведомление о том, что наряду с настоящей Лицензией её
|
||||
использование регулируется условием, относящимся к дополнительным запретам, Вы
|
||||
можете удалить такое условие. Если лицензия содержит дополнительный запрет, но
|
||||
допускает лицензирование на измененных условиях или передачу в соответствии с
|
||||
настоящей Лицензией, Вы можете добавить к Лицензионному произведению материал,
|
||||
используемый на условиях такой лицензии, в том случае, если дополнительный
|
||||
запрет не сохраняется при таком изменении условий лицензии или передаче.
|
||||
|
||||
Если Вы добавляете условия для использования Лицензионного произведения в
|
||||
соответствии с настоящим разделом, Вы должны поместить в соответствующих файлах
|
||||
исходного текста уведомление о том, что к этим файлам применяются дополнительные
|
||||
условия, или указание на то, как ознакомиться с соответствующими условиями.
|
||||
|
||||
Дополнительные разрешающие или ограничивающие условия могут быть сформулированы
|
||||
в виде отдельной лицензии или зафиксированы как исключения; вышеуказанные
|
||||
требования применяются в любом случае.
|
||||
|
||||
8. Прекращение действия.
|
||||
|
||||
Вы не можете распространять Лицензионное произведение или вносить в него
|
||||
изменения на условиях, отличающихся от явно оговоренных в настоящей Лицензии.
|
||||
Любая попытка распространения или внесения изменений на иных условиях является
|
||||
ничтожной и автоматически прекращает Ваши права, полученные по настоящей
|
||||
Лицензии (включая лицензию на любые патенты, предоставленные согласно третьему
|
||||
пункту раздела 11).
|
||||
|
||||
Тем не менее если Вы прекращаете нарушение настоящей Лицензии, Ваши права,
|
||||
полученные от конкретного правообладателя, восстанавливаются (а) временно, до
|
||||
тех пор пока правообладатель явно и окончательно не прекратит действие Ваших
|
||||
прав, и (б) навсегда, если правообладатель не уведомит Вас о нарушении с помощью
|
||||
надлежащих средств в течение 60 дней после прекращения нарушений.
|
||||
|
||||
Кроме того, Ваши права, полученные от конкретного правообладателя,
|
||||
восстанавливаются навсегда, если правообладатель впервые любым подходящим
|
||||
способом уведомляет Вас о нарушении настоящей Лицензии на свое произведение (для
|
||||
любого произведения) и Вы устраняете нарушение в течение 30 дней после получения
|
||||
уведомления.
|
||||
|
||||
Прекращение Ваших прав, описанное в настоящем разделе, не прекращает действие
|
||||
лицензий лиц, которые получили от Вас копии произведения или права,
|
||||
предоставляемые настоящей Лицензией. Если Ваши права были прекращены навсегда и
|
||||
не восстановлены, Вы не можете вновь получить право на тот же материал на
|
||||
условиях, описанных в разделе 10.
|
||||
|
||||
9. Акцепт не требуется для получения копий.
|
||||
|
||||
Вы не обязаны принимать условия настоящей Лицензии для того, чтобы получить или
|
||||
запустить копию Программы. Случайное распространение Лицензионного произведения,
|
||||
происходящее вследствие использования одноранговой (пиринговой) сети для
|
||||
получения его копии, также не требует принятия этих условий. Тем не менее только
|
||||
настоящая Лицензия дает Вам право распространять или изменять любое Лицензионное
|
||||
произведение. Если Вы не приняли условия настоящей Лицензии, такие действия
|
||||
будут нарушением авторского права. Поэтому изменяя или распространяя
|
||||
Лицензионное произведение, Вы выражаете согласие с условиями настоящей Лицензии.
|
||||
|
||||
10. Автоматическое получение прав последующими получателями.
|
||||
|
||||
Каждый раз, когда Вы передаете Лицензионное произведение, получатель
|
||||
автоматически получает от его лицензиара право запускать, изменять и
|
||||
распространять это произведение при условии соблюдения настоящей Лицензии. Вы не
|
||||
несете ответственности за соблюдение третьими лицами условий настоящей Лицензии.
|
||||
|
||||
"Реорганизацией" называются действия, в результате которых передается управление
|
||||
организацией или значительная часть её активов, а также происходит разделение
|
||||
или слияние организаций. Если распространение Лицензионного произведения
|
||||
является результатом реорганизации, каждая из сторон сделки, получающая копию
|
||||
произведения, также получает все права на произведение, которые предшествующее
|
||||
юридическое лицо имело или могло предоставить согласно предыдущему абзацу, а
|
||||
также право на владение Полным исходным текстом произведения от предшественника,
|
||||
осуществляемое в его интересах, если предшественник владеет им или может
|
||||
получить его при разумных усилиях.
|
||||
|
||||
Вы не можете налагать каких-либо дополнительных ограничений на осуществление
|
||||
прав, предоставленных или подтвержденных в соответствии с настоящей Лицензией.
|
||||
Например, Вы не можете ставить осуществление прав, предоставленных по настоящей
|
||||
Лицензии, в зависимость от оплаты отчислений, роялти или других сборов; также Вы
|
||||
не можете инициировать судебный процесс (включая встречный иск или заявление
|
||||
встречного требования в судебном процессе) о нарушении любых патентных прав при
|
||||
создании, использовании, продаже, предложении продажи, импорте Программы или
|
||||
любой её части.
|
||||
|
||||
11. Патенты.
|
||||
|
||||
"Инвестором" называется правообладатель, разрешающий использование Программы
|
||||
либо произведения, на котором основана Программа, на условиях настоящей
|
||||
Лицензии. Произведение, лицензированное таким образом, называется "версией со
|
||||
вкладом" инвестора.
|
||||
|
||||
"Неотъемлемые патентные претензии" инвестора -- все патентные права,
|
||||
принадлежащие инвестору или контролируемые им в настоящее время либо
|
||||
приобретенные в будущем, которые могут быть нарушены созданием, использованием
|
||||
или продажей версии со вкладом, допускаемыми настоящей Лицензией; они не
|
||||
включают в себя права, которые будут нарушены исключительно вследствие будущих
|
||||
изменений версии со вкладом. Для целей данного определения под "контролем"
|
||||
понимается право выдавать патентные сублицензии способами, не нарушающими
|
||||
требований настоящей Лицензии.
|
||||
|
||||
Каждый инвестор предоставляет Вам неисключительную безвозмездную лицензию на
|
||||
патент, действующую во всем мире, соответствующую неотъемлемым патентным
|
||||
претензиям инвестора, на создание, использование, продажу, предложение для
|
||||
продажи, импорт, а также запуск, внесение изменений и распространение всего, что
|
||||
входит в состав версии со вкладом.
|
||||
|
||||
В следующих трех абзацах "лицензией на патент" называется любое явно выраженное
|
||||
вовне согласие или обязательство не применять патент (например, выдача
|
||||
разрешения на использование запатентованного объекта или обещание не подавать в
|
||||
суд за нарушение патента). "Выдать" кому-то такую лицензию на патент означает
|
||||
заключить такое соглашение или обязаться не применять патент против него.
|
||||
|
||||
Если Вы передаете Лицензионное произведение, сознательно основываясь на лицензии
|
||||
на патент, в то время как Полный исходный текст произведения невозможно
|
||||
бесплатно скопировать с общедоступного сервера или другим не вызывающим
|
||||
затруднений способом, Вы должны либо (1) обеспечить возможность такого доступа к
|
||||
Полному исходному тексту, либо (2) отказаться от прав, предоставленных по
|
||||
лицензии на патент для данного произведения, либо (3) принять меры по передаче
|
||||
лицензии на патент последующим получателям произведения, в соответствии с
|
||||
требованиями настоящей Лицензии. "Сознательно основываясь" означает, что Вы
|
||||
знаете, что при отсутствии лицензии на патент передача Вами Лицензионного
|
||||
произведения в определенной стране или использование получателем переданного ему
|
||||
Вами Лицензионного произведения в этой стране нарушит один или несколько
|
||||
определенных патентов этой страны, срок действия которых не истек.
|
||||
|
||||
Если в соответствии или в связи с единичной сделкой либо соглашением Вы
|
||||
передаете или делаете заказ на распространение Лицензионного произведения, и
|
||||
предоставляете определенным лицам, получающим Лицензионное произведение,
|
||||
лицензию на патент, разрешающую им использовать, распространять, вносить
|
||||
изменения или передавать конкретные экземпляры Лицензионного произведения,
|
||||
права, которые Вы предоставляете по лицензии на патент, автоматически переходят
|
||||
ко всем получателям Лицензионного произведения и произведений, созданных на его
|
||||
основе.
|
||||
|
||||
Патентная лицензия называется "дискриминирующей", если она не покрывает,
|
||||
запрещает осуществление или содержит в качестве условия отказ от применения
|
||||
одного или нескольких прав, предоставленных настоящей Лицензией. Вы не можете
|
||||
передавать Лицензионное произведение, если Вы являетесь участником договора с
|
||||
третьим лицом, осуществляющим распространение программного обеспечения, в
|
||||
соответствии с которым Вы делаете в пользу третьего лица выплаты, размер которых
|
||||
зависит от масштабов Вашей деятельности по передаче произведения, и в
|
||||
соответствии с которым любое третье лицо, получающее от Вас Лицензионное
|
||||
произведение, делает это на условиях дискриминирующей патентной лицензии (а)
|
||||
которая зависит от количества копий Лицензионного произведения, переданных Вами
|
||||
(или копий, сделанных с этих копий), или (b) которая используется
|
||||
преимущественно в конкретных товарах или подборках, содержащих Лицензионное
|
||||
произведение, или в связи с ними, в том случае, если Вы заключили данный договор
|
||||
или получили лицензию на патент после 28 марта 2007 года.
|
||||
|
||||
Ничто в настоящей Лицензии не должно толковаться как исключение или ограничение
|
||||
любого предполагаемого права или других способов противодействия нарушениям,
|
||||
которые во всем остальном могут быть доступны для Вас в соответствии с
|
||||
применимым патентным правом.
|
||||
|
||||
12. Запрет отказывать в свободе другим.
|
||||
|
||||
Если на Вас наложены обязанности (будь то по решению суда, договору или иным
|
||||
способом), которые противоречат условиям настоящей Лицензии, это не освобождает
|
||||
Вас от соблюдения её условий. Если Вы не можете передать Лицензионное
|
||||
произведение так, чтобы одновременно выполнять Ваши обязательства по настоящей
|
||||
Лицензии и любые другие относящиеся к делу обязательства, то Вы не можете
|
||||
передавать его вообще. Например, если Вы согласны с условием, обязывающими Вас
|
||||
производить сбор отчислений за дальнейшую передачу от тех, кому Вы передаете
|
||||
Программу, то для того, чтобы соблюсти это условие и выполнить требования
|
||||
настоящей Лицензии, Вы должны полностью воздержаться от передачи Программы.
|
||||
|
||||
13. Удаленное сетевое взаимодействие.
|
||||
|
||||
Под "Прокси-программой" понимается отдельная программа, специально
|
||||
разработанная для использования совместно с Лицензионным произведением,
|
||||
и взаимодействующая с ним прямо или косвенно через любой вид программного
|
||||
интерфейса, компьютерную сеть, имитацию такой сети, или, в свою очередь,
|
||||
через другую Прокси-программу.
|
||||
|
||||
Независимо от любых других положений настоящей Лицензии, если вы
|
||||
предоставляете любому пользователю возможность взаимодействовать с Лицензионным
|
||||
произведением через компьютерную сеть, имитацию такой сети, или через любое
|
||||
количество "Прокси-программ", вы должны в явной форме предложить этому
|
||||
пользователю возможность получить Полный исходный текст Лицензионного
|
||||
произведения и всех Прокси-программ путём предоставления доступа к нему
|
||||
с сетевого сервера без взимания платы, посредством стандартных или
|
||||
традиционных способов, используемых для копирования программного обеспечения.
|
||||
Полный исходный текст Лицензионного произведения должен предоставляться
|
||||
пользователю на условиях настоящей Лицензии, а Полный исходный текст
|
||||
Прокси-программ должен предоставляться пользователю либо на условиях настоящей
|
||||
Лицензии, либо на условиях одной из свободных лицензий, совместимых с
|
||||
Генеральной публичной Лицензией GNU, перечисленных Фондом Свободного
|
||||
Программного Обеспечения в списке под названием "Лицензии свободных программ,
|
||||
совместимые с GPL".
|
||||
|
||||
14. Пересмотренные редакции настоящей Лицензии.
|
||||
|
||||
Автор настоящей Лицензии время от времени может публиковать пересмотренные
|
||||
и (или) новые редакции Сетевой Публичной Лицензии Vitastor. Они будут аналогичны
|
||||
по смыслу настоящей редакции, но могут отличаться от нее в деталях, направленных
|
||||
на решение новых проблем или регулирование новых отношений.
|
||||
|
||||
Каждой редакции присваивается собственный номер. Если для Программы указано,
|
||||
что к ней применима определенная редакция Сетевой Публичной Лицензии Vitastor
|
||||
"или любая более поздняя редакция", у Вас есть возможность использовать термины
|
||||
и условия, содержащиеся в редакции с указанным номером или любой более поздней
|
||||
редакции, опубликованной автором настоящей Лицензии. Если для Программы не
|
||||
указан номер редакции Сетевой Публичной Лицензии Vitastor, Вы можете выбрать
|
||||
любую редакцию, опубликованную автором настоящей Лицензии.
|
||||
|
||||
Более поздние редакции Лицензии могут дать Вам дополнительные или принципиально
|
||||
иные права. Тем не менее в результате Вашего выбора более поздней редакции на
|
||||
автора или правообладателя не возлагается никаких дополнительных обязанностей.
|
||||
|
||||
15. Отказ от гарантий.
|
||||
|
||||
НА ПРОГРАММУ НЕ ПРЕДОСТАВЛЯЕТСЯ НИКАКИХ ГАРАНТИЙ ЗА ИСКЛЮЧЕНИЕМ ПРЕДУСМОТРЕННЫХ
|
||||
ДЕЙСТВУЮЩИМ ЗАКОНОДАТЕЛЬСТВОМ. ЕСЛИ ИНОЕ НЕ УКАЗАНО В ПИСЬМЕННОЙ ФОРМЕ,
|
||||
ПРАВООБЛАДАТЕЛИ И (ИЛИ) ТРЕТЬИ ЛИЦА ПРЕДОСТАВЛЯЮТ ПРОГРАММУ "КАК ЕСТЬ", БЕЗ
|
||||
КАКИХ-ЛИБО ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ, ВКЛЮЧАЯ ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ
|
||||
КОНКРЕТНЫХ ЦЕЛЕЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. ВЕСЬ РИСК, СВЯЗАННЫЙ С КАЧЕСТВОМ И
|
||||
ПРОИЗВОДИТЕЛЬНОСТЬЮ ПРОГРАММЫ, ВОЗЛАГАЕТСЯ НА ВАС. ЕСЛИ В ПРОГРАММЕ БУДУТ
|
||||
ВЫЯВЛЕНЫ НЕДОСТАТКИ, ВЫ ПРИНИМАЕТЕ НА СЕБЯ СТОИМОСТЬ ВСЕГО НЕОБХОДИМОГО
|
||||
ОБСЛУЖИВАНИЯ, РЕМОНТА ИЛИ ИСПРАВЛЕНИЯ.
|
||||
|
||||
16. Ограничение ответственности.
|
||||
|
||||
ЕСЛИ ИНОЕ НЕ ПРЕДУСМОТРЕНО ДЕЙСТВУЮЩИМ ЗАКОНОДАТЕЛЬСТВОМ ИЛИ СОГЛАШЕНИЕМ СТОРОН,
|
||||
ЗАКЛЮЧЕННЫМ В ПИСЬМЕННОЙ ФОРМЕ, ПРАВООБЛАДАТЕЛЬ ИЛИ ИНОЕ ЛИЦО, КОТОРОЕ ВНОСИТ
|
||||
ИЗМЕНЕНИЯ В ПРОГРАММУ И (ИЛИ) ПЕРЕДАЕТ ЕЁ НА УСЛОВИЯХ, СФОРМУЛИРОВАННЫХ ВЫШЕ, НЕ
|
||||
МОЖЕТ НЕСТИ ОТВЕТСТВЕННОСТЬ ПЕРЕД ВАМИ ЗА ПРИЧИНЕННЫЙ УЩЕРБ, ВКЛЮЧАЯ УЩЕРБ
|
||||
ОБЩЕГО ЛИБО КОНКРЕТНОГО ХАРАКТЕРА, ПРИЧИНЕННЫЙ СЛУЧАЙНО ИЛИ ЯВЛЯЮЩИЙСЯ
|
||||
СЛЕДСТВИЕМ ИСПОЛЬЗОВАНИЯ ПРОГРАММЫ ЛИБО НЕВОЗМОЖНОСТИ ЕЁ ИСПОЛЬЗОВАНИЯ (В ТОМ
|
||||
ЧИСЛЕ ЗА УНИЧТОЖЕНИЕ ИЛИ МОДИФИКАЦИЮ ИНФОРМАЦИИ, ЛИБО УБЫТКИ, ПОНЕСЕННЫЕ ВАМИ
|
||||
ИЛИ ТРЕТЬИМИ ЛИЦАМИ, ЛИБО СБОИ ПРОГРАММЫ ПРИ ВЗАИМОДЕЙСТВИИ С ДРУГИМ ПРОГРАММНЫМ
|
||||
ОБЕСПЕЧЕНИЕМ), В ТОМ ЧИСЛЕ И В СЛУЧАЯХ, КОГДА ПРАВООБЛАДАТЕЛЬ ИЛИ ТРЕТЬЕ ЛИЦО
|
||||
ПРЕДУПРЕЖДЕНЫ О ВОЗМОЖНОСТИ ПРИЧИНЕНИЯ ТАКИХ УБЫТКОВ.
|
||||
|
||||
17. Толкование разделов 15 и 16.
|
||||
|
||||
Если отказ от гарантии и ограничение ответственности, представленные выше, по
|
||||
закону не могут быть применены в соответствии с их условиями, суды,
|
||||
рассматривающие спор, должны применить действующий закон, который в наибольшей
|
||||
степени предусматривает абсолютный отказ от всей гражданской ответственности в
|
||||
связи с Программой, за исключением случаев, когда гарантия или принятие на себя
|
||||
ответственности за копию программы предоставляется за плату.
|
||||
|
||||
КОНЕЦ ОПРЕДЕЛЕНИЙ И УСЛОВИЙ
|
||||
|
||||
Порядок применения условий Лицензии к Вашим программам
|
||||
|
||||
Если Вы разрабатываете новую программу и хотите, чтобы её использование принесло
|
||||
максимальную пользу обществу, наилучший способ достичь этого -- сделать её
|
||||
свободной, чтобы все могли распространять и изменять её на условиях настоящей
|
||||
Лицензии.
|
||||
|
||||
Для этого сделайте так, чтобы программа содержала в себе описанные ниже
|
||||
уведомления. Самым надежным способом это сделать является включение их в начало
|
||||
каждого файла исходного текста, чтобы наиболее эффективным образом сообщить об
|
||||
отсутствии гарантий; каждый файл должен иметь по меньшей мере одну строку с
|
||||
оповещением об авторских правах и указанием на то, где находится полный текст
|
||||
уведомлений.
|
||||
|
||||
<Строка с названием Программы и информацией о её назначении.>
|
||||
Copyright © <год выпуска программы в свет> <имя автора>
|
||||
|
||||
Эта программа является свободным программным обеспечением: Вы можете
|
||||
распространять её и (или) изменять, соблюдая условия Сетевой Публичной
|
||||
Лицензии Vitastor, опубликованной автором Vitastor, либо редакции 1.1
|
||||
Лицензии, либо (на Ваше усмотрение) любой редакции, выпущенной позже.
|
||||
|
||||
Эта программа распространяется в расчете на то, что она окажется полезной,
|
||||
но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, включая подразумеваемую гарантию КАЧЕСТВА либо
|
||||
ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Ознакомьтесь с Сетевой Публичной
|
||||
Лицензией Vitastor для получения более подробной информации.
|
||||
|
||||
Также добавьте информацию о том, как связаться с Вами посредством электронной
|
||||
или обычной почты.
|
||||
|
||||
Если ваша программа взаимодействует с пользователями удаленно через
|
||||
компьютерную сеть, Вы также должны убедиться, что обеспечили её пользователям
|
||||
возможность получить её исходные тексты. Например, если Ваша программа является
|
||||
веб-приложением, её интерфейс может отображать ссылку "Исходные коды", которая
|
||||
указывает на архив с текстом. Существует много способов, которыми Вы можете
|
||||
распространять исходные тексты, для разных программ подходят разные решения;
|
||||
ознакомьтесь с разделом 13 для того, чтобы узнать конкретные требования.
|
@@ -61,7 +61,7 @@ modification follow.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 1.1 of the Vitastor Network Public License.
|
||||
"This License" refers to version 1 of the Vitastor Network Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
@@ -629,7 +629,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the Vitastor Network Public License as published by
|
||||
the Vitastor Author, either version 1.1 of the License, or
|
||||
the Vitastor Author, either version 1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
|
2
debian/vitastor-osd.install
vendored
2
debian/vitastor-osd.install
vendored
@@ -1,3 +1,3 @@
|
||||
usr/bin/vitastor-osd
|
||||
usr/bin/vitastor-disk
|
||||
usr/bin/vitastor-dump-journal
|
||||
usr/bin/vitastor-dump-meta
|
||||
|
@@ -33,5 +33,5 @@ Vitastor Network Public License 1.1, основанная на GNU GPL 3.0 с д
|
||||
и также на условиях GNU GPL 2.0 или более поздней версии. Так сделано в целях
|
||||
совместимости с таким ПО, как QEMU и fio.
|
||||
|
||||
Вы можете найти полный текст VNPL 1.1 на английском языке в файле [VNPL-1.1.txt](../../VNPL-1.1.txt),
|
||||
VNPL 1.1 на русском языке в файле [VNPL-1.1-RU.txt](../../VNPL-1.1-RU.txt), а GPL 2.0 в файле [GPL-2.0.txt](../../GPL-2.0.txt).
|
||||
Вы можете найти полный текст VNPL 1.1 в файле [VNPL-1.1.txt](../../VNPL-1.1.txt),
|
||||
а GPL 2.0 в файле [GPL-2.0.txt](../../GPL-2.0.txt).
|
||||
|
@@ -112,8 +112,8 @@ cp -r mon %buildroot/usr/lib/vitastor
|
||||
|
||||
%files -n vitastor-osd
|
||||
%_bindir/vitastor-osd
|
||||
%_bindir/vitastor-disk
|
||||
%_bindir/vitastor-dump-journal
|
||||
%_bindir/vitastor-dump-meta
|
||||
|
||||
|
||||
%files -n vitastor-mon
|
||||
|
@@ -109,8 +109,8 @@ cp -r mon %buildroot/usr/lib/vitastor
|
||||
|
||||
%files -n vitastor-osd
|
||||
%_bindir/vitastor-osd
|
||||
%_bindir/vitastor-disk
|
||||
%_bindir/vitastor-dump-journal
|
||||
%_bindir/vitastor-dump-meta
|
||||
|
||||
|
||||
%files -n vitastor-mon
|
||||
|
@@ -193,13 +193,14 @@ target_link_libraries(vitastor-cli
|
||||
)
|
||||
configure_file(vitastor.pc.in vitastor.pc @ONLY)
|
||||
|
||||
# vitastor-disk
|
||||
add_executable(vitastor-disk
|
||||
disk_tool.cpp crc32c.c rw_blocking.cpp allocator.cpp ringloop.cpp
|
||||
# vitastor-dump-journal
|
||||
add_executable(vitastor-dump-journal
|
||||
dump_journal.cpp crc32c.c
|
||||
)
|
||||
target_link_libraries(vitastor-disk
|
||||
tcmalloc_minimal
|
||||
${LIBURING_LIBRARIES}
|
||||
|
||||
# vitastor-dump-meta
|
||||
add_executable(vitastor-dump-meta
|
||||
dump_meta.cpp
|
||||
)
|
||||
|
||||
if (${WITH_QEMU})
|
||||
@@ -279,8 +280,7 @@ target_include_directories(test_cluster_client PUBLIC ${CMAKE_SOURCE_DIR}/src/mo
|
||||
|
||||
### Install
|
||||
|
||||
install(TARGETS vitastor-osd vitastor-disk vitastor-nbd vitastor-nfs vitastor-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install_symlink(vitastor-disk ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-dump-journal)
|
||||
install(TARGETS vitastor-osd vitastor-dump-journal vitastor-dump-meta vitastor-nbd vitastor-nfs vitastor-cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vitastor-rm)
|
||||
install_symlink(vitastor-cli ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/vita)
|
||||
install(
|
||||
|
@@ -29,9 +29,9 @@
|
||||
#endif
|
||||
|
||||
// Default block size is 128 KB, current allowed range is 4K - 128M
|
||||
#define DEFAULT_DATA_BLOCK_ORDER 17
|
||||
#define MIN_DATA_BLOCK_SIZE 4*1024
|
||||
#define MAX_DATA_BLOCK_SIZE 128*1024*1024
|
||||
#define DEFAULT_ORDER 17
|
||||
#define MIN_BLOCK_SIZE 4*1024
|
||||
#define MAX_BLOCK_SIZE 128*1024*1024
|
||||
#define DEFAULT_BITMAP_GRANULARITY 4096
|
||||
|
||||
#define BS_OP_MIN 1
|
||||
@@ -193,6 +193,7 @@ public:
|
||||
// Print diagnostics to stdout
|
||||
void dump_diagnostics();
|
||||
|
||||
// FIXME rename to object_size
|
||||
uint32_t get_block_size();
|
||||
uint64_t get_block_count();
|
||||
uint64_t get_free_block_count();
|
||||
|
@@ -13,7 +13,7 @@ blockstore_impl_t::blockstore_impl_t(blockstore_config_t & config, ring_loop_t *
|
||||
initialized = 0;
|
||||
data_fd = meta_fd = journal.fd = -1;
|
||||
parse_config(config);
|
||||
zero_object = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, data_block_size);
|
||||
zero_object = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, block_size);
|
||||
try
|
||||
{
|
||||
open_data();
|
||||
@@ -343,8 +343,8 @@ void blockstore_impl_t::enqueue_op(blockstore_op_t *op)
|
||||
{
|
||||
if (op->opcode < BS_OP_MIN || op->opcode > BS_OP_MAX ||
|
||||
((op->opcode == BS_OP_READ || op->opcode == BS_OP_WRITE || op->opcode == BS_OP_WRITE_STABLE) && (
|
||||
op->offset >= data_block_size ||
|
||||
op->len > data_block_size-op->offset ||
|
||||
op->offset >= block_size ||
|
||||
op->len > block_size-op->offset ||
|
||||
(op->len % disk_alignment)
|
||||
)) ||
|
||||
readonly && op->opcode != BS_OP_READ && op->opcode != BS_OP_LIST)
|
||||
@@ -477,7 +477,7 @@ void blockstore_impl_t::process_list(blockstore_op_t *op)
|
||||
uint64_t min_inode = op->oid.inode;
|
||||
uint64_t max_inode = op->version;
|
||||
// Check PG
|
||||
if (pg_count != 0 && (pg_stripe_size < MIN_DATA_BLOCK_SIZE || list_pg > pg_count))
|
||||
if (pg_count != 0 && (pg_stripe_size < MIN_BLOCK_SIZE || list_pg > pg_count))
|
||||
{
|
||||
op->retval = -EINVAL;
|
||||
FINISH_OP(op);
|
||||
|
@@ -90,13 +90,13 @@
|
||||
#include "blockstore_journal.h"
|
||||
|
||||
// "VITAstor"
|
||||
#define BLOCKSTORE_META_MAGIC_V1 0x726F747341544956l
|
||||
#define BLOCKSTORE_META_VERSION_V1 1
|
||||
#define BLOCKSTORE_META_MAGIC 0x726F747341544956l
|
||||
#define BLOCKSTORE_META_VERSION 1
|
||||
|
||||
// metadata header (superblock)
|
||||
// FIXME: After adding the OSD superblock, add a key to metadata
|
||||
// and journal headers to check if they belong to the same OSD
|
||||
struct __attribute__((__packed__)) blockstore_meta_header_v1_t
|
||||
struct __attribute__((__packed__)) blockstore_meta_header_t
|
||||
{
|
||||
uint64_t zero;
|
||||
uint64_t magic;
|
||||
@@ -219,7 +219,7 @@ class blockstore_impl_t
|
||||
{
|
||||
/******* OPTIONS *******/
|
||||
std::string data_device, meta_device, journal_device;
|
||||
uint32_t data_block_size;
|
||||
uint32_t block_size;
|
||||
uint64_t meta_offset;
|
||||
uint64_t data_offset;
|
||||
uint64_t cfg_journal_size, cfg_data_size;
|
||||
@@ -274,8 +274,8 @@ class blockstore_impl_t
|
||||
|
||||
int meta_fd;
|
||||
int data_fd;
|
||||
uint64_t meta_device_size, meta_len;
|
||||
uint64_t data_device_size, data_len;
|
||||
uint64_t meta_size, meta_area, meta_len;
|
||||
uint64_t data_size, data_len;
|
||||
uint64_t data_device_sect, meta_device_sect, journal_device_sect;
|
||||
|
||||
void *metadata_buffer = NULL;
|
||||
@@ -394,7 +394,7 @@ public:
|
||||
// Print diagnostics to stdout
|
||||
void dump_diagnostics();
|
||||
|
||||
inline uint32_t get_block_size() { return data_block_size; }
|
||||
inline uint32_t get_block_size() { return block_size; }
|
||||
inline uint64_t get_block_count() { return block_count; }
|
||||
inline uint64_t get_free_block_count() { return data_alloc->get_free_count(); }
|
||||
inline uint32_t get_bitmap_granularity() { return disk_alignment; }
|
||||
|
@@ -71,12 +71,12 @@ resume_1:
|
||||
if (iszero((uint64_t*)metadata_buffer, bs->meta_block_size / sizeof(uint64_t)))
|
||||
{
|
||||
{
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)metadata_buffer;
|
||||
blockstore_meta_header_t *hdr = (blockstore_meta_header_t *)metadata_buffer;
|
||||
hdr->zero = 0;
|
||||
hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||
hdr->version = BLOCKSTORE_META_VERSION_V1;
|
||||
hdr->magic = BLOCKSTORE_META_MAGIC;
|
||||
hdr->version = BLOCKSTORE_META_VERSION;
|
||||
hdr->meta_block_size = bs->meta_block_size;
|
||||
hdr->data_block_size = bs->data_block_size;
|
||||
hdr->data_block_size = bs->block_size;
|
||||
hdr->bitmap_granularity = bs->bitmap_granularity;
|
||||
}
|
||||
if (bs->readonly)
|
||||
@@ -103,10 +103,10 @@ resume_1:
|
||||
}
|
||||
else
|
||||
{
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)metadata_buffer;
|
||||
blockstore_meta_header_t *hdr = (blockstore_meta_header_t *)metadata_buffer;
|
||||
if (hdr->zero != 0 ||
|
||||
hdr->magic != BLOCKSTORE_META_MAGIC_V1 ||
|
||||
hdr->version != BLOCKSTORE_META_VERSION_V1)
|
||||
hdr->magic != BLOCKSTORE_META_MAGIC ||
|
||||
hdr->version != BLOCKSTORE_META_VERSION)
|
||||
{
|
||||
printf(
|
||||
"Metadata is corrupt or old version.\n"
|
||||
@@ -116,7 +116,7 @@ resume_1:
|
||||
exit(1);
|
||||
}
|
||||
if (hdr->meta_block_size != bs->meta_block_size ||
|
||||
hdr->data_block_size != bs->data_block_size ||
|
||||
hdr->data_block_size != bs->block_size ||
|
||||
hdr->bitmap_granularity != bs->bitmap_granularity)
|
||||
{
|
||||
printf(
|
||||
@@ -124,7 +124,7 @@ resume_1:
|
||||
" (meta_block_size=%u, data_block_size=%u, bitmap_granularity=%u)"
|
||||
" differs from OSD configuration (%lu/%u/%lu).\n",
|
||||
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity,
|
||||
bs->meta_block_size, bs->data_block_size, bs->bitmap_granularity
|
||||
bs->meta_block_size, bs->block_size, bs->bitmap_granularity
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
@@ -240,7 +240,7 @@ void blockstore_init_meta::handle_entries(void* entries, unsigned count, int blo
|
||||
}
|
||||
else
|
||||
{
|
||||
bs->inode_space_stats[entry->oid.inode] += bs->data_block_size;
|
||||
bs->inode_space_stats[entry->oid.inode] += bs->block_size;
|
||||
}
|
||||
entries_loaded++;
|
||||
#ifdef BLOCKSTORE_DEBUG
|
||||
@@ -913,8 +913,8 @@ void blockstore_init_journal::erase_dirty_object(blockstore_dirty_db_t::iterator
|
||||
if (exists && clean_loc == UINT64_MAX)
|
||||
{
|
||||
auto & sp = bs->inode_space_stats[oid.inode];
|
||||
if (sp > bs->data_block_size)
|
||||
sp -= bs->data_block_size;
|
||||
if (sp > bs->block_size)
|
||||
sp -= bs->block_size;
|
||||
else
|
||||
bs->inode_space_stats.erase(oid.inode);
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config)
|
||||
cfg_data_size = strtoull(config["data_size"].c_str(), NULL, 10);
|
||||
meta_device = config["meta_device"];
|
||||
meta_offset = strtoull(config["meta_offset"].c_str(), NULL, 10);
|
||||
data_block_size = strtoull(config["block_size"].c_str(), NULL, 10);
|
||||
block_size = strtoull(config["block_size"].c_str(), NULL, 10);
|
||||
inmemory_meta = config["inmemory_metadata"] != "false";
|
||||
journal_device = config["journal_device"];
|
||||
journal.offset = strtoull(config["journal_offset"].c_str(), NULL, 10);
|
||||
@@ -85,11 +85,11 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config)
|
||||
throttle_target_parallelism = strtoull(config["throttle_target_parallelism"].c_str(), NULL, 10);
|
||||
throttle_threshold_us = strtoull(config["throttle_threshold_us"].c_str(), NULL, 10);
|
||||
// Validate
|
||||
if (!data_block_size)
|
||||
if (!block_size)
|
||||
{
|
||||
data_block_size = (1 << DEFAULT_DATA_BLOCK_ORDER);
|
||||
block_size = (1 << DEFAULT_ORDER);
|
||||
}
|
||||
if ((block_order = is_power_of_two(data_block_size)) >= 64 || data_block_size < MIN_DATA_BLOCK_SIZE || data_block_size >= MAX_DATA_BLOCK_SIZE)
|
||||
if ((block_order = is_power_of_two(block_size)) >= 64 || block_size < MIN_BLOCK_SIZE || block_size >= MAX_BLOCK_SIZE)
|
||||
{
|
||||
throw std::runtime_error("Bad block size");
|
||||
}
|
||||
@@ -141,7 +141,7 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config)
|
||||
{
|
||||
throw std::runtime_error("Sparse write tracking granularity must be a multiple of disk_alignment = "+std::to_string(disk_alignment));
|
||||
}
|
||||
if (data_block_size % bitmap_granularity)
|
||||
if (block_size % bitmap_granularity)
|
||||
{
|
||||
throw std::runtime_error("Block size must be a multiple of sparse write tracking granularity");
|
||||
}
|
||||
@@ -202,7 +202,7 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config)
|
||||
throttle_threshold_us = 50;
|
||||
}
|
||||
// init some fields
|
||||
clean_entry_bitmap_size = data_block_size / bitmap_granularity / 8;
|
||||
clean_entry_bitmap_size = block_size / bitmap_granularity / 8;
|
||||
clean_entry_size = sizeof(clean_disk_entry) + 2*clean_entry_bitmap_size;
|
||||
journal.block_size = journal_block_size;
|
||||
journal.next_free = journal_block_size;
|
||||
@@ -214,7 +214,7 @@ void blockstore_impl_t::parse_config(blockstore_config_t & config)
|
||||
void blockstore_impl_t::calc_lengths()
|
||||
{
|
||||
// data
|
||||
data_len = data_device_size - data_offset;
|
||||
data_len = data_size - data_offset;
|
||||
if (data_fd == meta_fd && data_offset < meta_offset)
|
||||
{
|
||||
data_len = meta_offset - data_offset;
|
||||
@@ -234,18 +234,18 @@ void blockstore_impl_t::calc_lengths()
|
||||
data_len = cfg_data_size;
|
||||
}
|
||||
// meta
|
||||
uint64_t meta_area_size = (meta_fd == data_fd ? data_device_size : meta_device_size) - meta_offset;
|
||||
meta_area = (meta_fd == data_fd ? data_size : meta_size) - meta_offset;
|
||||
if (meta_fd == data_fd && meta_offset <= data_offset)
|
||||
{
|
||||
meta_area_size = data_offset - meta_offset;
|
||||
meta_area = data_offset - meta_offset;
|
||||
}
|
||||
if (meta_fd == journal.fd && meta_offset <= journal.offset)
|
||||
{
|
||||
meta_area_size = meta_area_size < journal.offset-meta_offset
|
||||
? meta_area_size : journal.offset-meta_offset;
|
||||
meta_area = meta_area < journal.offset-meta_offset
|
||||
? meta_area : journal.offset-meta_offset;
|
||||
}
|
||||
// journal
|
||||
journal.len = (journal.fd == data_fd ? data_device_size : (journal.fd == meta_fd ? meta_device_size : journal.device_size)) - journal.offset;
|
||||
journal.len = (journal.fd == data_fd ? data_size : (journal.fd == meta_fd ? meta_size : journal.device_size)) - journal.offset;
|
||||
if (journal.fd == data_fd && journal.offset <= data_offset)
|
||||
{
|
||||
journal.len = data_offset - journal.offset;
|
||||
@@ -256,9 +256,9 @@ void blockstore_impl_t::calc_lengths()
|
||||
? journal.len : meta_offset-journal.offset;
|
||||
}
|
||||
// required metadata size
|
||||
block_count = data_len / data_block_size;
|
||||
block_count = data_len / block_size;
|
||||
meta_len = (1 + (block_count - 1 + meta_block_size / clean_entry_size) / (meta_block_size / clean_entry_size)) * meta_block_size;
|
||||
if (meta_area_size < meta_len)
|
||||
if (meta_area < meta_len)
|
||||
{
|
||||
throw std::runtime_error("Metadata area is too small, need at least "+std::to_string(meta_len)+" bytes");
|
||||
}
|
||||
@@ -316,7 +316,7 @@ static void check_size(int fd, uint64_t *size, uint64_t *sectsize, std::string n
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0 ||
|
||||
ioctl(fd, BLKSSZGET, §) < 0)
|
||||
{
|
||||
throw std::runtime_error("Failed to get "+name+" size or block size: "+strerror(errno));
|
||||
throw std::runtime_error("failed to get "+name+" size or block size: "+strerror(errno));
|
||||
}
|
||||
if (sectsize)
|
||||
{
|
||||
@@ -336,7 +336,7 @@ void blockstore_impl_t::open_data()
|
||||
{
|
||||
throw std::runtime_error("Failed to open data device");
|
||||
}
|
||||
check_size(data_fd, &data_device_size, &data_device_sect, "data device");
|
||||
check_size(data_fd, &data_size, &data_device_sect, "data device");
|
||||
if (disk_alignment % data_device_sect)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
@@ -344,9 +344,9 @@ void blockstore_impl_t::open_data()
|
||||
") is not a multiple of data device sector size ("+std::to_string(data_device_sect)+")"
|
||||
);
|
||||
}
|
||||
if (data_offset >= data_device_size)
|
||||
if (data_offset >= data_size)
|
||||
{
|
||||
throw std::runtime_error("data_offset exceeds device size = "+std::to_string(data_device_size));
|
||||
throw std::runtime_error("data_offset exceeds device size = "+std::to_string(data_size));
|
||||
}
|
||||
if (!disable_flock && flock(data_fd, LOCK_EX|LOCK_NB) != 0)
|
||||
{
|
||||
@@ -364,10 +364,10 @@ void blockstore_impl_t::open_meta()
|
||||
{
|
||||
throw std::runtime_error("Failed to open metadata device");
|
||||
}
|
||||
check_size(meta_fd, &meta_device_size, &meta_device_sect, "metadata device");
|
||||
if (meta_offset >= meta_device_size)
|
||||
check_size(meta_fd, &meta_size, &meta_device_sect, "metadata device");
|
||||
if (meta_offset >= meta_size)
|
||||
{
|
||||
throw std::runtime_error("meta_offset exceeds device size = "+std::to_string(meta_device_size));
|
||||
throw std::runtime_error("meta_offset exceeds device size = "+std::to_string(meta_size));
|
||||
}
|
||||
if (!disable_flock && flock(meta_fd, LOCK_EX|LOCK_NB) != 0)
|
||||
{
|
||||
@@ -378,10 +378,10 @@ void blockstore_impl_t::open_meta()
|
||||
{
|
||||
meta_fd = data_fd;
|
||||
meta_device_sect = data_device_sect;
|
||||
meta_device_size = 0;
|
||||
if (meta_offset >= data_device_size)
|
||||
meta_size = 0;
|
||||
if (meta_offset >= data_size)
|
||||
{
|
||||
throw std::runtime_error("meta_offset exceeds device size = "+std::to_string(data_device_size));
|
||||
throw std::runtime_error("meta_offset exceeds device size = "+std::to_string(data_size));
|
||||
}
|
||||
}
|
||||
if (meta_block_size % meta_device_sect)
|
||||
@@ -413,7 +413,7 @@ void blockstore_impl_t::open_journal()
|
||||
journal.fd = meta_fd;
|
||||
journal_device_sect = meta_device_sect;
|
||||
journal.device_size = 0;
|
||||
if (journal.offset >= data_device_size)
|
||||
if (journal.offset >= data_size)
|
||||
{
|
||||
throw std::runtime_error("journal_offset exceeds device size");
|
||||
}
|
||||
|
@@ -186,7 +186,7 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *read_op)
|
||||
{
|
||||
if (!clean_entry_bitmap_size)
|
||||
{
|
||||
if (!fulfill_read(read_op, fulfilled, 0, data_block_size, (BS_ST_BIG_WRITE | BS_ST_STABLE), 0, clean_it->second.location))
|
||||
if (!fulfill_read(read_op, fulfilled, 0, block_size, (BS_ST_BIG_WRITE | BS_ST_STABLE), 0, clean_it->second.location))
|
||||
{
|
||||
// need to wait. undo added requests, don't dequeue op
|
||||
PRIV(read_op)->read_vec.clear();
|
||||
@@ -196,7 +196,7 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *read_op)
|
||||
else
|
||||
{
|
||||
uint8_t *clean_entry_bitmap = get_clean_entry_bitmap(clean_it->second.location, 0);
|
||||
uint64_t bmp_start = 0, bmp_end = 0, bmp_size = data_block_size/bitmap_granularity;
|
||||
uint64_t bmp_start = 0, bmp_end = 0, bmp_size = block_size/bitmap_granularity;
|
||||
while (bmp_start < bmp_size)
|
||||
{
|
||||
while (!(clean_entry_bitmap[bmp_end >> 3] & (1 << (bmp_end & 0x7))) && bmp_end < bmp_size)
|
||||
@@ -233,7 +233,7 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *read_op)
|
||||
else if (fulfilled < read_op->len)
|
||||
{
|
||||
// fill remaining parts with zeroes
|
||||
assert(fulfill_read(read_op, fulfilled, 0, data_block_size, (BS_ST_DELETE | BS_ST_STABLE), 0, 0));
|
||||
assert(fulfill_read(read_op, fulfilled, 0, block_size, (BS_ST_DELETE | BS_ST_STABLE), 0, 0));
|
||||
}
|
||||
assert(fulfilled == read_op->len);
|
||||
read_op->version = result_version;
|
||||
|
@@ -195,14 +195,14 @@ void blockstore_impl_t::mark_stable(const obj_ver_id & v, bool forget_dirty)
|
||||
}
|
||||
if (!exists)
|
||||
{
|
||||
inode_space_stats[dirty_it->first.oid.inode] += data_block_size;
|
||||
inode_space_stats[dirty_it->first.oid.inode] += block_size;
|
||||
}
|
||||
}
|
||||
else if (IS_DELETE(dirty_it->second.state))
|
||||
{
|
||||
auto & sp = inode_space_stats[dirty_it->first.oid.inode];
|
||||
if (sp > data_block_size)
|
||||
sp -= data_block_size;
|
||||
if (sp > block_size)
|
||||
sp -= block_size;
|
||||
else
|
||||
inode_space_stats.erase(dirty_it->first.oid.inode);
|
||||
}
|
||||
|
@@ -97,7 +97,7 @@ bool blockstore_impl_t::enqueue_write(blockstore_op_t *op)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (wait_big && !is_del && !deleted && op->len < data_block_size &&
|
||||
if (wait_big && !is_del && !deleted && op->len < block_size &&
|
||||
immediate_commit != IMMEDIATE_ALL)
|
||||
{
|
||||
// Issue an additional sync so that the previous big write can reach the journal
|
||||
@@ -122,7 +122,7 @@ bool blockstore_impl_t::enqueue_write(blockstore_op_t *op)
|
||||
state = BS_ST_DELETE | BS_ST_IN_FLIGHT;
|
||||
else
|
||||
{
|
||||
state = (op->len == data_block_size || deleted ? BS_ST_BIG_WRITE : BS_ST_SMALL_WRITE);
|
||||
state = (op->len == block_size || deleted ? BS_ST_BIG_WRITE : BS_ST_SMALL_WRITE);
|
||||
if (state == BS_ST_SMALL_WRITE && throttle_small_writes)
|
||||
clock_gettime(CLOCK_REALTIME, &PRIV(op)->tv_begin);
|
||||
if (wait_del)
|
||||
|
@@ -84,7 +84,7 @@ std::function<bool(cli_result_t &)> cli_tool_t::simple_offsets(json11::Json cfg)
|
||||
fprintf(stderr, "Invalid device block size specified: %lu\n", device_block_size);
|
||||
exit(1);
|
||||
}
|
||||
if (object_size < device_block_size || object_size > MAX_DATA_BLOCK_SIZE ||
|
||||
if (object_size < device_block_size || object_size > MAX_BLOCK_SIZE ||
|
||||
object_size & (object_size-1) != 0)
|
||||
{
|
||||
fprintf(stderr, "Invalid object size specified: %lu\n", object_size);
|
||||
|
@@ -296,7 +296,7 @@ void cluster_client_t::on_load_config_hook(json11::Json::object & config)
|
||||
}
|
||||
bs_bitmap_size = bs_block_size / bs_bitmap_granularity / 8;
|
||||
uint32_t block_order;
|
||||
if ((block_order = is_power_of_two(bs_block_size)) >= 64 || bs_block_size < MIN_DATA_BLOCK_SIZE || bs_block_size >= MAX_DATA_BLOCK_SIZE)
|
||||
if ((block_order = is_power_of_two(bs_block_size)) >= 64 || bs_block_size < MIN_BLOCK_SIZE || bs_block_size >= MAX_BLOCK_SIZE)
|
||||
{
|
||||
throw std::runtime_error("Bad block size");
|
||||
}
|
||||
|
@@ -6,8 +6,8 @@
|
||||
#include "messenger.h"
|
||||
#include "etcd_state_client.h"
|
||||
|
||||
#define MIN_DATA_BLOCK_SIZE 4*1024
|
||||
#define MAX_DATA_BLOCK_SIZE 128*1024*1024
|
||||
#define MIN_BLOCK_SIZE 4*1024
|
||||
#define MAX_BLOCK_SIZE 128*1024*1024
|
||||
#define DEFAULT_CLIENT_MAX_DIRTY_BYTES 32*1024*1024
|
||||
#define DEFAULT_CLIENT_MAX_DIRTY_OPS 1024
|
||||
#define INODE_LIST_DONE 1
|
||||
|
@@ -1,944 +0,0 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blockstore_impl.h"
|
||||
#include "osd_id.h"
|
||||
#include "crc32c.h"
|
||||
#include "rw_blocking.h"
|
||||
|
||||
#define DM_ST_EMPTY 0
|
||||
#define DM_ST_TO_READ 1
|
||||
#define DM_ST_READING 2
|
||||
#define DM_ST_TO_WRITE 3
|
||||
#define DM_ST_WRITING 4
|
||||
|
||||
struct resizer_data_moving_t
|
||||
{
|
||||
int state = 0;
|
||||
void *buf = NULL;
|
||||
uint64_t old_loc, new_loc;
|
||||
};
|
||||
|
||||
struct disk_tool_t
|
||||
{
|
||||
/**** Parameters ****/
|
||||
|
||||
std::map<std::string, std::string> options;
|
||||
|
||||
std::string journal_device;
|
||||
uint32_t journal_block_size;
|
||||
uint64_t journal_offset;
|
||||
uint64_t journal_len;
|
||||
bool all;
|
||||
|
||||
std::string meta_device;
|
||||
uint32_t meta_block_size;
|
||||
uint64_t meta_offset;
|
||||
uint64_t meta_len;
|
||||
uint64_t meta_pos;
|
||||
|
||||
std::string data_device;
|
||||
uint64_t data_offset;
|
||||
uint64_t data_len;
|
||||
uint64_t data_block_size;
|
||||
|
||||
uint64_t clean_entry_bitmap_size, clean_entry_size;
|
||||
uint32_t bitmap_granularity;
|
||||
|
||||
// resize data and/or move metadata and journal
|
||||
int iodepth;
|
||||
char *new_meta_device, *new_journal_device;
|
||||
uint64_t new_data_offset, new_data_len;
|
||||
uint64_t new_journal_offset, new_journal_len;
|
||||
uint64_t new_meta_offset, new_meta_len;
|
||||
|
||||
/**** State ****/
|
||||
|
||||
uint64_t journal_pos, journal_calc_data_pos;
|
||||
|
||||
int journal_fd, meta_fd;
|
||||
bool first;
|
||||
|
||||
int data_fd;
|
||||
allocator *data_alloc;
|
||||
std::map<uint64_t, uint64_t> data_remap;
|
||||
std::map<uint64_t, uint64_t>::iterator remap_it;
|
||||
ring_loop_t *ringloop;
|
||||
ring_consumer_t ring_consumer;
|
||||
int remap_active;
|
||||
uint8_t *new_buf, *new_journal_ptr, *new_journal_data;
|
||||
uint64_t new_journal_in_pos;
|
||||
int64_t data_idx_diff;
|
||||
uint64_t total_blocks, free_first, free_last;
|
||||
uint64_t new_clean_entry_bitmap_size, new_clean_entry_size, new_entries_per_block;
|
||||
int new_journal_fd, new_meta_fd;
|
||||
resizer_data_moving_t *moving_blocks;
|
||||
|
||||
bool started;
|
||||
void *small_write_data;
|
||||
uint32_t data_crc32;
|
||||
uint32_t crc32_last;
|
||||
uint32_t new_crc32_prev;
|
||||
|
||||
/**** Commands ****/
|
||||
|
||||
int dump_journal();
|
||||
int dump_meta();
|
||||
int resize_data();
|
||||
|
||||
/**** Methods ****/
|
||||
|
||||
void dump_journal_entry(int num, journal_entry *je);
|
||||
int process_journal(std::function<int(void*)> block_fn);
|
||||
int process_journal_block(void *buf, std::function<void(int, journal_entry*)> iter_fn);
|
||||
int process_meta(std::function<void(blockstore_meta_header_v1_t *)> hdr_fn,
|
||||
std::function<void(uint64_t, clean_disk_entry*, uint8_t*)> record_fn);
|
||||
void dump_meta_header(blockstore_meta_header_v1_t *hdr);
|
||||
void dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap);
|
||||
|
||||
void resize_init(blockstore_meta_header_v1_t *hdr);
|
||||
int resize_remap_blocks();
|
||||
int resize_copy_data();
|
||||
int resize_rewrite_journal();
|
||||
int resize_rewrite_meta();
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
disk_tool_t self = {};
|
||||
std::vector<char*> cmd;
|
||||
char *exe_name = strrchr(argv[0], '/');
|
||||
exe_name = exe_name ? exe_name+1 : argv[0];
|
||||
bool aliased = false;
|
||||
if (!strcmp(exe_name, "vitastor-dump-journal"))
|
||||
{
|
||||
cmd.push_back((char*)"dump-journal");
|
||||
aliased = true;
|
||||
}
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (!strcmp(argv[i], "--all"))
|
||||
{
|
||||
self.all = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--help"))
|
||||
{
|
||||
cmd.clear();
|
||||
cmd.push_back((char*)"help");
|
||||
}
|
||||
else if (argv[i][0] == '-' && argv[i][1] == '-')
|
||||
{
|
||||
char *key = argv[i]+2;
|
||||
self.options[key] = argv[++i];
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
if (cmd.size() && !strcmp(cmd[0], "dump-journal"))
|
||||
{
|
||||
if (cmd.size() < 5)
|
||||
{
|
||||
fprintf(stderr, "USAGE: %s%s [--all] <journal_file> <journal_block_size> <offset> <size>\n", argv[0], aliased ? "" : " dump-journal");
|
||||
return 1;
|
||||
}
|
||||
self.journal_device = cmd[1];
|
||||
self.journal_block_size = strtoul(cmd[2], NULL, 10);
|
||||
self.journal_offset = strtoull(cmd[3], NULL, 10);
|
||||
self.journal_len = strtoull(cmd[4], NULL, 10);
|
||||
return self.dump_journal();
|
||||
}
|
||||
else if (cmd.size() && !strcmp(cmd[0], "dump-meta"))
|
||||
{
|
||||
if (cmd.size() < 5)
|
||||
{
|
||||
fprintf(stderr, "USAGE: %s dump-meta <meta_file> <meta_block_size> <offset> <size>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
self.meta_device = cmd[1];
|
||||
self.meta_block_size = strtoul(cmd[2], NULL, 10);
|
||||
self.meta_offset = strtoull(cmd[3], NULL, 10);
|
||||
self.meta_len = strtoull(cmd[4], NULL, 10);
|
||||
return self.dump_meta();
|
||||
}
|
||||
else if (cmd.size() && !strcmp(cmd[0], "resize"))
|
||||
{
|
||||
return self.resize_data();
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(
|
||||
"USAGE:\n"
|
||||
" %s dump-journal [--all] <journal_file> <journal_block_size> <offset> <size>\n"
|
||||
" %s dump-meta <meta_file> <meta_block_size> <offset> <size>\n"
|
||||
,
|
||||
argv[0], argv[0]
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::dump_journal()
|
||||
{
|
||||
if (journal_block_size < DIRECT_IO_ALIGNMENT || (journal_block_size % DIRECT_IO_ALIGNMENT) ||
|
||||
journal_block_size > 128*1024)
|
||||
{
|
||||
fprintf(stderr, "Invalid journal block size\n");
|
||||
return 1;
|
||||
}
|
||||
journal_fd = open(journal_device.c_str(), O_DIRECT|O_RDONLY);
|
||||
if (journal_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open journal device %s: %s\n", journal_device.c_str(), strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (all)
|
||||
{
|
||||
void *journal_buf = memalign_or_die(MEM_ALIGNMENT, journal_block_size);
|
||||
journal_pos = 0;
|
||||
while (journal_pos < journal_len)
|
||||
{
|
||||
int r = pread(journal_fd, journal_buf, journal_block_size, journal_offset+journal_pos);
|
||||
assert(r == journal_block_size);
|
||||
uint64_t s;
|
||||
for (s = 0; s < journal_block_size; s += 8)
|
||||
{
|
||||
if (*((uint64_t*)((uint8_t*)journal_buf+s)) != 0)
|
||||
break;
|
||||
}
|
||||
if (s == journal_block_size)
|
||||
{
|
||||
printf("offset %08lx: zeroes\n", journal_pos);
|
||||
journal_pos += journal_block_size;
|
||||
}
|
||||
else if (((journal_entry*)journal_buf)->magic == JOURNAL_MAGIC)
|
||||
{
|
||||
printf("offset %08lx:\n", journal_pos);
|
||||
process_journal_block(journal_buf, [this](int num, journal_entry *je) { dump_journal_entry(num, je); });
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("offset %08lx: no magic in the beginning, looks like random data (pattern=%lx)\n", journal_pos, *((uint64_t*)journal_buf));
|
||||
journal_pos += journal_block_size;
|
||||
}
|
||||
}
|
||||
free(journal_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
process_journal([this](void *data)
|
||||
{
|
||||
printf("offset %08lx:\n", journal_pos);
|
||||
int r = process_journal_block(data, [this](int num, journal_entry *je) { dump_journal_entry(num, je); });
|
||||
if (r <= 0)
|
||||
printf("end of the journal\n");
|
||||
return r;
|
||||
});
|
||||
}
|
||||
close(journal_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::process_journal(std::function<int(void*)> block_fn)
|
||||
{
|
||||
void *data = memalign_or_die(MEM_ALIGNMENT, journal_block_size);
|
||||
journal_pos = 0;
|
||||
int r = pread(journal_fd, data, journal_block_size, journal_offset+journal_pos);
|
||||
assert(r == journal_block_size);
|
||||
journal_entry *je = (journal_entry*)(data);
|
||||
if (je->magic != JOURNAL_MAGIC || je->type != JE_START || je_crc32(je) != je->crc32)
|
||||
{
|
||||
fprintf(stderr, "offset %08lx: journal superblock is invalid\n", journal_pos);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
block_fn(data);
|
||||
started = false;
|
||||
journal_pos = je->start.journal_start;
|
||||
while (1)
|
||||
{
|
||||
if (journal_pos >= journal_len)
|
||||
journal_pos = journal_block_size;
|
||||
r = pread(journal_fd, data, journal_block_size, journal_offset+journal_pos);
|
||||
assert(r == journal_block_size);
|
||||
r = block_fn(data);
|
||||
if (r <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::process_journal_block(void *buf, std::function<void(int, journal_entry*)> iter_fn)
|
||||
{
|
||||
uint32_t pos = 0;
|
||||
journal_pos += journal_block_size;
|
||||
int entry = 0;
|
||||
bool wrapped = false;
|
||||
while (pos < journal_block_size)
|
||||
{
|
||||
journal_entry *je = (journal_entry*)((uint8_t*)buf + pos);
|
||||
if (je->magic != JOURNAL_MAGIC || je->type < JE_MIN || je->type > JE_MAX ||
|
||||
!all && started && je->crc32_prev != crc32_last)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bool crc32_valid = je_crc32(je) == je->crc32;
|
||||
if (!all && !crc32_valid)
|
||||
{
|
||||
break;
|
||||
}
|
||||
started = true;
|
||||
crc32_last = je->crc32;
|
||||
if (je->type == JE_SMALL_WRITE || je->type == JE_SMALL_WRITE_INSTANT)
|
||||
{
|
||||
journal_calc_data_pos = journal_pos;
|
||||
if (journal_pos + je->small_write.len > journal_len)
|
||||
{
|
||||
// data continues from the beginning of the journal
|
||||
journal_calc_data_pos = journal_pos = journal_block_size;
|
||||
wrapped = true;
|
||||
}
|
||||
journal_pos += je->small_write.len;
|
||||
if (journal_pos >= journal_len)
|
||||
{
|
||||
journal_pos = journal_block_size;
|
||||
wrapped = true;
|
||||
}
|
||||
small_write_data = memalign_or_die(MEM_ALIGNMENT, je->small_write.len);
|
||||
assert(pread(journal_fd, small_write_data, je->small_write.len, journal_offset+je->small_write.data_offset) == je->small_write.len);
|
||||
data_crc32 = crc32c(0, small_write_data, je->small_write.len);
|
||||
}
|
||||
iter_fn(entry, je);
|
||||
if (je->type == JE_SMALL_WRITE || je->type == JE_SMALL_WRITE_INSTANT)
|
||||
{
|
||||
free(small_write_data);
|
||||
small_write_data = NULL;
|
||||
}
|
||||
pos += je->size;
|
||||
entry++;
|
||||
}
|
||||
if (wrapped)
|
||||
{
|
||||
journal_pos = journal_len;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_journal_entry(int num, journal_entry *je)
|
||||
{
|
||||
printf("entry % 3d: crc32=%08x %s prev=%08x ", num, je->crc32, (je_crc32(je) == je->crc32 ? "(valid)" : "(invalid)"), je->crc32_prev);
|
||||
if (je->type == JE_START)
|
||||
{
|
||||
printf("je_start start=%08lx\n", je->start.journal_start);
|
||||
}
|
||||
else if (je->type == JE_SMALL_WRITE || je->type == JE_SMALL_WRITE_INSTANT)
|
||||
{
|
||||
printf(
|
||||
"je_small_write%s oid=%lx:%lx ver=%lu offset=%u len=%u loc=%08lx",
|
||||
je->type == JE_SMALL_WRITE_INSTANT ? "_instant" : "",
|
||||
je->small_write.oid.inode, je->small_write.oid.stripe,
|
||||
je->small_write.version, je->small_write.offset, je->small_write.len,
|
||||
je->small_write.data_offset
|
||||
);
|
||||
if (journal_calc_data_pos != je->small_write.data_offset)
|
||||
{
|
||||
printf(" (mismatched, calculated = %lu)", journal_pos);
|
||||
}
|
||||
printf(
|
||||
" data_crc32=%08x%s", je->small_write.crc32_data,
|
||||
(data_crc32 != je->small_write.crc32_data) ? " (invalid)" : " (valid)"
|
||||
);
|
||||
printf("\n");
|
||||
}
|
||||
else if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
|
||||
{
|
||||
printf(
|
||||
"je_big_write%s oid=%lx:%lx ver=%lu loc=%08lx\n",
|
||||
je->type == JE_BIG_WRITE_INSTANT ? "_instant" : "",
|
||||
je->big_write.oid.inode, je->big_write.oid.stripe, je->big_write.version, je->big_write.location
|
||||
);
|
||||
}
|
||||
else if (je->type == JE_STABLE)
|
||||
{
|
||||
printf("je_stable oid=%lx:%lx ver=%lu\n", je->stable.oid.inode, je->stable.oid.stripe, je->stable.version);
|
||||
}
|
||||
else if (je->type == JE_ROLLBACK)
|
||||
{
|
||||
printf("je_rollback oid=%lx:%lx ver=%lu\n", je->rollback.oid.inode, je->rollback.oid.stripe, je->rollback.version);
|
||||
}
|
||||
else if (je->type == JE_DELETE)
|
||||
{
|
||||
printf("je_delete oid=%lx:%lx ver=%lu\n", je->del.oid.inode, je->del.oid.stripe, je->del.version);
|
||||
}
|
||||
}
|
||||
|
||||
int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v1_t *)> hdr_fn,
|
||||
std::function<void(uint64_t, clean_disk_entry*, uint8_t*)> record_fn)
|
||||
{
|
||||
if (meta_block_size % DIRECT_IO_ALIGNMENT)
|
||||
{
|
||||
fprintf(stderr, "Invalid metadata block size: is not a multiple of %d\n", DIRECT_IO_ALIGNMENT);
|
||||
return 1;
|
||||
}
|
||||
meta_fd = open(meta_device.c_str(), O_DIRECT|O_RDONLY);
|
||||
if (meta_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open metadata device %s: %s\n", meta_device.c_str(), strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
int buf_size = 1024*1024;
|
||||
if (buf_size % meta_block_size)
|
||||
buf_size = 8*meta_block_size;
|
||||
if (buf_size > meta_len)
|
||||
buf_size = meta_len;
|
||||
void *data = memalign_or_die(MEM_ALIGNMENT, buf_size);
|
||||
lseek64(meta_fd, meta_offset, 0);
|
||||
read_blocking(meta_fd, data, buf_size);
|
||||
// Check superblock
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)data;
|
||||
if (hdr->zero == 0 &&
|
||||
hdr->magic == BLOCKSTORE_META_MAGIC_V1 &&
|
||||
hdr->version == BLOCKSTORE_META_VERSION_V1)
|
||||
{
|
||||
// Vitastor 0.6-0.7 - static array of clean_disk_entry with bitmaps
|
||||
if (hdr->meta_block_size != meta_block_size)
|
||||
{
|
||||
fprintf(stderr, "Using block size of %u bytes based on information from the superblock\n", hdr->meta_block_size);
|
||||
meta_block_size = hdr->meta_block_size;
|
||||
if (buf_size % meta_block_size)
|
||||
{
|
||||
buf_size = 8*meta_block_size;
|
||||
free(data);
|
||||
data = memalign_or_die(MEM_ALIGNMENT, buf_size);
|
||||
}
|
||||
}
|
||||
bitmap_granularity = hdr->bitmap_granularity;
|
||||
clean_entry_bitmap_size = hdr->data_block_size / hdr->bitmap_granularity / 8;
|
||||
clean_entry_size = sizeof(clean_disk_entry) + 2*clean_entry_bitmap_size;
|
||||
uint64_t block_num = 0;
|
||||
hdr_fn(hdr);
|
||||
meta_pos = meta_block_size;
|
||||
lseek64(meta_fd, meta_offset+meta_pos, 0);
|
||||
while (meta_pos < meta_len)
|
||||
{
|
||||
uint64_t read_len = buf_size < meta_len-meta_pos ? buf_size : meta_len-meta_pos;
|
||||
read_blocking(meta_fd, data, read_len);
|
||||
meta_pos += read_len;
|
||||
for (uint64_t blk = 0; blk < read_len; blk += meta_block_size)
|
||||
{
|
||||
for (uint64_t ioff = 0; ioff < meta_block_size-clean_entry_size; ioff += clean_entry_size, block_num++)
|
||||
{
|
||||
clean_disk_entry *entry = (clean_disk_entry*)(data + blk + ioff);
|
||||
if (entry->oid.inode)
|
||||
{
|
||||
record_fn(block_num, entry, entry->bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vitastor 0.4-0.5 - static array of clean_disk_entry
|
||||
clean_entry_bitmap_size = 0;
|
||||
clean_entry_size = sizeof(clean_disk_entry);
|
||||
uint64_t block_num = 0;
|
||||
hdr_fn(NULL);
|
||||
while (meta_pos < meta_len)
|
||||
{
|
||||
uint64_t read_len = buf_size < meta_len-meta_pos ? buf_size : meta_len-meta_pos;
|
||||
read_blocking(meta_fd, data, read_len);
|
||||
meta_pos += read_len;
|
||||
for (uint64_t blk = 0; blk < read_len; blk += meta_block_size)
|
||||
{
|
||||
for (uint64_t ioff = 0; ioff < meta_block_size-clean_entry_size; ioff += clean_entry_size, block_num++)
|
||||
{
|
||||
clean_disk_entry *entry = (clean_disk_entry*)(data + blk + ioff);
|
||||
if (entry->oid.inode)
|
||||
{
|
||||
record_fn(block_num, entry, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
close(meta_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::dump_meta()
|
||||
{
|
||||
int r = process_meta(
|
||||
[this](blockstore_meta_header_v1_t *hdr) { dump_meta_header(hdr); },
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap) { dump_meta_entry(block_num, entry, bitmap); }
|
||||
);
|
||||
printf("\n]}\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_meta_header(blockstore_meta_header_v1_t *hdr)
|
||||
{
|
||||
if (hdr)
|
||||
{
|
||||
printf(
|
||||
"{\"version\":\"0.6\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,\"entries\":[\n",
|
||||
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("{\"version\":\"0.5\",\"meta_block_size\":%u,\"entries\":[\n", meta_block_size);
|
||||
}
|
||||
first = true;
|
||||
}
|
||||
|
||||
void disk_tool_t::dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"block\":%lu,\"pool\":%u,\"inode\":%lu,\"stripe\":%lu,\"version\":%lu"
|
||||
(first ? ENTRY_FMT : (",\n" ENTRY_FMT)),
|
||||
#undef ENTRY_FMT
|
||||
block_num, INODE_POOL(entry->oid.inode), INODE_NO_POOL(entry->oid.inode),
|
||||
entry->oid.stripe, entry->version
|
||||
);
|
||||
if (bitmap)
|
||||
{
|
||||
printf(",\"bitmap\":\"");
|
||||
for (uint64_t i = 0; i < clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", bitmap[i]);
|
||||
}
|
||||
printf("\",\"ext_bitmap\":\"");
|
||||
for (uint64_t i = 0; i < clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", bitmap[clean_entry_bitmap_size + i]);
|
||||
}
|
||||
printf("\"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("}");
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_data()
|
||||
{
|
||||
int r;
|
||||
// Parse parameters
|
||||
r = resize_parse_params();
|
||||
if (r != 0)
|
||||
return r;
|
||||
// Check parameters and fill allocator
|
||||
r = process_meta(
|
||||
[this](blockstore_meta_header_v1_t *hdr)
|
||||
{
|
||||
resize_init(hdr);
|
||||
},
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
data_alloc->set(block_num, true);
|
||||
}
|
||||
);
|
||||
if (r != 0)
|
||||
return r;
|
||||
r = process_journal([this](void *buf)
|
||||
{
|
||||
return process_journal_block(buf, [this](int num, journal_entry *je)
|
||||
{
|
||||
if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
|
||||
{
|
||||
data_alloc->set(je->big_write.location / data_block_size, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (r != 0)
|
||||
return r;
|
||||
// Remap blocks
|
||||
r = resize_remap_blocks();
|
||||
if (r != 0)
|
||||
return r;
|
||||
// Copy data blocks into new places
|
||||
r = resize_copy_data();
|
||||
if (r != 0)
|
||||
return r;
|
||||
// Rewrite journal
|
||||
r = resize_rewrite_journal();
|
||||
if (r != 0)
|
||||
return r;
|
||||
// Rewrite metadata
|
||||
r = resize_rewrite_meta();
|
||||
if (r != 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_parse_params()
|
||||
{
|
||||
auto & config = options;
|
||||
// FIXME: Deduplicate with blockstore_open.cpp !
|
||||
journal_len = strtoull(config["journal_size"].c_str(), NULL, 10);
|
||||
data_device = config["data_device"];
|
||||
data_offset = strtoull(config["data_offset"].c_str(), NULL, 10);
|
||||
data_len = strtoull(config["data_size"].c_str(), NULL, 10);
|
||||
meta_device = config["meta_device"];
|
||||
meta_offset = strtoull(config["meta_offset"].c_str(), NULL, 10);
|
||||
data_block_size = strtoull(config["block_size"].c_str(), NULL, 10);
|
||||
journal_device = config["journal_device"];
|
||||
journal_offset = strtoull(config["journal_offset"].c_str(), NULL, 10);
|
||||
journal_block_size = strtoull(config["journal_block_size"].c_str(), NULL, 10);
|
||||
meta_block_size = strtoull(config["meta_block_size"].c_str(), NULL, 10);
|
||||
iodepth = strtoull(config["iodepth"].c_str(), NULL, 10);
|
||||
// Validate
|
||||
if (!data_block_size)
|
||||
data_block_size = (1 << DEFAULT_ORDER);
|
||||
if (data_block_size < MIN_BLOCK_SIZE || data_block_size >= MAX_BLOCK_SIZE)
|
||||
throw std::runtime_error("Bad block size");
|
||||
if (!journal_block_size)
|
||||
journal_block_size = 4096;
|
||||
else if (journal_block_size % DIRECT_IO_ALIGNMENT)
|
||||
throw std::runtime_error("journal_block_size must be a multiple of "+std::to_string(DIRECT_IO_ALIGNMENT));
|
||||
if (!meta_block_size)
|
||||
meta_block_size = 4096;
|
||||
else if (meta_block_size % DIRECT_IO_ALIGNMENT)
|
||||
throw std::runtime_error("meta_block_size must be a multiple of "+std::to_string(DIRECT_IO_ALIGNMENT));
|
||||
if (journal_device == meta_device || meta_device == "" && journal_device == data_device)
|
||||
journal_device = "";
|
||||
if (meta_device == data_device)
|
||||
meta_device = "";
|
||||
if (meta_offset % meta_block_size)
|
||||
throw std::runtime_error("meta_offset must be a multiple of meta_block_size = "+std::to_string(meta_block_size));
|
||||
if (journal_offset % journal_block_size)
|
||||
throw std::runtime_error("journal_offset must be a multiple of journal_block_size = "+std::to_string(journal_block_size));
|
||||
if (!iodepth)
|
||||
iodepth = 32;
|
||||
// Check offsets
|
||||
|
||||
}
|
||||
|
||||
void disk_tool_t::resize_init(blockstore_meta_header_v1_t *hdr)
|
||||
{
|
||||
if (hdr && data_block_size != hdr->data_block_size)
|
||||
{
|
||||
if (data_block_size)
|
||||
{
|
||||
fprintf(stderr, "Using data block size of %u bytes from metadata superblock\n", hdr->data_block_size);
|
||||
}
|
||||
data_block_size = hdr->data_block_size;
|
||||
}
|
||||
if (((new_data_len-data_len) % data_block_size) ||
|
||||
((new_data_offset-data_offset) % data_block_size))
|
||||
{
|
||||
fprintf(stderr, "Data alignment mismatch\n");
|
||||
exit(1);
|
||||
}
|
||||
data_idx_diff = (new_data_offset-data_offset) / data_block_size;
|
||||
free_first = new_data_offset > data_offset ? data_idx_diff : 0;
|
||||
free_last = (new_data_offset+new_data_len < data_offset+data_len)
|
||||
? (data_offset+data_len-new_data_offset-new_data_len) / data_block_size
|
||||
: 0;
|
||||
new_clean_entry_bitmap_size = data_block_size / (hdr ? hdr->bitmap_granularity : 4096) / 8;
|
||||
new_clean_entry_size = sizeof(clean_disk_entry) + 2 * new_clean_entry_bitmap_size;
|
||||
new_entries_per_block = meta_block_size/new_clean_entry_size;
|
||||
uint64_t new_meta_blocks = 1 + (new_data_len/data_block_size + new_entries_per_block-1) / new_entries_per_block;
|
||||
if (new_meta_len < meta_block_size*new_meta_blocks)
|
||||
{
|
||||
fprintf(stderr, "New metadata area size is too small, should be at least %lu bytes\n", meta_block_size*new_meta_blocks);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_remap_blocks()
|
||||
{
|
||||
total_blocks = data_len / data_block_size;
|
||||
for (uint64_t i = 0; i < free_first; i++)
|
||||
{
|
||||
if (data_alloc->get(i))
|
||||
data_remap[i] = 0;
|
||||
else
|
||||
data_alloc->set(i, true);
|
||||
}
|
||||
for (uint64_t i = 0; i < free_last; i++)
|
||||
{
|
||||
if (data_alloc->get(total_blocks-i))
|
||||
data_remap[total_blocks-i] = 0;
|
||||
else
|
||||
data_alloc->set(total_blocks-i, true);
|
||||
}
|
||||
for (auto & p: data_remap)
|
||||
{
|
||||
uint64_t new_loc = data_alloc->find_free();
|
||||
if (new_loc == UINT64_MAX)
|
||||
{
|
||||
fprintf(stderr, "Not enough space to move data\n");
|
||||
return 1;
|
||||
}
|
||||
data_remap[p.first] = new_loc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_copy_data()
|
||||
{
|
||||
if (iodepth <= 0 || iodepth > 4096)
|
||||
{
|
||||
iodepth = 32;
|
||||
}
|
||||
ringloop = new ring_loop_t(iodepth < 512 ? 512 : iodepth);
|
||||
data_fd = open(data_device.c_str(), O_DIRECT|O_RDWR);
|
||||
if (data_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open data device %s: %s\n", data_device.c_str(), strerror(errno));
|
||||
delete ringloop;
|
||||
return 1;
|
||||
}
|
||||
moving_blocks = new resizer_data_moving_t[iodepth];
|
||||
moving_blocks[0].buf = memalign_or_die(MEM_ALIGNMENT, iodepth*data_block_size);
|
||||
for (int i = 1; i < iodepth; i++)
|
||||
{
|
||||
moving_blocks[i].buf = moving_blocks[0].buf + i*data_block_size;
|
||||
}
|
||||
remap_active = 1;
|
||||
remap_it = data_remap.begin();
|
||||
ring_consumer.loop = [this]()
|
||||
{
|
||||
remap_active = 0;
|
||||
for (int i = 0; i < iodepth; i++)
|
||||
{
|
||||
if (moving_blocks[i].state == DM_ST_EMPTY && remap_it != data_remap.end())
|
||||
{
|
||||
uint64_t old_loc = remap_it->first, new_loc = remap_it->second;
|
||||
moving_blocks[i].state = DM_ST_TO_READ;
|
||||
moving_blocks[i].old_loc = old_loc;
|
||||
moving_blocks[i].new_loc = new_loc;
|
||||
remap_it++;
|
||||
}
|
||||
if (moving_blocks[i].state == DM_ST_TO_READ)
|
||||
{
|
||||
struct io_uring_sqe *sqe = ringloop->get_sqe();
|
||||
if (sqe)
|
||||
{
|
||||
moving_blocks[i].state = DM_ST_READING;
|
||||
struct ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
||||
data->iov = (struct iovec){ moving_blocks[i].buf, data_block_size };
|
||||
my_uring_prep_readv(sqe, data_fd, &data->iov, 1, data_offset + moving_blocks[i].old_loc*data_block_size);
|
||||
data->callback = [this, i](ring_data_t *data)
|
||||
{
|
||||
if (data->res != data_block_size)
|
||||
{
|
||||
fprintf(
|
||||
stderr, "Failed to read %lu bytes at %lu from %s: %s\n", data_block_size,
|
||||
data_offset + moving_blocks[i].old_loc*data_block_size, data_device.c_str(),
|
||||
data->res < 0 ? strerror(-data->res) : "short read"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
moving_blocks[i].state = DM_ST_TO_WRITE;
|
||||
ringloop->wakeup();
|
||||
};
|
||||
}
|
||||
}
|
||||
if (moving_blocks[i].state == DM_ST_TO_WRITE)
|
||||
{
|
||||
struct io_uring_sqe *sqe = ringloop->get_sqe();
|
||||
if (sqe)
|
||||
{
|
||||
moving_blocks[i].state = DM_ST_WRITING;
|
||||
struct ring_data_t *data = ((ring_data_t*)sqe->user_data);
|
||||
data->iov = (struct iovec){ moving_blocks[i].buf, data_block_size };
|
||||
my_uring_prep_writev(sqe, data_fd, &data->iov, 1, data_offset + moving_blocks[i].new_loc*data_block_size);
|
||||
data->callback = [this, i](ring_data_t *data)
|
||||
{
|
||||
if (data->res != data_block_size)
|
||||
{
|
||||
fprintf(
|
||||
stderr, "Failed to write %lu bytes at %lu to %s: %s\n", data_block_size,
|
||||
data_offset + moving_blocks[i].new_loc*data_block_size, data_device.c_str(),
|
||||
data->res < 0 ? strerror(-data->res) : "short write"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
moving_blocks[i].state = DM_ST_EMPTY;
|
||||
ringloop->wakeup();
|
||||
};
|
||||
}
|
||||
}
|
||||
remap_active += moving_blocks[i].state != DM_ST_EMPTY ? 1 : 0;
|
||||
}
|
||||
ringloop->submit();
|
||||
};
|
||||
ringloop->register_consumer(&ring_consumer);
|
||||
while (1)
|
||||
{
|
||||
ringloop->loop();
|
||||
if (!remap_active)
|
||||
break;
|
||||
ringloop->wait();
|
||||
}
|
||||
ringloop->unregister_consumer(&ring_consumer);
|
||||
free(moving_blocks[0].buf);
|
||||
delete[] moving_blocks;
|
||||
close(data_fd);
|
||||
delete ringloop;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_rewrite_journal()
|
||||
{
|
||||
// Simply overwriting on the fly may be impossible because old and new areas may overlap
|
||||
// For now, just build new journal data in memory
|
||||
new_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_journal_len);
|
||||
new_journal_ptr = new_buf;
|
||||
new_journal_data = new_journal_ptr + journal_block_size;
|
||||
memset(new_buf, 0, new_journal_len);
|
||||
process_journal([this](void *buf)
|
||||
{
|
||||
return process_journal_block(buf, [this](int num, journal_entry *je)
|
||||
{
|
||||
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
|
||||
if (je->type == JE_START)
|
||||
{
|
||||
*((journal_entry_start*)ne) = (journal_entry_start){
|
||||
.magic = JOURNAL_MAGIC,
|
||||
.type = JE_START,
|
||||
.size = sizeof(ne->start),
|
||||
.journal_start = journal_block_size,
|
||||
.version = JOURNAL_VERSION,
|
||||
};
|
||||
ne->crc32 = je_crc32(ne);
|
||||
new_journal_ptr += journal_block_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (journal_block_size < new_journal_in_pos+je->size)
|
||||
{
|
||||
new_journal_ptr = new_journal_data;
|
||||
if (new_journal_ptr-new_buf >= new_journal_len)
|
||||
{
|
||||
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
|
||||
exit(1);
|
||||
}
|
||||
new_journal_data += journal_block_size;
|
||||
new_journal_in_pos = 0;
|
||||
if (journal_block_size < je->size)
|
||||
{
|
||||
fprintf(stderr, "Error: journal entry too large (%u bytes)\n", je->size);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
memcpy(ne, je, je->size);
|
||||
ne->crc32_prev = new_crc32_prev;
|
||||
if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
|
||||
{
|
||||
// Change the block reference
|
||||
auto remap_it = data_remap.find(ne->big_write.location / data_block_size);
|
||||
if (remap_it != data_remap.end())
|
||||
{
|
||||
ne->big_write.location = remap_it->second * data_block_size;
|
||||
}
|
||||
ne->big_write.location += data_idx_diff;
|
||||
}
|
||||
else if (je->type == JE_SMALL_WRITE || je->type == JE_SMALL_WRITE_INSTANT)
|
||||
{
|
||||
ne->small_write.data_offset = new_journal_data-new_buf;
|
||||
if (ne->small_write.data_offset + ne->small_write.len > new_journal_len)
|
||||
{
|
||||
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(new_journal_data, small_write_data, ne->small_write.len);
|
||||
new_journal_data += ne->small_write.len;
|
||||
}
|
||||
ne->crc32 = je_crc32(ne);
|
||||
new_journal_in_pos += ne->size;
|
||||
new_crc32_prev = ne->crc32;
|
||||
}
|
||||
});
|
||||
});
|
||||
// FIXME: Write new journal and metadata with journaling if they overlap with old
|
||||
new_journal_fd = open(new_journal_device, O_DIRECT|O_RDWR);
|
||||
if (new_journal_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open new journal device %s: %s\n", new_journal_device, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
lseek64(new_journal_fd, new_journal_offset, 0);
|
||||
write_blocking(new_journal_fd, new_buf, new_journal_len);
|
||||
fsync(new_journal_fd);
|
||||
close(new_journal_fd);
|
||||
free(new_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_tool_t::resize_rewrite_meta()
|
||||
{
|
||||
new_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
|
||||
memset(new_buf, 0, new_meta_len);
|
||||
int r = process_meta(
|
||||
[this](blockstore_meta_header_v1_t *hdr)
|
||||
{
|
||||
blockstore_meta_header_v1_t *new_hdr = (blockstore_meta_header_v1_t *)new_buf;
|
||||
new_hdr->zero = 0;
|
||||
new_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
|
||||
new_hdr->version = BLOCKSTORE_META_VERSION_V1;
|
||||
new_hdr->meta_block_size = meta_block_size;
|
||||
new_hdr->data_block_size = data_block_size;
|
||||
new_hdr->bitmap_granularity = bitmap_granularity ? bitmap_granularity : 4096;
|
||||
},
|
||||
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
|
||||
{
|
||||
auto remap_it = data_remap.find(block_num);
|
||||
if (remap_it != data_remap.end())
|
||||
block_num = remap_it->second;
|
||||
if (block_num < free_first || block_num >= total_blocks-free_last)
|
||||
return;
|
||||
block_num += data_idx_diff;
|
||||
clean_disk_entry *new_entry = (clean_disk_entry*)(new_buf + meta_block_size +
|
||||
meta_block_size*(block_num / new_entries_per_block) +
|
||||
new_clean_entry_size*(block_num % new_entries_per_block));
|
||||
new_entry->oid = entry->oid;
|
||||
new_entry->version = entry->version;
|
||||
if (bitmap)
|
||||
memcpy(new_entry->bitmap, bitmap, 2*new_clean_entry_bitmap_size);
|
||||
else
|
||||
memset(new_entry->bitmap, 0xff, 2*new_clean_entry_bitmap_size);
|
||||
}
|
||||
);
|
||||
if (r != 0)
|
||||
{
|
||||
free(new_buf);
|
||||
return r;
|
||||
}
|
||||
new_meta_fd = open(new_meta_device, O_DIRECT|O_RDWR);
|
||||
if (new_meta_fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open new metadata device %s: %s\n", new_meta_device, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
lseek64(new_meta_fd, new_meta_offset, 0);
|
||||
write_blocking(new_meta_fd, new_buf, new_meta_len);
|
||||
fsync(new_meta_fd);
|
||||
close(new_meta_fd);
|
||||
free(new_buf);
|
||||
return 0;
|
||||
}
|
224
src/dump_journal.cpp
Normal file
224
src/dump_journal.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blockstore_impl.h"
|
||||
#include "crc32c.h"
|
||||
|
||||
struct journal_dump_t
|
||||
{
|
||||
char *journal_device;
|
||||
uint32_t journal_block;
|
||||
uint64_t journal_offset;
|
||||
uint64_t journal_len;
|
||||
uint64_t journal_pos;
|
||||
bool all;
|
||||
bool started;
|
||||
int fd;
|
||||
uint32_t crc32_last;
|
||||
|
||||
int dump_block(void *buf);
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
journal_dump_t self = { 0 };
|
||||
int b = 1;
|
||||
if (argc >= 2 && !strcmp(argv[1], "--all"))
|
||||
{
|
||||
self.all = true;
|
||||
b = 2;
|
||||
}
|
||||
if (argc < b+4)
|
||||
{
|
||||
printf("USAGE: %s [--all] <journal_file> <journal_block_size> <offset> <size>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
self.journal_device = argv[b];
|
||||
self.journal_block = strtoul(argv[b+1], NULL, 10);
|
||||
self.journal_offset = strtoull(argv[b+2], NULL, 10);
|
||||
self.journal_len = strtoull(argv[b+3], NULL, 10);
|
||||
if (self.journal_block < DIRECT_IO_ALIGNMENT || (self.journal_block % DIRECT_IO_ALIGNMENT) ||
|
||||
self.journal_block > 128*1024)
|
||||
{
|
||||
printf("Invalid journal block size\n");
|
||||
return 1;
|
||||
}
|
||||
self.fd = open(self.journal_device, O_DIRECT|O_RDONLY);
|
||||
if (self.fd == -1)
|
||||
{
|
||||
printf("Failed to open journal\n");
|
||||
return 1;
|
||||
}
|
||||
void *data = memalign(MEM_ALIGNMENT, self.journal_block);
|
||||
self.journal_pos = 0;
|
||||
if (self.all)
|
||||
{
|
||||
while (self.journal_pos < self.journal_len)
|
||||
{
|
||||
int r = pread(self.fd, data, self.journal_block, self.journal_offset+self.journal_pos);
|
||||
assert(r == self.journal_block);
|
||||
uint64_t s;
|
||||
for (s = 0; s < self.journal_block; s += 8)
|
||||
{
|
||||
if (*((uint64_t*)((uint8_t*)data+s)) != 0)
|
||||
break;
|
||||
}
|
||||
if (s == self.journal_block)
|
||||
{
|
||||
printf("offset %08lx: zeroes\n", self.journal_pos);
|
||||
self.journal_pos += self.journal_block;
|
||||
}
|
||||
else if (((journal_entry*)data)->magic == JOURNAL_MAGIC)
|
||||
{
|
||||
printf("offset %08lx:\n", self.journal_pos);
|
||||
self.dump_block(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("offset %08lx: no magic in the beginning, looks like random data (pattern=%lx)\n", self.journal_pos, *((uint64_t*)data));
|
||||
self.journal_pos += self.journal_block;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = pread(self.fd, data, self.journal_block, self.journal_offset+self.journal_pos);
|
||||
assert(r == self.journal_block);
|
||||
journal_entry *je = (journal_entry*)(data);
|
||||
if (je->magic != JOURNAL_MAGIC || je->type != JE_START || je_crc32(je) != je->crc32)
|
||||
{
|
||||
printf("offset %08lx: journal superblock is invalid\n", self.journal_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("offset %08lx:\n", self.journal_pos);
|
||||
self.dump_block(data);
|
||||
self.started = false;
|
||||
self.journal_pos = je->start.journal_start;
|
||||
while (1)
|
||||
{
|
||||
if (self.journal_pos >= self.journal_len)
|
||||
self.journal_pos = self.journal_block;
|
||||
r = pread(self.fd, data, self.journal_block, self.journal_offset+self.journal_pos);
|
||||
assert(r == self.journal_block);
|
||||
printf("offset %08lx:\n", self.journal_pos);
|
||||
r = self.dump_block(data);
|
||||
if (r <= 0)
|
||||
{
|
||||
printf("end of the journal\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
close(self.fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int journal_dump_t::dump_block(void *buf)
|
||||
{
|
||||
uint32_t pos = 0;
|
||||
journal_pos += journal_block;
|
||||
int entry = 0;
|
||||
bool wrapped = false;
|
||||
while (pos < journal_block)
|
||||
{
|
||||
journal_entry *je = (journal_entry*)((uint8_t*)buf + pos);
|
||||
if (je->magic != JOURNAL_MAGIC || je->type < JE_MIN || je->type > JE_MAX ||
|
||||
!all && started && je->crc32_prev != crc32_last)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bool crc32_valid = je_crc32(je) == je->crc32;
|
||||
if (!all && !crc32_valid)
|
||||
{
|
||||
break;
|
||||
}
|
||||
started = true;
|
||||
crc32_last = je->crc32;
|
||||
printf("entry % 3d: crc32=%08x %s prev=%08x ", entry, je->crc32, (crc32_valid ? "(valid)" : "(invalid)"), je->crc32_prev);
|
||||
if (je->type == JE_START)
|
||||
{
|
||||
printf("je_start start=%08lx\n", je->start.journal_start);
|
||||
}
|
||||
else if (je->type == JE_SMALL_WRITE || je->type == JE_SMALL_WRITE_INSTANT)
|
||||
{
|
||||
printf(
|
||||
"je_small_write%s oid=%lx:%lx ver=%lu offset=%u len=%u loc=%08lx",
|
||||
je->type == JE_SMALL_WRITE_INSTANT ? "_instant" : "",
|
||||
je->small_write.oid.inode, je->small_write.oid.stripe,
|
||||
je->small_write.version, je->small_write.offset, je->small_write.len,
|
||||
je->small_write.data_offset
|
||||
);
|
||||
if (journal_pos + je->small_write.len > journal_len)
|
||||
{
|
||||
// data continues from the beginning of the journal
|
||||
journal_pos = journal_block;
|
||||
wrapped = true;
|
||||
}
|
||||
if (journal_pos != je->small_write.data_offset)
|
||||
{
|
||||
printf(" (mismatched, calculated = %lu)", journal_pos);
|
||||
}
|
||||
journal_pos += je->small_write.len;
|
||||
if (journal_pos >= journal_len)
|
||||
{
|
||||
journal_pos = journal_block;
|
||||
wrapped = true;
|
||||
}
|
||||
uint32_t data_crc32 = 0;
|
||||
void *data = memalign(MEM_ALIGNMENT, je->small_write.len);
|
||||
assert(pread(fd, data, je->small_write.len, journal_offset+je->small_write.data_offset) == je->small_write.len);
|
||||
data_crc32 = crc32c(0, data, je->small_write.len);
|
||||
free(data);
|
||||
printf(
|
||||
" data_crc32=%08x%s", je->small_write.crc32_data,
|
||||
(data_crc32 != je->small_write.crc32_data) ? " (invalid)" : " (valid)"
|
||||
);
|
||||
printf("\n");
|
||||
}
|
||||
else if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
|
||||
{
|
||||
printf(
|
||||
"je_big_write%s oid=%lx:%lx ver=%lu loc=%08lx\n",
|
||||
je->type == JE_BIG_WRITE_INSTANT ? "_instant" : "",
|
||||
je->big_write.oid.inode, je->big_write.oid.stripe, je->big_write.version, je->big_write.location
|
||||
);
|
||||
}
|
||||
else if (je->type == JE_STABLE)
|
||||
{
|
||||
printf("je_stable oid=%lx:%lx ver=%lu\n", je->stable.oid.inode, je->stable.oid.stripe, je->stable.version);
|
||||
}
|
||||
else if (je->type == JE_ROLLBACK)
|
||||
{
|
||||
printf("je_rollback oid=%lx:%lx ver=%lu\n", je->rollback.oid.inode, je->rollback.oid.stripe, je->rollback.version);
|
||||
}
|
||||
else if (je->type == JE_DELETE)
|
||||
{
|
||||
printf("je_delete oid=%lx:%lx ver=%lu\n", je->del.oid.inode, je->del.oid.stripe, je->del.version);
|
||||
}
|
||||
pos += je->size;
|
||||
entry++;
|
||||
}
|
||||
if (wrapped)
|
||||
{
|
||||
journal_pos = journal_len;
|
||||
}
|
||||
return entry;
|
||||
}
|
173
src/dump_meta.cpp
Normal file
173
src/dump_meta.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "object_id.h"
|
||||
#include "osd_id.h"
|
||||
|
||||
// "VITAstor"
|
||||
#define BLOCKSTORE_META_MAGIC_V1 0x726F747341544956l
|
||||
#define BLOCKSTORE_META_VERSION_V1 1
|
||||
|
||||
#define DIRECT_IO_ALIGNMENT 512
|
||||
#define MEM_ALIGNMENT 4096
|
||||
|
||||
struct __attribute__((__packed__)) clean_disk_entry_v0_t
|
||||
{
|
||||
object_id oid;
|
||||
uint64_t version;
|
||||
uint8_t bitmap[];
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) blockstore_meta_header_v1_t
|
||||
{
|
||||
uint64_t zero;
|
||||
uint64_t magic;
|
||||
uint64_t version;
|
||||
uint32_t meta_block_size;
|
||||
uint32_t data_block_size;
|
||||
uint32_t bitmap_granularity;
|
||||
};
|
||||
|
||||
struct meta_dumper_t
|
||||
{
|
||||
char *meta_device;
|
||||
uint32_t meta_block_size;
|
||||
uint64_t meta_offset;
|
||||
uint64_t meta_len;
|
||||
uint64_t meta_pos;
|
||||
int fd;
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
meta_dumper_t self = { 0 };
|
||||
int b = 1;
|
||||
if (argc < b+4)
|
||||
{
|
||||
printf("USAGE: %s <meta_file> <meta_block_size> <offset> <size>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
self.meta_device = argv[b];
|
||||
self.meta_block_size = strtoul(argv[b+1], NULL, 10);
|
||||
self.meta_offset = strtoull(argv[b+2], NULL, 10);
|
||||
self.meta_len = strtoull(argv[b+3], NULL, 10);
|
||||
if (self.meta_block_size % DIRECT_IO_ALIGNMENT)
|
||||
{
|
||||
printf("Invalid metadata block size\n");
|
||||
return 1;
|
||||
}
|
||||
self.fd = open(self.meta_device, O_DIRECT|O_RDONLY);
|
||||
if (self.fd == -1)
|
||||
{
|
||||
printf("Failed to open metadata device\n");
|
||||
return 1;
|
||||
}
|
||||
// Read all metadata into memory
|
||||
void *data = memalign(MEM_ALIGNMENT, self.meta_len);
|
||||
if (!data)
|
||||
{
|
||||
printf("Failed to allocate %lu MB of memory\n", self.meta_len/1024/1024);
|
||||
close(self.fd);
|
||||
return 1;
|
||||
}
|
||||
while (self.meta_pos < self.meta_len)
|
||||
{
|
||||
int r = pread(self.fd, data+self.meta_pos, self.meta_len-self.meta_pos, self.meta_offset+self.meta_pos);
|
||||
assert(r > 0);
|
||||
self.meta_pos += r;
|
||||
}
|
||||
close(self.fd);
|
||||
// Check superblock
|
||||
blockstore_meta_header_v1_t *hdr = (blockstore_meta_header_v1_t *)data;
|
||||
if (hdr->zero == 0 &&
|
||||
hdr->magic == BLOCKSTORE_META_MAGIC_V1 &&
|
||||
hdr->version == BLOCKSTORE_META_VERSION_V1)
|
||||
{
|
||||
// Vitastor 0.6-0.7 - static array of clean_disk_entry_v0_t with bitmaps
|
||||
if (hdr->meta_block_size != self.meta_block_size)
|
||||
{
|
||||
printf("Using block size %u bytes based on information from the superblock\n", hdr->meta_block_size);
|
||||
self.meta_block_size = hdr->meta_block_size;
|
||||
}
|
||||
uint64_t clean_entry_bitmap_size = hdr->data_block_size / hdr->bitmap_granularity / 8;
|
||||
uint64_t clean_entry_size = sizeof(clean_disk_entry_v0_t) + 2*clean_entry_bitmap_size;
|
||||
uint64_t block_num = 0;
|
||||
printf(
|
||||
"{\"version\":\"0.6\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u,\"entries\":[\n",
|
||||
hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity
|
||||
);
|
||||
bool first = true;
|
||||
for (uint64_t meta_pos = self.meta_block_size; meta_pos < self.meta_len; meta_pos += self.meta_block_size)
|
||||
{
|
||||
for (uint64_t ioff = 0; ioff < self.meta_block_size-clean_entry_size; ioff += clean_entry_size, block_num++)
|
||||
{
|
||||
clean_disk_entry_v0_t *entry = (clean_disk_entry_v0_t*)(data + meta_pos + ioff);
|
||||
if (entry->oid.inode)
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"block\":%lu,\"pool\":%u,\"inode\":%lu,\"stripe\":%lu,\"version\":%lu,\"bitmap\":\""
|
||||
(first ? (",\n" ENTRY_FMT) : ENTRY_FMT),
|
||||
#undef ENTRY_FMT
|
||||
block_num, INODE_POOL(entry->oid.inode), INODE_NO_POOL(entry->oid.inode),
|
||||
entry->oid.stripe, entry->version
|
||||
);
|
||||
first = false;
|
||||
for (uint64_t i = 0; i < clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", entry->bitmap[i]);
|
||||
}
|
||||
printf("\",\"ext_bitmap\":\"");
|
||||
for (uint64_t i = 0; i < clean_entry_bitmap_size; i++)
|
||||
{
|
||||
printf("%02x", entry->bitmap[clean_entry_bitmap_size + i]);
|
||||
}
|
||||
printf("\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("]}\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vitastor 0.4-0.5 - static array of clean_disk_entry_v0_t
|
||||
uint64_t clean_entry_size = sizeof(clean_disk_entry_v0_t);
|
||||
uint64_t block_num = 0;
|
||||
printf("{\"version\":\"0.5\",\"meta_block_size\":%u,\"entries\":[\n", self.meta_block_size);
|
||||
bool first = true;
|
||||
for (uint64_t meta_pos = 0; meta_pos < self.meta_len; meta_pos += self.meta_block_size)
|
||||
{
|
||||
for (uint64_t ioff = 0; ioff < self.meta_block_size-clean_entry_size; ioff += clean_entry_size, block_num++)
|
||||
{
|
||||
clean_disk_entry_v0_t *entry = (clean_disk_entry_v0_t*)(data + meta_pos + ioff);
|
||||
if (entry->oid.inode)
|
||||
{
|
||||
printf(
|
||||
#define ENTRY_FMT "{\"block\":%lu,\"pool\":%u,\"inode\":%lu,\"stripe\":%lu,\"version\":%lu}"
|
||||
(first ? (",\n" ENTRY_FMT) : ENTRY_FMT),
|
||||
#undef ENTRY_FMT
|
||||
block_num, INODE_POOL(entry->oid.inode), INODE_NO_POOL(entry->oid.inode),
|
||||
entry->oid.stripe, entry->version
|
||||
);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("]}\n");
|
||||
}
|
||||
free(data);
|
||||
}
|
2
src/lrc/Makefile
Normal file
2
src/lrc/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
mat: mat.c
|
||||
gcc -O3 -I/usr/include/jerasure -o mat mat.c -lJerasure
|
291
src/lrc/mat.c
Normal file
291
src/lrc/mat.c
Normal file
@@ -0,0 +1,291 @@
|
||||
#include <jerasure/reed_sol.h>
|
||||
#include <jerasure.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Generate LRC matrix: (groups*local + global) code rows with (data_drives) columns
|
||||
// w should be >= log2(data_drives + groups*local + global), but not necessary 8/16/32
|
||||
int* reed_sol_vandermonde_lrc_matrix(int data_drives, int groups, int local, int global, int w)
|
||||
{
|
||||
if (w < 0 || w > 32 || data_drives + groups*local + global > (1<<w))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int *lrc_matrix = (int*)malloc(sizeof(int) * (local*groups+global));
|
||||
int *matrix = reed_sol_vandermonde_coding_matrix(data_drives, local+global, w);
|
||||
// Enough to transform LRC 8+2+2 GF(8) matrix into MR-LRC
|
||||
//for (int i = 0; i < local+global; i++)
|
||||
//{
|
||||
// int t = matrix[i*data_drives + 3];
|
||||
// matrix[i*data_drives + 3] = matrix[i*data_drives + 7];
|
||||
// matrix[i*data_drives + 7] = t;
|
||||
//}
|
||||
for (int gr = 0; gr < groups; gr++)
|
||||
{
|
||||
for (int l = 0; l < local; l++)
|
||||
{
|
||||
for (int j = 0; j < data_drives; j++)
|
||||
{
|
||||
lrc_matrix[(gr*local+l)*data_drives + j] = (j / (data_drives/groups)) == gr ? matrix[l*data_drives + j] : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < global; i++)
|
||||
{
|
||||
for (int j = 0; j < data_drives; j++)
|
||||
{
|
||||
lrc_matrix[(groups*local+i)*data_drives + j] = matrix[(local+i)*data_drives + j];
|
||||
}
|
||||
}
|
||||
free(matrix);
|
||||
return lrc_matrix;
|
||||
}
|
||||
|
||||
struct lrc_test_result_t
|
||||
{
|
||||
int success, impossible, failures;
|
||||
};
|
||||
|
||||
// Check if the generated LRC with given parameters is Maximally Reconstructible (MR-LRC)
|
||||
// Example of a MR-LRC: (8, 2, 1, 2, 6, 8)
|
||||
struct lrc_test_result_t check_mr_lrc(int *lrc_matrix, int data_drives, int groups, int local, int global, int w, int log_level)
|
||||
{
|
||||
int n = data_drives;
|
||||
int total_rows = n + groups*local + global;
|
||||
int impossible = 0, success = 0, failures = 0;
|
||||
int *lost_per_group = (int*)malloc(sizeof(int) * groups);
|
||||
int *recovered_per_group = (int*)malloc(sizeof(int) * groups);
|
||||
int *selected_inverted = (int*)malloc(sizeof(int) * data_drives);
|
||||
// global+1 is always recoverable
|
||||
for (int lost = global+2; lost <= groups*local+global; lost++)
|
||||
{
|
||||
int *erased_matrix = (int*)malloc(sizeof(int) * (total_rows-lost)*n);
|
||||
int *inverted_matrix = (int*)malloc(sizeof(int) * (total_rows-lost)*n);
|
||||
int *p = (int*)malloc(sizeof(int) * (total_rows-lost));
|
||||
for (int i = 0; i < n; i++)
|
||||
p[i] = i;
|
||||
int *p2 = (int*)malloc(sizeof(int) * n);
|
||||
if (total_rows-lost > n)
|
||||
{
|
||||
p[n-1] = n; // skip combinations with all N data disks (0..n-1)
|
||||
for (int i = n; i < total_rows-lost; i++)
|
||||
p[i] = i+1;
|
||||
p[total_rows-lost-1]--; // will be incremented on the first step
|
||||
}
|
||||
int inc = total_rows-lost-1;
|
||||
while (1)
|
||||
{
|
||||
p[inc]++;
|
||||
if (p[inc] >= n+groups*local+global)
|
||||
{
|
||||
if (inc == 0)
|
||||
break;
|
||||
inc--;
|
||||
}
|
||||
else if (inc+1 < total_rows-lost)
|
||||
{
|
||||
p[inc+1] = p[inc];
|
||||
inc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if it should be recoverable
|
||||
// Calculate count of data chunks lost in each group
|
||||
int nsel = 0;
|
||||
for (int gr = 0; gr < groups; gr++)
|
||||
{
|
||||
lost_per_group[gr] = ((gr+1)*(n/groups) > n ? (n - gr*(n/groups)) : n/groups);
|
||||
recovered_per_group[gr] = 0;
|
||||
}
|
||||
for (int j = 0; j < total_rows-lost; j++)
|
||||
{
|
||||
if (p[j] < n)
|
||||
{
|
||||
lost_per_group[(p[j] / (n/groups))]--;
|
||||
selected_inverted[nsel++] = j;
|
||||
}
|
||||
}
|
||||
// Every local parity chunk is supposed to restore 1 missing chunk inside its group
|
||||
// So, subtract local parity chunk counts from each group lost chunk count
|
||||
for (int j = 0; j < total_rows-lost; j++)
|
||||
{
|
||||
if (p[j] >= n && p[j] < n+groups*local)
|
||||
{
|
||||
int gr = (p[j]-n)/local;
|
||||
if (lost_per_group[gr] > recovered_per_group[gr] && nsel < n)
|
||||
{
|
||||
selected_inverted[nsel++] = j;
|
||||
}
|
||||
recovered_per_group[gr]++;
|
||||
}
|
||||
}
|
||||
// Every global parity chunk is supposed to restore 1 chunk of all that are still missing
|
||||
int still_missing = 0;
|
||||
for (int gr = 0; gr < groups; gr++)
|
||||
{
|
||||
int non_fixed = lost_per_group[gr] - recovered_per_group[gr];
|
||||
still_missing += (non_fixed > 0 ? non_fixed : 0);
|
||||
}
|
||||
for (int j = 0; j < total_rows-lost; j++)
|
||||
{
|
||||
if (p[j] >= n+groups*local)
|
||||
{
|
||||
if (still_missing > 0 && nsel < n)
|
||||
{
|
||||
selected_inverted[nsel++] = j;
|
||||
}
|
||||
still_missing--;
|
||||
}
|
||||
}
|
||||
if (still_missing <= 0)
|
||||
{
|
||||
// We hope it can be recoverable. Try to invert it
|
||||
assert(nsel == n);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
erased_matrix[i*n+j] = lrc_matrix[p[selected_inverted[i]]*n+j];
|
||||
}
|
||||
}
|
||||
int invert_ok = jerasure_invert_matrix(erased_matrix, inverted_matrix, n, w);
|
||||
if (invert_ok < 0)
|
||||
{
|
||||
failures++;
|
||||
if (log_level > 0)
|
||||
{
|
||||
printf("\nFAIL: ");
|
||||
for (int i = 0; i < total_rows-lost; i++)
|
||||
{
|
||||
printf("%d ", p[i]);
|
||||
}
|
||||
printf("\nDIRECT:\n");
|
||||
for (int i = 0; i < total_rows-lost; i++)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
printf("%d ", lrc_matrix[p[i]*n+j]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("INVERSE:\n");
|
||||
for (int i = 0; i < total_rows-lost; i++)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
printf("%d ", inverted_matrix[i*n+j]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success++;
|
||||
if (log_level > 2)
|
||||
{
|
||||
printf("OK: ");
|
||||
for (int i = 0; i < total_rows-lost; i++)
|
||||
{
|
||||
printf("%d ", p[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
impossible++;
|
||||
if (log_level > 1)
|
||||
{
|
||||
printf("IMPOSSIBLE: ");
|
||||
for (int i = 0; i < total_rows-lost; i++)
|
||||
{
|
||||
printf("%d ", p[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(p2);
|
||||
free(p);
|
||||
free(inverted_matrix);
|
||||
free(erased_matrix);
|
||||
}
|
||||
free(lost_per_group);
|
||||
free(recovered_per_group);
|
||||
return (struct lrc_test_result_t){
|
||||
.success = success,
|
||||
.impossible = impossible,
|
||||
.failures = failures,
|
||||
};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int W = 8, MATRIX_W = 8;
|
||||
int n = 8, groups = 2, local = 1, global = 2;
|
||||
//n = 4, groups = 2, local = 1, global = 1;
|
||||
int total_rows = n+groups*local+global;
|
||||
int *matrix = reed_sol_vandermonde_lrc_matrix(n, groups, local, global, MATRIX_W);
|
||||
int *lrc_matrix = (int*)malloc(sizeof(int) * total_rows*n);
|
||||
// Fill identity+LRC matrix
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < n; j++)
|
||||
lrc_matrix[i*n + j] = j == i ? 1 : 0;
|
||||
memcpy(lrc_matrix + n*n, matrix, (total_rows-n)*n*sizeof(int));
|
||||
free(matrix);
|
||||
matrix = NULL;
|
||||
// Print LRC matrix
|
||||
for (int i = 0; i < total_rows; i++)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
{
|
||||
printf("%d ", lrc_matrix[i*n+j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
struct lrc_test_result_t t = check_mr_lrc(lrc_matrix, n, groups, local, global, W, 1);
|
||||
printf("\n%d recovered, %d impossible, %d failures\n", t.success, t.impossible, t.failures);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 1 1 1 1 0 0 0 0
|
||||
// 0 0 0 0 1 1 1 1
|
||||
// 1 55 39 73 84 181 225 217
|
||||
// 1 172 70 235 143 34 200 101
|
||||
//
|
||||
// Can't recover
|
||||
// 1 2 4 5 8 9 10 11 -1
|
||||
// 2 3 4 6 8 9 10 11 -1
|
||||
// FULL:
|
||||
// 1 0 0 0 0 0 0 0
|
||||
// 0 1 0 0 0 0 0 0
|
||||
// 0 0 1 0 0 0 0 0
|
||||
// 0 0 0 1 0 0 0 0
|
||||
// 0 0 0 0 1 0 0 0
|
||||
// 0 0 0 0 0 1 0 0
|
||||
// 0 0 0 0 0 0 1 0
|
||||
// 0 0 0 0 0 0 0 1
|
||||
// 1 1 1 1 0 0 0 0
|
||||
// 0 0 0 0 1 1 1 1
|
||||
// 1 55 39 73 84 181 225 217
|
||||
// 1 172 70 235 143 34 200 101
|
||||
// FIRST UNRECOVERABLE:
|
||||
// 0 1 0 0 0 0 0 0
|
||||
// 0 0 1 0 0 0 0 0
|
||||
// 0 0 0 0 1 0 0 0
|
||||
// 0 0 0 0 0 1 0 0
|
||||
// 1 1 1 1 0 0 0 0
|
||||
// 0 0 0 0 1 1 1 1
|
||||
// 1 55 39 73 84 181 225 217
|
||||
// 1 172 70 235 143 34 200 101
|
||||
// SECOND UNRECOVERABLE:
|
||||
// 0 0 1 0 0 0 0 0
|
||||
// 0 0 0 1 0 0 0 0
|
||||
// 0 0 0 0 1 0 0 0
|
||||
// 0 0 0 0 0 0 1 0
|
||||
// 1 1 1 1 0 0 0 0
|
||||
// 0 0 0 0 1 1 1 1
|
||||
// 1 55 39 73 84 181 225 217
|
||||
// 1 172 70 235 143 34 200 101
|
||||
// Ho ho ho
|
Reference in New Issue
Block a user