13-bo‘lim

Fayl tizimining ichki tuzilishi

Superblok, inode, blok ajratish, bilvosita bloklar, ekstentlar, jurnal (journaling), ext4 va boshqa fayl tizimlari.

🕑 18 daqiqa o‘qish 📄 969 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Diskning umumiy tuzilishi
  2. inode nima?
  3. Bloklarni ajratish usullari
  4. Bilvosita bloklar
  5. Ekstentlar - ext4 ning yechimi
  6. Jurnal (journaling)
  7. Fayl tizimlarini taqqoslash
  8. inode tugashi
  9. Fayl tizimini tekshirish
  10. Xulosa

Diskda faqat raqamlangan bloklar bor. "Fayl", "katalog", "nom" tushunchalari - fayl tizimi yaratgan tuzilmalar.

Diskning umumiy tuzilishi #

Diskdagi soha tuzilishi Yuklash bloki Superblok meta-ma'lumot inode bitmap blok bitmap bo'sh joy xaritasi inode jadvali fayl xossalari Ma'lumot bloklari fayl mazmuni va katalog yozuvlari (diskning 95%+ qismi) Superblokda nima bor? Blok hajmi, jami bloklar soni Bo'sh bloklar va inode lar soni Fayl tizimi turi va holati inode da nima bor? Hajm, egasi, guruh, huquqlar Uch vaqt tamg'asi, havolalar soni Ma'lumot bloklari manzillari
Superblok buzilsa butun fayl tizimi o'qilmaydi - shuning uchun uning nusxalari saqlanadi
Terminal
sudo dumpe2fs -h /dev/sda1
Natija
Filesystem volume name:   <none>
Filesystem features:      has_journal ext_attr dir_index extent 64bit
Filesystem state:         clean
Inode count:              6553600
Block count:              26214400
Free blocks:              14829213
Free inodes:              6098442
First block:              0
Block size:               4096
Inode size:               256
Journal size:             1024M

inode nima? #

C
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main(void) {
    FILE *f = fopen("inode_sinov.txt", "w");

    if (f == NULL) {
        return 1;
    }

    fputs("salom", f);
    fclose(f);

    struct stat h;
    stat("inode_sinov.txt", &h);

    printf("inode raqami   : %s\n", h.st_ino > 0 ? "mavjud" : "yo'q");
    printf("Havolalar      : %ld\n", (long) h.st_nlink);
    printf("Hajm           : %ld bayt\n", (long) h.st_size);
    printf("Blok hajmi     : %ld bayt\n", (long) h.st_blksize);
    printf("Egallagan blok : %ld (512 baytli)\n", (long) h.st_blocks);

    /* Ikkinchi nom qo'shamiz */
    link("inode_sinov.txt", "ikkinchi_nom.txt");
    stat("inode_sinov.txt", &h);

    printf("\nQattiq havoladan keyin:\n");
    printf("Havolalar      : %ld\n", (long) h.st_nlink);
    printf("Hajm o'zgardimi? %s\n", h.st_size == 5 ? "yo'q" : "ha");

    unlink("ikkinchi_nom.txt");
    unlink("inode_sinov.txt");

    return 0;
}
Natija
inode raqami   : mavjud
Havolalar      : 1
Hajm           : 5 bayt
Blok hajmi     : 4096 bayt
Egallagan blok : 8 (512 baytli)

Qattiq havoladan keyin:
Havolalar      : 2
Hajm o'zgardimi? yo'q
Terminal
ls -li
Natija
4521234 -rw-r--r-- 2 husanboy husanboy 5 sen  9 10:22 ikkinchi_nom.txt
4521234 -rw-r--r-- 2 husanboy husanboy 5 sen  9 10:22 inode_sinov.txt

Birinchi ustun - inode raqami. Ikkala nom bir xil raqamga ega.

Bloklarni ajratish usullari #

UsulG'oyaKamchiligi
UzluksizFayl ketma-ket bloklardaFragmentatsiya, o'sish qiyin
Bog'langan ro'yxatHar blok keyingisiga ishoraTasodifiy kirish sekin
FATRo'yxat alohida jadvaldaJadval katta, RAM da turishi kerak
inode (bilvosita)Manzillar ro'yxati inode daKatta faylga qo'shimcha o'qish
Ekstent(boshlanish, uzunlik) juftliklariJuda parchalangan faylda samarasiz

Bilvosita bloklar #

ext2 uslubidagi bilvosita bloklar inode 12 ta to'g'ridan- to'g'ri manzil = 48 KB 1-bilvosita 2-bilvosita 3-bilvosita 1024 manzil = 4 MB 1024 blok = 4 GB 1024 blok 1024 blok = 4 TB Nima uchun shunday? Kichik fayllar (48 KB gacha) - qo'shimcha o'qishsiz Katta fayllar esa baribir imkoniyat topadi
Fayllar ko'pincha kichik - shuning uchun tez yo'l ular uchun optimallashtirilgan
C
#include <stdio.h>

#define BLOK        4096
#define MANZIL       4                  /* bitta manzil 4 bayt */
#define TOGRI       12

int main(void) {
    long manzil_blokda = BLOK / MANZIL;          /* 1024 */

    long togri = (long) TOGRI * BLOK;
    long bir = manzil_blokda * BLOK;
    long ikki = manzil_blokda * manzil_blokda * BLOK;
    long uch = manzil_blokda * manzil_blokda * manzil_blokda * BLOK;

    printf("Bitta blokda %ld ta manzil sig'adi\n\n", manzil_blokda);

    printf("To'g'ridan-to'g'ri : %8ld KB\n", togri / 1024);
    printf("1-bilvosita        : %8ld KB\n", bir / 1024);
    printf("2-bilvosita        : %8ld MB\n", ikki / (1024 * 1024));
    printf("3-bilvosita        : %8ld GB\n", uch / (1024 * 1024 * 1024));

    long jami = togri + bir + ikki + uch;
    printf("\nMaksimal fayl hajmi: %ld GB\n", jami / (1024 * 1024 * 1024));

    /* Katta faylning oxirgi bloki uchun nechta o'qish kerak? */
    printf("\n48 KB gacha fayl uchun o'qish: 1 ta (inode dagi manzil)\n");
    printf("4 TB fayl oxiri uchun o'qish : 4 ta (3 bilvosita + blok)\n");

    return 0;
}
Natija
Bitta blokda 1024 ta manzil sig'adi

To'g'ridan-to'g'ri :       48 KB
1-bilvosita        :     4096 KB
2-bilvosita        :     4096 MB
3-bilvosita        :     4096 GB

Maksimal fayl hajmi: 4100 GB

48 KB gacha fayl uchun o'qish: 1 ta (inode dagi manzil)
4 TB fayl oxiri uchun o'qish : 4 ta (3 bilvosita + blok)

Ekstentlar - ext4 ning yechimi #

C
#include <stdio.h>

typedef struct {
    long boshlanish;               /* birinchi blok raqami */
    long uzunlik;                  /* nechta ketma-ket blok */
} Ekstent;

int main(void) {
    /* 1 GB lik fayl, 4 KB bloklar = 262144 blok */
    long bloklar = 262144;

    /* Bilvosita usulda har bir blok uchun alohida manzil */
    long bilvosita_manzillar = bloklar;
    long bilvosita_bayt = bilvosita_manzillar * 4;

    /* Ekstent usulida: fayl 3 bo'lakda joylashgan bo'lsin */
    Ekstent ekstentlar[3] = {
        { 100000, 131072 },
        { 400000,  65536 },
        { 700000,  65536 }
    };

    long ekstent_bayt = 3 * sizeof(Ekstent);
    long jami = 0;

    for (int i = 0; i < 3; i++) {
        jami += ekstentlar[i].uzunlik;
    }

    printf("1 GB fayl = %ld ta blok\n\n", bloklar);
    printf("Bilvosita usul : %ld ta manzil = %ld KB meta-ma'lumot\n",
           bilvosita_manzillar, bilvosita_bayt / 1024);
    printf("Ekstent usuli  : 3 ta yozuv = %ld bayt meta-ma'lumot\n",
           ekstent_bayt);

    printf("\nEkstent bilan qamralgan bloklar: %ld\n", jami);
    printf("Hammasi qamraldimi? %s\n", jami == bloklar ? "ha" : "yo'q");
    printf("Meta-ma'lumot necha barobar kam? %ld\n",
           bilvosita_bayt / ekstent_bayt);

    return 0;
}
Natija
1 GB fayl = 262144 ta blok

Bilvosita usul : 262144 ta manzil = 1024 KB meta-ma'lumot
Ekstent usuli  : 3 ta yozuv = 48 bayt meta-ma'lumot

Ekstent bilan qamralgan bloklar: 262144
Hammasi qamraldimi? ha
Meta-ma'lumot necha barobar kam? 21845
Ekstent nima uchun samarali

Ekstent - bu (boshlanish bloki, uzunlik) juftligi. Bitta yozuv minglab ketma-ket blokni ifodalaydi.

Fayl turiEkstent soni
Yangi yozilgan video1-5 ta
Uzoq o'sgan log fayl100+ ta
Ma'lumotlar bazasi fayliO'nlab

Bu fragmentatsiya darajasiga bog'liq. Faylni ko'rish:

Terminal
filefrag -v katta.iso
Natija
Filesystem type is: ef53
File size of katta.iso is 4700372992 (1147552 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   flags:
   0:        0..   32767:    1245184..   1277951:  32768:
   1:    32768..   65535:    1277952..   1310719:  32768:
katta.iso: 36 extents found

36 ta ekstent - juda yaxshi natija. 4.7 GB fayl uchun bilvosita usulda 1.1 million manzil kerak bo'lardi.

Jurnal (journaling) #

Jurnalsiz va jurnalli fayl tizimi Jurnalsiz: tok o'chdi 1. inode yangilandi (hajm = 8 KB) 2. blok bitmap - YOZILMADI 3. ma'lumot bloki - YOZILMADI Fayl tizimi nomuvofiq holatda fsck butun diskni tekshiradi (soatlab) Jurnalli: tok o'chdi 1. Jurnalga "nima qilaman" yoziladi 2. Jurnalga "tayyor" belgisi 3. Haqiqiy joyga yozish - uzildi Jurnal qayta o'ynatiladi Tiklanish bir necha soniyada Narxi: har o'zgarish ikki marta yoziladi Shuning uchun odatda faqat meta-ma'lumot jurnallanadi
Jurnal - ishonchlilik va tezlik orasidagi kelishuv
RejimNima jurnallanadiXavfsizlikTezlik
journalMeta-ma'lumot va ma'lumotEng yuqoriEng sekin
orderedFaqat meta; ma'lumot avval yoziladiYaxshiOdatiy
writebackFaqat meta, tartibsizPastTez
Terminal
mount | grep " / "
Natija
/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro)
Terminal
sudo tune2fs -l /dev/sda1 | grep -i journal
Natija
Filesystem features:      has_journal ext_attr resize_inode dir_index
Journal inode:            8
Journal backup:           inode blocks
ordered rejim ham hamma narsani kafolatlamaydi

ordered (Linux dagi odatiy rejim) faqat shuni kafolatlaydi: meta-ma'lumot ma'lumotdan keyin yoziladi.

Ya'ni siz hech qachon "fayl hajmi 8 KB, lekin ichida axlat" holatiga tushmaysiz.

Lekin write() qaytgani ma'lumot diskda degani emas - u faqat yadro keshida bo'lishi mumkin.

Kafolat kerak bo'lsa:

C
write(fd, malumot, hajm);
fsync(fd);                  /* endi haqiqatan diskda */

Yangi fayl yaratgan bo'lsangiz, katalogni ham sinxronlash kerak:

C
int kd = open("katalog", O_RDONLY | O_DIRECTORY);
fsync(kd);
close(kd);

Aks holda fayl mazmuni saqlanadi, lekin uning nomi yo'qoladi.

Fayl tizimlarini taqqoslash #

Fayl tizimiYilKuchli tomoniQayerda ishlatiladi
FAT321996Hamma joyda o'qiladiUSB fleshka
NTFS1993Jurnal, huquqlar, siqishWindows
ext42008Barqaror, tez, ekstentlarLinux odatiy
XFS1994Katta fayllar, parallel I/OServerlar
Btrfs2009Snapshot, nusxa-yozishdaOpenSUSE, NAS
ZFS2005Butunlik tekshiruvi, RAIDMa'lumot omborlari
APFS2017SSD ga moslashgan, shifrlashmacOS, iOS
Terminal
df -Th
Natija
Filesystem     Type   Size  Used Avail Use% Mounted on
/dev/sda1      ext4   100G   42G   53G  45% /
/dev/sda2      vfat   512M  6.1M  506M   2% /boot/efi
tmpfs          tmpfs  7.8G   84M  7.7G   2% /dev/shm

inode tugashi #

C
#include <stdio.h>

int main(void) {
    /* 100 GB disk, 4 KB bloklar */
    long disk_gb = 100;
    long blok = 4096;
    long bloklar = disk_gb * 1024 * 1024 * 1024 / blok;

    /* ext4 odatda har 16 KB ga bitta inode ajratadi */
    long inodelar = disk_gb * 1024 * 1024 * 1024 / (16 * 1024);

    printf("Disk hajmi   : %ld GB\n", disk_gb);
    printf("Bloklar soni : %ld\n", bloklar);
    printf("inode lar    : %ld\n\n", inodelar);

    /* Agar hamma fayl 1 KB bo'lsa nima bo'ladi? */
    long mayda_fayllar = inodelar;
    long ishlatilgan_gb = mayda_fayllar * blok / (1024 * 1024 * 1024);

    printf("Agar barcha fayl 1 KB bo'lsa:\n");
    printf("  Sig'adigan fayl soni : %ld ta\n", mayda_fayllar);
    printf("  Egallangan disk      : %ld GB\n", ishlatilgan_gb);
    printf("  Disk to'ladimi?      : %s\n",
           ishlatilgan_gb >= disk_gb ? "ha" : "yo'q - inode tugadi!");

    return 0;
}
Natija
Disk hajmi   : 100 GB
Bloklar soni : 26214400
inode lar    : 6553600

Agar barcha fayl 1 KB bo'lsa:
  Sig'adigan fayl soni : 6553600 ta
  Egallangan disk      : 25 GB
  Disk to'ladimi?      : yo'q - inode tugadi!
"No space left on device", lekin df bo'sh joy ko'rsatadi

Bu klassik holat - inode lar tugagan:

Terminal
df -i
Natija
Filesystem      Inodes   IUsed IFree IUse% Mounted on
/dev/sda1      6553600 6553600     0  100% /

IUse% 100% - yangi fayl yaratib bo'lmaydi, garchi df -h 75 GB bo'sh ko'rsatsa ham.

Sabab odatda:

  • Kesh katalogida millionlab mayda fayl;
  • Sessiya fayllari tozalanmagan;
  • Mail queue to'lib ketgan.

Aybdorni topish:

Terminal
sudo du --inodes -x -d 1 / | sort -rn | head

inode lar soni fayl tizimi yaratilganda belgilanadi va keyin o'zgartirib bo'lmaydi. Mayda fayllar ko'p bo'ladigan disk uchun oldindan sozlang:

Terminal
mkfs.ext4 -i 8192 /dev/sdb1      # har 8 KB ga bitta inode

XFS va Btrfs da inode lar dinamik ajratiladi - bu muammo yo'q.

Fayl tizimini tekshirish #

Terminal
sudo umount /dev/sdb1
sudo fsck.ext4 -f /dev/sdb1
Natija
e2fsck 1.46.5 (30-Dec-2021)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sdb1: 11/65536 files (0.0% non-contiguous), 8896/262144 blocks
fsck ni ulangan diskda ishlatmang

Ulangan (mounted) fayl tizimini fsck bilan tuzatish uni butunlay buzishi mumkin - yadro va fsck bir vaqtda bir xil tuzilmalarni o'zgartiradi.

To'g'ri tartib:

  1. umount bilan uzing;
  2. Ildiz bo'lsa - jonli USB dan yuklaning;
  3. Muhim ma'lumot bo'lsa - avval dd bilan to'liq nusxa oling.

lost+found katalogi - fsck topgan, lekin nomi yo'qolgan fayllar shu yerga qo'yiladi (inode raqami nom sifatida).

Amaliy topshiriq
  1. stat bilan faylning inode raqami va bloklarini ko'ring.
  2. Qattiq havola yaratib, ls -li da inode bir xilligini tasdiqlang.
  3. Bilvosita bloklar bilan maksimal fayl hajmini hisoblang.
  4. Ekstent va bilvosita usulning meta-ma'lumot hajmini solishtiring.
  5. filefrag -v bilan katta faylning ekstentlarini ko'ring.
  6. dumpe2fs -h bilan superblok ma'lumotini o'qing.
  7. mount chiqishida jurnal rejimini aniqlang.
  8. df -h va df -i farqini tushuntiring.
  9. inode tugashi ssenariysini hisoblab chiqing.
  10. du --inodes bilan eng ko'p fayl saqlagan katalogni toping.

Xulosa #

  • Disk sohalari: yuklash bloki, superblok, bitmaplar, inode jadvali, ma'lumot bloklari.
  • Superblok fayl tizimi haqidagi asosiy ma'lumotni saqlaydi.
  • inode faylning hamma xossasini saqlaydi - nomidan tashqari.
  • Bilvosita bloklar kichik fayllarni tez, kattalarini imkonli qiladi.
  • Ekstentlar meta-ma'lumotni minglab barobar kamaytiradi.
  • Jurnal tok o'chganda tiklanishni soniyalarga qisqartiradi.
  • ordered rejim odatiy: meta ma'lumotdan keyin yoziladi.
  • write qaytgani diskda degani emas - kafolat uchun fsync.
  • Yangi fayl uchun katalogni ham fsync qiling.
  • inode lar tugashi disk to'lishidan mustaqil muammo.
  • fsck ni faqat uzilgan fayl tizimida ishlating.

Keyingi bo'limda kiritish-chiqarish va qurilmalarni ko'ramiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.