Назад | Перейти на главную страницу

Распечатать неиспользуемые байты логического тома

Представьте, что размер физического тома изменился:

pvresize /dev/sda2 

Размер логического тома был изменен:

lvresize -l +100%FREE system/home

Но эта команда не была выполнена:

resize2fs /dev/mapper/system-home

Поскольку последняя команда была забыта, осталось неиспользуемое пространство.

Как посчитать неиспользованные байты?

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

Кстати: я не доверяю сценариям оболочки.

Размер всего блочного устройства по умолчанию, плюс онлайн-рост, делают ненужную проверку размера. Бегать resize2fs во всех ваших файловых системах.

(Если у вас есть вариант использования, который требует размера, отредактируйте свой вопрос.)

Предотвратите повторное забывание файловой системы, добавив lvresize --resizefs к вашим скриптам или псевдонимам оболочки.


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

Шаг 1 : определить границы файловой системы

dumpe2fs -h /dev/mapper/system-home | grep -E "^Block count|^Block size"

вы получите общий размер файловой системы с этими двумя числами, пример ниже:

Block count:              98304
Block size:               1024    (which is 1k)
FS size = 98304 = **96MB**

Шаг 2 : определить границы блочного устройства

а) определите dm, связанный с вашим логическим томом readlink -f /dev/mapper/system-home что дает вам / dev / dm-XX

б) определить границы / dev / dm-XX cat /sys/block/dm-XX/size что дает вам общий размер в блоках (512 байт). Если размер 300000 блоков, то у вас немного меньше 150 МБ на блочном устройстве

150-96 марок ~ 54 МБ свободного места в файловой системе

Я решаю проблему изменения размера с помощью сценария, который находит все задействованные блочные устройства и соответственно распечатывает им команды изменения размера.

https://github.com/mircea-vutcovici/scripts/blob/master/vol_resize.sh

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

Например. Представьте себе такой макет:

  • Многопутевость для LUN
  • таблица разделов
  • lvm
  • dmcrypt
  • zfs
  • zfs zvol

Как узнать размер:

  • блочные устройства: blockdev --getsz sdX, grep . /sys/block/*/size
  • lvm: pvs
  • ext2, 3, 4: dumpe2fs /dev/sdX|egrep '^Block (count|size):'
  • zfs: zpool status, zpool list, zfs list
  • btrfs:
  • xfs: xfs_info
  • сопоставитель устройств: dmsetup table
  • смонтированные файловые системы: df

Другие перечислили инструменты, которые можно использовать для ответа на ваш вопрос, но я хотел создать реальную рабочую реализацию, которую вы могли бы использовать. Итак, я написал сценарий bash, который делает именно то, что вы просите: сообщать, сколько свободного места в конце LV еще не занято FS (например, когда кто-то забывает вырастить сам FS).

Я должен отметить, что, поскольку определение размера файловой системы зависит от инструментов этой файловой системы, вы должны персонализировать ее для того, какие файловые системы вы используете для своих дисков LVM. Я лично использую и XFS, и EXT4, поэтому приведенный ниже сценарий реализует их оба. В частности, мне пришлось использовать tune2fs для EXT4 и xfs_info для XFS.

lvfree.sh

#!/bin/bash

# Header
printf '%-20s %-7s %8s %8s %8s\n' Mountpoint FS_Type LV_Size FS_Size LV_Free

lsblk -nlbo TYPE,FSTYPE,MOUNTPOINT,PATH,SIZE | grep -E '^lvm +(ext4|xfs)' | while read TYPE FSTYPE MOUNTPOINT PAATH SIZE; do
  if [[ $FSTYPE == 'ext4' ]] ; then
    FSSIZE=$(tune2fs -l $PAATH | grep -E '(Block count|Block size)' | awk 'BEGIN{x=1}{x=x*$NF}END{print x}') 
  elif [[ $FSTYPE == 'xfs' ]] ; then
    FSSIZE=$(xfs_info $MOUNTPOINT | grep ^data | /bin/tr = ' ' | awk '{print $3*$5}')
  fi
  LVFREE=$((SIZE - FSSIZE))
  printf '%-20s %-7s %8d %8d %8d\n' $MOUNTPOINT $FSTYPE $((SIZE/1024/1024)) $((FSSIZE/1024/1024)) $((LVFREE/1024/1024))
done

Тестируем это

Сначала я продлеваю пару своих LV, но забываю продлить FS

[root@xps joshua]# lvextend -L +1G /dev/vg1/home
 Size of logical volume vg1/home changed from 90.00 GiB (23040 extents) to 91.00 GiB (23296 extents).
 Logical volume vg1/home successfully resized.

[root@xps ~]# lvextend -L +256M /dev/vg1/usr
 Size of logical volume vg1/usr changed from 25.00 GiB (6400 extents) to 25.25 GiB (6464 extents).
 Logical volume vg1/usr successfully resized.

Теперь запускаю скрипт и вижу свободное место в LV

[root@xps ~]# ./lvfree.sh 
Mountpoint           FS_Type  LV_Size  FS_Size  LV_Free
/                    ext4        5120     5120        0
/var                 ext4       24576    24576        0
/var/log             ext4       20480    20480        0
/usr                 ext4       25856    25600      256
/home                xfs        93184    92160     1024
/tmp                 ext4       10240    10240        0
/opt                 ext4        5120     5120        0

Теперь я не забыл расширить файловые системы XFS и EXT4:

[root@xps ~]# xfs_growfs /home
meta-data=/dev/mapper/vg1-home   isize=256    agcount=8, agsize=3276800 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0, sparse=0, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=23592960, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=65536  ascii-ci=0, ftype=0
log      =internal log           bsize=4096   blocks=6400, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 23592960 to 23855104

[root@xps ~]# resize2fs /dev/mapper/vg1-usr 
resize2fs 1.45.3 (14-Jul-2019)
Filesystem at /dev/mapper/vg1-usr is mounted on /usr; on-line resizing required
old_desc_blocks = 2, new_desc_blocks = 2
The filesystem on /dev/mapper/vg1-usr is now 6619136 (4k) blocks long.

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

[root@xps ~]# ./lvfree.sh 
Mountpoint           FS_Type  LV_Size  FS_Size  LV_Free
/                    ext4        5120     5120        0
/var                 ext4       24576    24576        0
/var/log             ext4       20480    20480        0
/usr                 ext4       25856    25856        0
/home                xfs        93184    93184        0
/tmp                 ext4       10240    10240        0
/opt                 ext4        5120     5120        0

Сноска: PAATH в моем сценарии не опечатка. Мне пришлось не использовать имя переменной PATH, поскольку оно имеет зарезервированное значение в сценариях оболочки.

Просто используя функции:

crtdev=/dev/sda9
crtdev=/dev/Vol-1/Root
  1. Размер устройства (реальный):

    { read devsz;read devss;}< <(blockdev --getsz --getss $crtdev)
    devsize=$((devsz*devss))
    

    Примечание: Вы могли бы использовать lsblk чтобы перечислить устройства с размерами:

    lsblk -no KNAME,NAME,SIZE
    

    Это может быть полезно в скрипте ... Смотрите дальше!

  2. Размер файловой системы (текущий)

    1. для ext2|ext3|ext4:

      while IFS=$':\t\r\n' read fld val;do
          case $fld in
               Block\ size)  fsbs=$val;;
               Block\ count) fssz=$val;;
           esac
      done < <(dumpe2fs 2>&1 -h $crtdev)
      fssize=$((fssz*fsbs))
      
    2. для xfs:

      Информация XFS не будет выполняться на подключенных устройствах, вместо этого вы должны использовать mont-point:

      mntpnt=/mnt
      while IFS=$' =,\t\r\n' read -a lne;do
          [ "$lne" = "data" ] &&
              fsbs=${lne[2]} fssz=${lne[4]}
      done < <( xfs_info $mntpnt )
      fssize=$((fssz*fsbs))
      
    3. для ntfs:

      Кажется, с этим все не так просто ... Так как я ими не часто пользуюсь, даже если уже использовал ntfsresize в прошлом. Есть что-то:

      read fsinfo < <(file -bs $1)
      fssz=${fsinfo#*, sectors } fssz=${fssz%%,*}
      fssize=$(( 512 * ( fssz + 1 ) ))
      

      Примечание: ненавижу это: я не мог объяснить + 1 и некоторые из моих тестовых работ с + 8 вместо...

Тогда наконец

printf "Dev: %d - FS: %d = Unused: %d\n" $devsize $fssize $(( devsize - fssize ))

Скрипт с использованием lsblk для сканирования всех устройств:

Этот сценарий, запущенный без аргументов, будет печатать одну строку по устройству, у которого diff не null. Запуск с любым (фиктивным) аргументом, будет печатать по одной строке для каждого xfs или ext[234] устройство.

Как это использовать с эффективным башизм и ограниченные вилки до lshw, dumpe2fs и / или xfs_info только этот сценарий требует очень мало ресурсов.

!! Чтобы работать как root или с sudo !!

#!/bin/bash
shopt -s extglob
declare -A KNAMES='()' # Prevent double check
infolog() {
    # Entering this with $kname, $size, $fs, $name, $fsbs and $fssz.
    fssize=$((fssz*fsbs))
    (( $# | size-fssize ))&& # Only if diffsize > 0 or if argument was submited
        printf "%-25s %-6s %15u %15u %14u\n" \
               ${NAME##*/} $FSTYPE $SIZE $fssize $((SIZE-fssize))
}
while read line; do  eval "$line"
    [ "${KNAMES[${KNAME##*/}]}" ] || case $FSTYPE in 
        ext* ) while IFS=$':\t\r\n' read fld val;do
                case $fld in
                    Block\ size)  fsbs=$val;;
                    Block\ count) fssz=$val;;
                esac
            done < <(dumpe2fs 2>&1 -h $KNAME)
            infolog $@ ;;
        xfs ) check=$KNAME
            [ "$MOUNTPOINT" ] && check="$MOUNTPOINT"
            while IFS=$' =,\t\r\n' read -a lne;do
                [ "$lne" = "data" ] &&
                    fsbs=${lne[2]} fssz=${lne[4]}
            done < <( xfs_info "$check" )
            infolog $@ ;;
        ntfs )
            read fsinfo < <(file -Lbs $KNAME)
            fssz=${fsinfo#*, sectors } fssz=${fssz%%,*}
            (( fssz += 1, fsbs=512 ))
            infolog $@ ;;
    esac
    KNAMES[${KNAME##*/}]="done"
done < <(lsblk -bnpPo KNAME,NAME,MOUNTPOINT,FSTYPE,SIZE)

(Это немного уменьшено, чтобы предотвратить полосы прокрутки SO;)

Пример выполнения (без аргументов):

./unused_bytes_by_dev.sh
Vol--I-XDATAS             xfs        48318382080     42949672960     5368709120
sdd1                      ext4        1010774016       175472640      835301376

С одним аргументом:

./unused_bytes_by_dev.sh dummy
md0                       ext4         246349824       246349824              0
Vol--I-ROOT               ext4        1610612736      1610612736              0
Vol--V-USR                ext4       31138512896     31138512896              0
Vol--I-VAR                ext4       22548578304     22548578304              0
Vol--I-HOME               ext4       34359738368     34359738368              0
Vol--I-XDATAS             xfs        48318382080     42949672960     5368709120
Vol--I-Win                ntfs       42949672960     42949672960              0
sdd1                      ext4        1010774016       175472640      835301376

df дает вам общий размер, как видно из FS, с -k - в КБ.

sudo blockdev --getsize64 дает вам чистый размер блочного устройства - в байтах.

Довольно просто преобразовать байты в килобайты и сравнить, есть ли между ними какая-либо значительная разница.

Чтобы получить неиспользуемые байты, вы должны получить таблицу разделов и взглянуть на границы разделов и границы файловой системы.

Есть несколько способов сделать это, поэтому я назову несколько из них.

fdisk

Это требует некоторого расчета. Вы можете видеть, сколько секторов на диске, и вы можете видеть количество секторов в начале и в конце каждого раздела, чтобы вы могли вычислить, осталось ли свободное место.

# fdisk -l /dev/nvme0n1
Disk /dev/nvme0n1: 477 GiB, 512110190592 bytes, 1000215216 sectors
Disk model: THNSN5512GPUK NVMe TOSHIBA 512GB        
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: B9E14CDC-1817-4552-9AD0-967A6FC9C4CE

Device            Start        End   Sectors  Size Type
/dev/nvme0n1p1     2048     411647    409600  200M EFI System
/dev/nvme0n1p2   411648    2508799   2097152    1G Linux filesystem
/dev/nvme0n1p3  2508800   18782207  16273408  7.8G Linux filesystem
/dev/nvme0n1p4 18782208 1000214527 981432320  468G Linux filesystem

расстались

Вы можете вызвать parted, чтобы распечатать свободное место в таблице разделов

# parted /dev/nvme0n1 print free
Model: THNSN5512GPUK NVMe TOSHIBA 512GB (nvme)
Disk /dev/nvme0n1: 512GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start   End     Size    File system  Name                  Flags
        17.4kB  1049kB  1031kB  Free Space
 1      1049kB  211MB   210MB   fat16        EFI System Partition  boot, esp
 2      211MB   1285MB  1074MB  ext4
 3      1285MB  9616MB  8332MB
 4      9616MB  512GB   502GB
        512GB   512GB   335kB   Free Space