From 8ec7faa6753e8dceedc2aed4eba5e33d3f4d57e6 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Mon, 22 Dec 2025 01:52:07 +0300 Subject: [PATCH] Disable use_atomic_flag by default --- docs/config/osd.en.md | 25 +++++++----- docs/config/osd.ru.md | 22 ++++++---- docs/config/src/osd.yml | 47 ++++++++++++++-------- patches/linux-fix-atomic-write-checks.diff | 39 ++++++++++++++++++ src/disk_tool/disk_tool.h | 1 + src/disk_tool/disk_tool_prepare.cpp | 27 +++++++------ 6 files changed, 117 insertions(+), 44 deletions(-) create mode 100644 patches/linux-fix-atomic-write-checks.diff diff --git a/docs/config/osd.en.md b/docs/config/osd.en.md index f7e68e58..3fc095b2 100644 --- a/docs/config/osd.en.md +++ b/docs/config/osd.en.md @@ -682,7 +682,10 @@ with replicated pools and reach the best possible write performance. Default value is auto-detected during OSD initialization from `/sys/block/xx/queue/atomic_write_max_bytes` or assumed to be 4096 bytes -because all known disks support 4 KB atomic writes. +because all known disks support 4 KB atomic writes. Auto-detection is only used for +NVMe disks because SAS disks require the explicit WRITE ATOMIC command which requires +RWF_ATOMIC (see below [#use_atomic_flag]) but that flag works incorrectly in current +Linux versions. You can also check if your NVMe drives support atomic writes by running the command `nvme id-ctrl /dev/nvme0n1 | grep awupf`. If the reported value, @@ -697,12 +700,16 @@ reducing Write Amplification and improving write performance up to 2 times. - Type: boolean -This option controls whether the Vitastor OSD uses RWF_ATOMIC write flag with atomic -writes. This flag is only supported on Linux kernel since 6.11. Atomic writes are -generally only safe to use with this flag because it tells the kernel to never fragment -write requests and also to check the write against the actual atomic write capabilities -of the device. +This option controls whether Vitastor OSDs use RWF_ATOMIC write flag with atomic writes. +This flag is supported since Linux 6.11 and adds some safety to atomic writes - the kernel +guarantees to not fragment write requests with it and also to check them against the actual +device atomic write capabilities. -This option is enabled by default when atomic_write_size is set to a value larger than 4 KB. -You can disable it if you're sure that your disks support atomic writes and you want to -bypass the Linux atomic write checks. +However, the option is disabled by default because the flag is currently UNUSABLE - Linux +incorrectly requires writes with that flag to be of power-of-2 length and length-aligned. +I.e., for example, 12 KB writes and not-8-KB aligned 8 KB writes are forbidden by the kernel, +even though the NVMe specification allows them. + +For NVMe disks with `scheduler=none` writes aren't fragmented anyway so it's not a big deal. +However, you can rebuild your kernel with [this patch](../../patches/linux-fix-atomic-write-checks.diff) +and turn this option on. It will make your atomic writes a bit safer. diff --git a/docs/config/osd.ru.md b/docs/config/osd.ru.md index 5bd97d2b..97cdd60a 100644 --- a/docs/config/osd.ru.md +++ b/docs/config/osd.ru.md @@ -717,6 +717,9 @@ pg_minsize OSD во время переключений, что может по Значение по умолчанию авто-определяется во время инициализации OSD из `/sys/block/xx/queue/atomic_write_max_bytes` либо принимается равным 4096, так как все известные диски поддерживают атомарную запись 4 КБ блоков. +Автоопределение применяется только для NVMe-дисков, так как SAS диски требуют +использования отдельной команды WRITE ATOMIC, а для неё нужен флаг RWF_ATOMIC +(см. ниже [#use_atomic_flag]), а он в текущих версиях Linux работает некорректно. Вы также можете проверить, поддерживают ли ваши NVMe-диски атомарную запись, с помощью команды `nvme id-ctrl /dev/nvme0n1 | grep awupf`. Если значение awupf @@ -735,11 +738,16 @@ pg_minsize OSD во время переключений, что может по - Тип: булево (да/нет) Данная опция контролирует использование Vitastor OSD флага RWF_ATOMIC при атомарной записи -блоков. Этот флаг поддерживается только в ядрах Linux начиная с 6.11. Атомарная запись -является безопасной только при использовании этого флага, так как он сообщает ядру о том, -что запрос записи нельзя фрагментировать и о том, что запрос нужно проверить на соответствие -реальным возможностям атомарной записи устройства. +блоков. Этот флаг поддерживается, начиная с версии ядра Linux 6.11 и добавляет немного корректности +атомарным записям - ядро гарантирует отсутствие фрагментации запросов записи с этим флагом и +проверяет их на соответствие реальным возможностям устройства. -Опция включается по умолчанию, когда atomic_write_size устанавливается в значение больше 4 КБ. -Вы можете явно отключить её, если уверены, что ваши диски поддерживают атомарную запись и -хотите обойти проверки уровня ядра. +Однако, данная опция по умолчанию отключена, так как флаг в текущих версиях Linux работает +абсолютно НЕКОРРЕКТНО - при нём Linux требует, чтобы запросы записи имели длину, равную +степени двойки и были выровнены на эту длину. То есть, например, 12 КБ запросы записи, а также +8 КБ запросы записи по не-кратному 8 КБ смещению запрещаются ядром, хотя спецификация NVMe их +разрешает. + +Для NVMe-дисков с `scheduler=none` запросы записи и так не фрагментируются, так что это не так +уж и важно, однако вы можете пересобрать своё ядро с [этим патчем](../../patches/linux-fix-atomic-write-checks.diff) +и включить данную опцию. Это сделает вашу атомарную запись капельку безопаснее. diff --git a/docs/config/src/osd.yml b/docs/config/src/osd.yml index aa331f02..1d4399b1 100644 --- a/docs/config/src/osd.yml +++ b/docs/config/src/osd.yml @@ -813,7 +813,10 @@ Default value is auto-detected during OSD initialization from `/sys/block/xx/queue/atomic_write_max_bytes` or assumed to be 4096 bytes - because all known disks support 4 KB atomic writes. + because all known disks support 4 KB atomic writes. Auto-detection is only used for + NVMe disks because SAS disks require the explicit WRITE ATOMIC command which requires + RWF_ATOMIC (see below [#use_atomic_flag]) but that flag works incorrectly in current + Linux versions. You can also check if your NVMe drives support atomic writes by running the command `nvme id-ctrl /dev/nvme0n1 | grep awupf`. If the reported value, @@ -834,6 +837,9 @@ Значение по умолчанию авто-определяется во время инициализации OSD из `/sys/block/xx/queue/atomic_write_max_bytes` либо принимается равным 4096, так как все известные диски поддерживают атомарную запись 4 КБ блоков. + Автоопределение применяется только для NVMe-дисков, так как SAS диски требуют + использования отдельной команды WRITE ATOMIC, а для неё нужен флаг RWF_ATOMIC + (см. ниже [#use_atomic_flag]), а он в текущих версиях Linux работает некорректно. Вы также можете проверить, поддерживают ли ваши NVMe-диски атомарную запись, с помощью команды `nvme id-ctrl /dev/nvme0n1 | grep awupf`. Если значение awupf @@ -849,22 +855,31 @@ - name: use_atomic_flag type: bool info: | - This option controls whether the Vitastor OSD uses RWF_ATOMIC write flag with atomic - writes. This flag is only supported on Linux kernel since 6.11. Atomic writes are - generally only safe to use with this flag because it tells the kernel to never fragment - write requests and also to check the write against the actual atomic write capabilities - of the device. + This option controls whether Vitastor OSDs use RWF_ATOMIC write flag with atomic writes. + This flag is supported since Linux 6.11 and adds some safety to atomic writes - the kernel + guarantees to not fragment write requests with it and also to check them against the actual + device atomic write capabilities. - This option is enabled by default when atomic_write_size is set to a value larger than 4 KB. - You can disable it if you're sure that your disks support atomic writes and you want to - bypass the Linux atomic write checks. + However, the option is disabled by default because the flag is currently UNUSABLE - Linux + incorrectly requires writes with that flag to be of power-of-2 length and length-aligned. + I.e., for example, 12 KB writes and not-8-KB aligned 8 KB writes are forbidden by the kernel, + even though the NVMe specification allows them. + + For NVMe disks with `scheduler=none` writes aren't fragmented anyway so it's not a big deal. + However, you can rebuild your kernel with [this patch](../../patches/linux-fix-atomic-write-checks.diff) + and turn this option on. It will make your atomic writes a bit safer. info_ru: | Данная опция контролирует использование Vitastor OSD флага RWF_ATOMIC при атомарной записи - блоков. Этот флаг поддерживается только в ядрах Linux начиная с 6.11. Атомарная запись - является безопасной только при использовании этого флага, так как он сообщает ядру о том, - что запрос записи нельзя фрагментировать и о том, что запрос нужно проверить на соответствие - реальным возможностям атомарной записи устройства. + блоков. Этот флаг поддерживается, начиная с версии ядра Linux 6.11 и добавляет немного корректности + атомарным записям - ядро гарантирует отсутствие фрагментации запросов записи с этим флагом и + проверяет их на соответствие реальным возможностям устройства. - Опция включается по умолчанию, когда atomic_write_size устанавливается в значение больше 4 КБ. - Вы можете явно отключить её, если уверены, что ваши диски поддерживают атомарную запись и - хотите обойти проверки уровня ядра. + Однако, данная опция по умолчанию отключена, так как флаг в текущих версиях Linux работает + абсолютно НЕКОРРЕКТНО - при нём Linux требует, чтобы запросы записи имели длину, равную + степени двойки и были выровнены на эту длину. То есть, например, 12 КБ запросы записи, а также + 8 КБ запросы записи по не-кратному 8 КБ смещению запрещаются ядром, хотя спецификация NVMe их + разрешает. + + Для NVMe-дисков с `scheduler=none` запросы записи и так не фрагментируются, так что это не так + уж и важно, однако вы можете пересобрать своё ядро с [этим патчем](../../patches/linux-fix-atomic-write-checks.diff) + и включить данную опцию. Это сделает вашу атомарную запись капельку безопаснее. diff --git a/patches/linux-fix-atomic-write-checks.diff b/patches/linux-fix-atomic-write-checks.diff new file mode 100644 index 00000000..b916c846 --- /dev/null +++ b/patches/linux-fix-atomic-write-checks.diff @@ -0,0 +1,39 @@ +From 98d3f68a40130c438854f61db6025f9e9b099cb6 Mon Sep 17 00:00:00 2001 +From: Vitaliy Filippov +Date: Sat, 20 Dec 2025 14:44:35 +0300 +Subject: [PATCH] Do not require atomic writes to be power of 2 sized and + aligned on length boundary + +It contradicts NVMe specification where alignment is only required when atomic +write boundary (NABSPF/NABO) is set and highly limits usage of NVMe atomic writes + +Signed-off-by: Vitaliy Filippov +--- + fs/read_write.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/fs/read_write.c b/fs/read_write.c +index 833bae068770..5467d710108d 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -1802,17 +1802,9 @@ int generic_file_rw_checks(struct file *file_in, struct file *file_out) + + int generic_atomic_write_valid(struct kiocb *iocb, struct iov_iter *iter) + { +- size_t len = iov_iter_count(iter); +- + if (!iter_is_ubuf(iter)) + return -EINVAL; + +- if (!is_power_of_2(len)) +- return -EINVAL; +- +- if (!IS_ALIGNED(iocb->ki_pos, len)) +- return -EINVAL; +- + if (!(iocb->ki_flags & IOCB_DIRECT)) + return -EOPNOTSUPP; + +-- +2.51.0 + diff --git a/src/disk_tool/disk_tool.h b/src/disk_tool/disk_tool.h index 07cf41be..962c76fe 100644 --- a/src/disk_tool/disk_tool.h +++ b/src/disk_tool/disk_tool.h @@ -88,6 +88,7 @@ struct disk_tool_t uint32_t new_meta_format = 0; int new_journal_fd = -1, new_meta_fd = -1; resizer_data_moving_t *moving_blocks = NULL; + bool atomic_warned = false; bool started = false; void *small_write_data = NULL; diff --git a/src/disk_tool/disk_tool_prepare.cpp b/src/disk_tool/disk_tool_prepare.cpp index 3aa39254..f2d3035b 100644 --- a/src/disk_tool/disk_tool_prepare.cpp +++ b/src/disk_tool/disk_tool_prepare.cpp @@ -91,21 +91,24 @@ int disk_tool_t::prepare_one(std::map options, int is_ if (options.find("atomic_write_size") == options.end()) { auto data_dev = realpath_str(options["data_device"], false); - uint64_t atomic_write_size = get_atomic_write_size(data_dev); - if (atomic_write_size > 4096) + if (data_dev.substr(0, 9) == "/dev/nvme") { - fprintf(stderr, "Data device %s supports atomic writes up to %ju bytes, enabling. Enjoy faster writes!\n", - data_dev.c_str(), atomic_write_size); - options["atomic_write_size"] = std::to_string(atomic_write_size); - options["use_atomic_flag"] = "1"; + uint64_t atomic_write_size = get_atomic_write_size(data_dev); + if (atomic_write_size > 4096) + { + // FIXME: Enable use_atomic_flag when the kernel does checks correctly + fprintf(stderr, "Data device %s supports atomic writes up to %ju bytes, enabling. Enjoy faster writes!\n", + data_dev.c_str(), atomic_write_size); + options["atomic_write_size"] = std::to_string(atomic_write_size); + if (!atomic_warned) + { + fprintf(stderr, "WARNING: RWF_ATOMIC can't be used because Linux checks atomic writes incorrectly.\n" + " Please don't change scheduler from default 'none' and check use_atomic_flag documentation for more details.\n"); + atomic_warned = true; + } + } } } - else if (options.find("use_atomic_flag") == options.end() && - parse_size(options["atomic_write_size"]) > 4096) - { - fprintf(stderr, "Atomic writes larger than 4 KB are enabled manually, enabling use_atomic_flag too.\n"); - options["use_atomic_flag"] = "1"; - } for (auto dev: std::vector{"data", "meta", "journal"}) { if (options[dev+"_device"] != "" && options["disable_"+dev+"_fsync"] == "auto")