SAMBA: Неправильно отображается информация о размерах папки лежащей на BTRFS

Типичной ситуацией является некорректное отображение общего размера сетевой шары, если она лежит на BTRFS-рейде - вместо действительного размера тома показывается сумма размеров всех дисков в рейде. Для исправления этой ситуации можно воспользоваться опцией "dfree command", которая позволяет указать кастомный исполняемый файл, которые будет подсчитывать и возвращать данные о размерах диска.

Данные опции нужно добавить в конфигурацию шары:

[Public]
    ....
    dfree command = /etc/samba/btrfs-dfree.py
    dfree cache time = 60
    force user = root
    force group = root
    ....

Здесь стоит обратить внимание на опцию "force user = root", которая с одной стороны принудительно сделает рута владельцем новых файлов и папок, что может быть вам не нужно, но также позволит выполняться скрипту с рутовыми правами - это необходимо для получения таких данных из вывода "btrfs filesystem usage" как "ratio" - коэффициент данных на рейде, учитывающий сколько копий данных фактически на рейде расположено, и "free (estimated) min" -  более точное значение свободного места.

Если в ваши планы не входит менять юзера с дефолтного, то свободное место будет браться скриптом из Free (statfs, df), а для показа точного общего размера сетевой шары можно вручную в скрипте указать значение ratio, присвоив его переменной CUSTOMRATIO.

Итак, создаем скрипт "/etc/samba/btrfs-dfree.py" (спасибо проекту openmediavault, я использовал их скрипт "omv-btrfs-dfree" как основу), не забываем сделать его исполняемым. Скрипт на гитхабе

#!/usr/bin/env python3

import os
import re
import subprocess
import sys
from systemd import journal

CUSTOMRATIO = 0 # set ratio of your btrfs volume if samba user is not root (smb.conf: force user = root)
LOGGING = 0 # 0 - off, 1 - on. journalctl -t 'SMBUS'

def main():
    path = os.path.realpath(sys.argv[1] if len(sys.argv) > 0 else '.')

    output = subprocess.run(
        ['btrfs', 'filesystem', 'usage', '--raw', '-T', path],
        capture_output=True
    ).stdout.decode()

    re_matches_for_total = r'.+Device size:\s+(\d+)\n.+'
    matches_for_total = re.match(
        re_matches_for_total,
        output, re.DOTALL
    )
    if os.getuid() == 0: # if samba user is root we can get ratio to calculate total space
        re_matches_for_ratio = r'.+Data ratio:\s+(\d+\.\d+).+'
        matches_for_ratio = re.match(
            re_matches_for_ratio,
            output, re.DOTALL
        )
        ratio = float(matches_for_ratio.group(1))
    else: # else set ratio = 1 but can get wrong total size
        if CUSTOMRATIO == 0:
            ratio = 1
        else:
            ratio = CUSTOMRATIO

    if os.getuid() == 0: # if user is root we can get estimated (minimum) free space
        re_matches_for_available = r'.+Free \(estimated\):\s+\d+\s+\(min: (\d+)\)\n.+'
    else: # otherwise only 'statfs' free
        re_matches_for_available = r'.+Free \(statfs, df\):\s+(\d+)\n.+'
    matches_for_available = re.match(
        re_matches_for_available,
        output, re.DOTALL
    )

    if matches_for_total is not None:
        totalb = matches_for_total.group(1)
        availableb = matches_for_available.group(1)
        if LOGGING == 1:
            journal.stream('SMBUS').write(f'SMB VARS: userid={os.getuid()}, ratio={ratio}, availableb={availableb}, totalb={totalb}')
            for line in output.splitlines():
                journal.stream('SMBUS').write(f'{line}')
        total =     round(int(totalb) // (1024 * ratio))
        available = round(int(availableb) // 1024)

    else:
        output = subprocess.run(
            ['df', '--portability', '--print-type', '--block-size=1K', path],
            capture_output=True
        ).stdout.decode()
        _, _, total, _, available, *_ = output.split('\n')[1].split()
    sys.stdout.write(f'{total} {available} 1024\n')

if   name   == "  main  ":
    sys.exit(main())

Проверить работу скрипта можно выполнив его вручную, указав в качестве аргумента путь к папке на btrfs:

Поделиться:
Метки: , , . Закладка Постоянная ссылка.
0 Комментарий
Oldest
Newest Most Voted
Inline Feedbacks
View all comments