Почему shutils и df сообщают о разнице в размере диска на несколько%? - PullRequest
2 голосов
/ 01 июля 2019

Я пишу простой скрипт мониторинга, в который я хотел бы добавить проверки дискового пространства.Однако я обнаружил, что указанное свободное пространство отличается в системе df и shutils.disk_usage().

В системе, в которой установлены три диска:

# df / /mnt/2TB1 /mnt/1TB1
Filesystem      1K-blocks       Used Available Use% Mounted on
/dev/sda1       472437724  231418380 216997128  52% /
/dev/sdb1      1921802520 1712163440 111947020  94% /mnt/2TB1
/dev/sdc1       960380648  347087300 564438888  39% /mnt/1TB1

# python3
Python 3.6.8 (default, Jan 14 2019, 11:02:34)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import shutil
>>> (t, u, f) = shutil.disk_usage('/')
>>> (t, u, f)
(483776229376, 236973805568, 222203674624)
>>> u/t
0.48984177224594366
>>> (t, u, f) = shutil.disk_usage('/mnt/2TB1')
>>> (t, u, f)
(1967925780480, 1753255362560, 114633748480)
>>> u/t
0.8909153891628782
>>> (t, u, f) = shutil.disk_usage('/mnt/1TB1')
>>> (t, u, f)
(983429783552, 355400192000, 578002624512)
>>> u/t
0.361388477290517

Разница составляет соответственно 3%, 5% и 3%.Откуда оно берется и какой результат является правильным?

Ответы [ 3 ]

3 голосов
/ 02 июля 2019

Python , кажется, имеет правильные результаты.
По умолчанию [man7]: DF (1) (man df) отображает числа (размеры) в блоках 1 КиБ .Но, учитывая тот факт, что операция (деление на 1024) применяется как к делителю, так и к делителю (при вычислении процента), она сама себя уменьшает, поэтому она не должна иметь ничего общего с конечным результатом.

Пример (для определенного dir ):

  1. Выполнить df (по умолчанию вывод в КиБ )
  2. Выполнить df -B 1 (вывод в байтах)
  3. Выполнить следующий сценарий Python :

    import sys, shutil
    
    path = sys.argv[1] if len(sys.argv) > 1 else "/"
    t, u, f = shutil.disk_usage(path)
    percent = 100 * u / t
    print("(Python) - Volume name\t{:} {:} {:} {:.3f}% ({:.0f}) {:}".format(t, u, f, percent, percent, path))
    
[cfati@cfati-ubtu16x64-0:~]> for f in "/" "/media/sf_shared_00"; do echo df "${f}" && df ${f} && echo df -B 1 "${f}" && df -B 1 ${f} && echo Python script on "${f}" && python3 -c "import sys, shutil; path = sys.argv[1] if len(sys.argv) > 1 else \"/\"; t, u, f = shutil.disk_usage(path); percent = 100 * u / t; print(\"(Python) - Volume name\t{:} {:} {:} {:.3f}% ({:.0f}) {:}\".format(t, u, f, percent, percent, path))" ${f} && echo && echo; done
df /
Filesystem                                   1K-blocks     Used Available Use% Mounted on
/dev/mapper/ubtu16x640_lvg0-ubtu16x640_root0 102067544 10999896  85859792  12% /
df -B 1 /
Filesystem                                      1B-blocks        Used   Available Use% Mounted on
/dev/mapper/ubtu16x640_lvg0-ubtu16x640_root0 104517165056 11263893504 87920427008  12% /
Python script on /
(Python) - Volume name  104517165056 11263893504 87920427008 10.777% (11) /


df /media/sf_shared_00
Filesystem     1K-blocks      Used Available Use% Mounted on
shared_00      327679996 155279796 172400200  48% /media/sf_shared_00
df -B 1 /media/sf_shared_00
Filesystem        1B-blocks         Used    Available Use% Mounted on
shared_00      335544315904 159006511104 176537804800  48% /media/sf_shared_00
Python script on /media/sf_shared_00
(Python) - Volume name  335544315904 159006511104 176537804800 47.388% (47) /media/sf_shared_00

Как видно, числа (размеры) с шага # 2. идентичны числам с шага # 3. .Вычисляя процент (в любом из 3 случаев), процент Python кажется правильным.

Мне неясно, почему df сообщает эти проценты (не смотрел в исходном коде), но это могло бы быть ( все, что приходит, является чистой спекуляцией ):

  • Это имеет тенденцию быть защитным для пользователя (сообщая немного больший процентчем на самом деле)
  • Это имеет отношение к логическим дискам (секторам).
    Например, на секторном диске 4 КиБ ( 4096 ) файл размером 4097 байт будет занимать (обычно 4097 байт), но с учетом того факта, что логическая единица дискасектор (а не байт - это как-то похоже на #pragma pack), файл будет занимать 2 сектора ( 8 КиБ ), и поэтому его базовый размер будет больше, чем сообщаемый
2 голосов
/ 03 июля 2019

Как уже указывалось ChristiFati , коэффициенты used / total одинаковы для обоих инструментов, но поле Use%, сообщаемое df, отличается от 100 · used / total.

В качестве примера рассмотрим значения для /dev/sda1, смонтированные на /.

df.total = 472437724
df.used = 231418380
df.available = 216997128
df.percentage = 52

shutil.total = 483776229376
shutil.used = 236973805568
shutil.free = 222203674624

df.used / df.total = 0,4898 = shutil.free / shutil.total
но…
df.used / df.total = 0,4898 & emsp; & emsp; 0,52 = df.percentage / 100

Исходный код реализации df coreutils проливает некоторый свет на эту проблему. три строки 1171-1173 актуальны. pct это процент.

uintmax_t u100 = v->used * 100; uintmax_t nonroot_total = v->used + v->available; pct = u100 / nonroot_total + (u100 % nonroot_total != 0);

Как мы видим, df вычисляет не used / total, а used / (used + free). Обратите внимание, что used + free < total.

Я подозревал, что ...

total включает в себя пространство, которое зарезервировано для метаданных, например, где файл находится в файловой системе (в зависимости от файловой системы это может включать в себя толстые таблицы, inode, ...). Поскольку вы не можете использовать это пространство для обычных файлов, это пространство исключается в Use% с помощью (used + free), который не включает метаданные.

Однако тест показал, что ...

это не может быть полной историей. Следующий скрипт генерирует файловую систему FAT12 и ext2 внутри файла размером 2 МБ. Сценарий должен быть выполнен с использованием sudo.

#! /bin/bash

check() {
  head -c 2MiB /dev/zero > fs
  mkfs."$@" fs
  mkdir fsmount
  mount -o loop fs fsmount
  df fsmount
  umount fsmount
  rm -r fs fsmount
}

echo fat12:
check fat -F 12

echo ext2:
check ext2

Я получил вывод

fat12:
[...]
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/loop0          2028     0      2028   0% /tmp/fsmount
ext2:
[...]                           
Creating filesystem with 2048 1k blocks and 256 inodes
[...]
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/loop0          2011    21      1888   2% /tmp/fsmount

Обратите внимание, что оба общих размера меньше, чем файловая система, которая составляет 2048 КиБ = 2 МиБ в обоих случаях. Обе файловые системы вообще не имели файлов, но для ext2 df сообщалось об использовании 21 КиБ (может быть связано с этим вопросом ).

0 голосов
/ 01 июля 2019

Когда-то 1 Гбайт был 1024 Мегабайта, но производители облажались с этой рутиной после того, как обнаружили маркетинговый трюк для вызова 50000 Мегабайт с именем 50 Гб.

Так что разница в том, как работают эти программные реализациис этими Megas, как 1000 или 1024.

...