Sparse File di Linux dan ESXi

Sparse file adalah file yang menggunakan penyimpanan di filesystem dengan efisien dengan hanya menyimpan blok yang tidak kosong. Setelah ngobrol dengan banyak orang, ternyata banyak yang masih belum paham konsep sparse file, sementara yang paham sparse file di Linux (atau sistem operasi lain yang kompatibel dengan POSIX), tidak tahu tentang implementasi, batasan dan tools yang tersedia di ESXi.

Pada file sparse, data blok 0 tidak disimpan

Pemahaman tentang sparse file ini sangat membantu ketika berurusan dengan virtual machine image (mengclone, membackup, mentransfer, dsb). Ini juga berguna ketika berurusan dengan recovery virtual machine yang terkena ransomware. Jika tidak paham berurusan dengan sparse file, maka ketika ukuran backup bisa membengkak (berkali lipat) dan waktu transfer lebih lama (berkali lipat).

Sebagai catatan: ESXi adalah sebuah hypervisor, yaitu suatu sistem software yang kegunaan utamanya untuk menjalankan sistem operasi. Secara sederhana, sebuah hypervisor ini adalah sebuah sistem operasi (sesuai definisi sistem operasi), jadi di tulisan ini, ketika saya menyebutkan “berbagai sistem operasi”, ESXi atau hypervisor lain saya anggap sebagai sistem operasi.

Konsep Sparse File

Sebuah file kadang memiliki banyak bagian yang “kosong” atau bytenya semuanya nol. Contoh yang paling umum adalah “disk image”, yaitu file yang mensimulasikan sebuah disk di virtual machine.

Ketika membuat virtual machine baru, kita akan mengalokasikan disk virtual, lalu menginstall sistem operasi. Jika kita ingin agar virtual machine memiliki disk 128GB, maka ada dua opsi: langsung mengalokasikan 128GB, lalu menuliskan byte 0 sebanyak 128 GB di disk, atau kita bisa membuat sparse file yang kira-kira hanya berisi informasi: file ini 128GB, tapi dari offset 0 sampai 128GB isinya adalah 0.

Ketika disk mulai diisi, misalnya 10GB pertama ditulis, maka sistem operasi akan mengupdate filesystem dengan informasi: ini pointer ke 10GB pertama, dan 118GB sisanya adalah 0. Jika 10 GB terakhir ditulis (tanpa menyentuh bagian tengah), maka informasinya adalah: pointer ke 10GB pertama, informasi bahwa dari 10GB-118GB, masih kosong, dan pointer ke data 118 GB-128GB.

Perhatikan bahwa space yang tidak dialokasikan ini seperti lubang (hole), jadi di berbagai tool dan API, nama opsinya memakai kata hole.

Dari sudut pandang program biasa (yang tidak khusus menangani file sparse): file yang sparse atau tidak sparse akan terlihat sama saja (ukuran dan isinya). JIka kita melakukan hashing (sha1/md5/apapun) hasilnya sama. Jika kita melakukan tail/head/cat, dsb, hasilnya juga tetap sama. File sparse bisa dikonversi menjadi tidak sparse, dan juga sebaliknya, dan isinya akan tetap sama persis.

Hal penting pertama yang perlu diketahui adalah: sparse file butuh dukungan sistem operasi dan filesystem. Sebagian besar filesystem modern mendukung sparse file, tapi beberapa tidak misalnya FAT/FAT32/exFAT yang biasanya dipakai di USB disk.

Sistem operasi menyediakan support untuk manipulasi sparse file, tapi supportnya berbeda untuk tiap OS. Ini yang membuat tool tertentu hanya tersedia di sistem operasi tertentu. Contohnya fallocate tidak tersedia di ESXi.

Eksperimen sparse file di Linux

Mari kita langsung bereksperimen dengan sparse file di Linux dengan filesystem ext4. Filesystem lain yang mendukung sparse file juga tidak apa-apa, tapi jangan dicoba di FAT/FAT32/exFAT, atau yang lain yang tidak memiliki support sparse file.

Jika kita sekedar membuat file berisi byte-byte 0, maka sistem operasi/filesystem biasanya tidak tahu hal ini, dan akan memakan space seperti biasa. Mari kita coba:

dd if=/dev/zero of=myfile bs=1MiB count=1

Ini akan membuat file yang berukuran 1 MB, ini bisa dicek dengan ls -hl myfile. Di disk, space yang dipakai juga 1 MB, du -hs myfile .

Sekarang file ini bisa kita ubah menjadi sparse:

fallocate -v --dig-holes myfile

Sekarang cek ukuran filenya: masih sama, hashnya: masih sama, tapi lihat disk usagenya, sekarang menjadi 0KB.

File yang benar-benar kosong memakan 0KB

Alternatif lain membuat file yang kosong saja (tidak makan disk space) adalah dengan truncate. Perhatikan: truncate akan selalu memotong atau memanjangkan file. Jadi jika tadinya filenya 2GB, dan kita truncate menjadi 1GB maka datanya 1 GB akan hilang tidak bisa dikembalikan. Sementara fallocate dengan --dig-holes akan menghapus blok-blok yang isinya 0 saja.

Membuat sparse file dengan truncate

File yang saya contohkan sebelumnya tersebut benar-benar “kosong” (isinya 0 semua), mari kita tambahkan teks di akhir dengan echo dan redirection.

Setelah ditambah “hello”, file ini memakan 4KB di disk

Hasilnya: ukuran file menjadi 4KB (ini ukuran blok standard di ext4). Ukuran blok ini penting: jika ada banyak byte 0 tapi tidak dalam posisi kelipatan 4KB, atau ukurannya kurang dari 4KB, maka ini tidak bisa dijadikan sparse. Sekarang coba kita edit dengan vi, editor yang tidak paham sparse file. Kita tambahkan hello di awal.

File diedit dengan editor yang tidak mengenal file sparse

Ketika dicek lagi, ukuran menjadi 1.1Mb, karena semua 0 disimpan. Kita bisa buat menjadi sparse lagi dengan fallocate lagi, dan ukuran sekarang menjadi 8KB.

Membuat sparse dengan fallocate

Adakah cara lain untuk membuat sparse file selain dengan fallocate? selain membuat program sendiri, kita bisa memakai cp atau dd. Perhatikan bahwa ada banyak versi cp dan dd, saya memakai versi cp dan dd dari coreutils (default di Debian/Ubuntu). Opsi cp dan dd di sistem operasi lain mungkin tidak sama.

Cara pertama adalah dengan membuat file dengan skip seek. dd if=/dev/zero of=test-big-file count=1 bs=1K seek=1MiB. Kedua adalah dengan membuat file yang tidak sparse (cara apapun), lalu kita buat copy-nya yang sparse: cp --sparse=always mybigfile mysparsefile

Cara lain adalah dengan program rsync, selain bisa digunakan untuk transfer file di jaringan, rsync juga bisa digunakan untuk membuat salinan file yang sparse di filesystem lokal:

rsync -S namafile namafile-sparse

Menyalin sparse file via jaringan

Jika kita langsung melakukan copy dengan scp/ftp, semua byte di file dibaca dan ditransfer (meskipun filenya sparse), jadi prosesnya bisa sangat lambat. Perhatikan betapa lamanya mengcopy file sparse 100GB yang hanya memakan space 4KB di disk (butuh lebih dari 17 menit di network gigabit). Di mesin target filenya tidak sparse jadi akan memakan 100GB. Jadi sebaiknya jangan melakukan ini ketika mengcopy virtual machine yang sparse.

Mentransfer file sparse butuh waktu lama

Alternatif pertama: kita tar dulu filenya, tapi harus dengan opsi --sparse (hanya tersedia di GNU tar). Dengan opsi ini, hanya bagian file yang tidak sparse yang akan masuk ke dalam hasil tar.

dengan men-tar dulu, ukuran file jadi lbih kecil, dan butuh waktu sangat cepat

Solusi ini cukup bagus, tapi tidak ideal karena kita butuh space sementara untuk menyimpan file .tar-nya. Misalnya yang ingin kita salin adalah virtual machine 256 GB dan 50%-nya sparse, maka kita butuh ekstra 128GB untuk file tar-nya.

Kita bisa melakukan akal-akalan untuk mempipe hasil output tar ke jaringan dan membaca langsung dari jaringan, tapi ini bisa bermasalah (jika ada interupsi, harus diulangi dari awal)

Alternatif lain yang lebih baik adalah dengan rsync, rsync memiliki opsi -S yang akan membuat file sparse. Masalahnya ini akan tetap butuh waktu sangat lama untuk mengcopy file karena data dibaca seperti file biasa, dan di tujuan akan diciptakan jadi file sparse.

Rsync punya opsi --inplace agar mengubah file tujuan jika ada perbedaan (tidak menghapus/membuat file baru), jika file tujuan sudah harus ada (jika belum maka sifatnya sama dengan rsync biasa). Supaya cepat: kita perlu membuat dulu file tujuan tapi sparse.

Kita bisa membuat file di tujuan dengan truncate. Pertama kita cari dulu ukuran file yang akan ditransfer dengan stat --c "%s" myfile, lalu kita ssh ke target dan jalankan truncate -s UKURAN myfile. Setelah itu rsync akan bisa berjalan sangat cepat (dalam contoh ini file 100GB sparse bisa ditransfer dalam kurang dari satu detik). Bisa dicek sebelum dan setelah transfer MD5-nya masih sama.

Transfer file dengan lebih dahulu mengalokasikan di remote

ESXi

ESXi mendukung sparse file, tapi sayangnya supportnya tidak sebagus Linux. Support ini baik di level API ataupun usermode program. Program fallocate dan truncate tidak tersedia (yang ekivalen tidak ada), tapi kita bisa memakai dd untuk membuat sparse file.

Sebagai catatan: ESXi mendukung binary Linux, tapi tidak semua library dan tidak semua syscall diimplementasikan. Kita tidak bisa sekedar menyalin fallocate atau truncate ke ESXi.

Hal penting pertama adalah: ukuran blok default di ESXi adalah 1MB, jika kita punya file sparse 1GB plus sedikit data, akan tetap makan 1MB (bukan 4KB seperti di Linux dengan ext3)

ukuran blok 1MB

Menyalin File

Kita bisa menyalin file-file di ESXI dengan dua cara: melalui command line (di terminal setelah melakukan ssh), atau melalui datastore browser. Datastore browser paham sparse file, dan akan mengcopy file sparse tetap jadi sparse. Sedangkan melalui ssh, program cp yang digunakan asalnya dari busybox yang tidak paham ini, jadi file sparse ketika dicopy menjadi tidak sparse.

file yang dicopy cp menjadi besar

Rsync tidak tersedia resmi di ESXi, tapi sudah ada yang mengcompile versi ESXi-nya: https://github.com/itiligent/RSYNC-ESXi. Dengan menyalin ini ke ESXi, kita bisa melakukan ini rsync -S namafile namafile.sparse.

Thick dan thin volume

Ketika membuat disk untuk virtual machine di ESXi, kita bisa mengalokasikan sebagai:

  • thin
  • thick
  • thick eager zeroed

Perbedaannya adalah:

  • thin: file sparse, jadi semua blok kosong tidak disimpan
  • thick: file tidak sparse, tapi isi disk tidak ditimpa dengan 0 saat itu juga, nanti jika diminta kali pertama, maka akan dikosongkan
  • thick eager zeroed: ketika disk ini dibuat, langsung semua isi disk akan dinolkan saat itu juga

Ketika melakukan transfer file, maka file thick akan dicopy sebagai thick, dan akan makan waktu lama dan disk space besar di target. Kita bisa melakukan hole punching pada file supaya jadi sparse, tapi ini hanya berlaku untuk file VMDK yang valid (bukan yang sekedar ekstensinya VMDK), jadi jika file VMDK ini terenkrip malware, maka tool ini tidak bekerja, file-file biasa juga tidak bisa dipunch hole-nya.

vmkfstools -K namafile.vmdk

Hole punching

Menangani sparse file dalam kode program

Jika kita melakukan seek ke posisi yang jauh ke depan (lebih dari ukuran blok), maka secara otomatis ini akan dianggap sebagai hole di Linux maupun ESXi, jadi kalau kita menulis satu byte, lalu maju 1Mb dan menulis byte lagi, space yang terpakai hanya 2 blok (8 KB).

Ketika membaca file, di Linux API lseek bisa melompat bagian hole dengan parameter whence SEEK_DATA, dan bisa pergi ke hole berikutnya dengan SEEK_HOLE, tapi ini tidak tersedia di ESXi.

Meskipun binary command line truncate tidak tersedia, tapi APItruncate tersedia di ESXi, dan bisa digunakan untuk membuat sparse file. Perhatikan bahwa kadang truncate ini gagal untuk file besar jika kita mentruncate tidak dalam kelipatan 1MB.

Di Linux di library C ada fallocate dan salah satu opsinya adalah FALLOC_FL_PUNCH_HOLE yang bisa digunakan untuk melakukan hole punching, ini tidak tersedia di ESXi. Setelah melakukan reverse engineering, FALLOC_FL_PUNCH_HOLE bisa diemulasikan dengan ioctl spesifik ESXi. API ini tidak terdokumentasi, dan mungkin bisa berubah antar versi ESXi.

Cara melakukan hole punching di ESXi

Penutup

Ilmu tentang sparse file ini sudah saya ketahui dari dulu, tapi ilmu spesifik ESXi saya pelajari baru-baru ini. Soal sparse file ini kadang muncul di CTF (silakan cari “ctf writeup sparse file”), jadi salah satu kegunaan ikut CTF adalah belajar hal random baru yang mungkin baru akan terpakai di masa depan.

Semoga ilmu sparse file ini berguna bagi pihak-pihak yang sering berurusan dengan file besar. Secara umum jika berurusan dengan file besar, terutama disk image:

  • jika ingin membackup, cari tahu apakah sourcenya sparse dan apakah bisa dibuat menjadi sparse
  • cari tahu apakah disk space akan cukup untuk membackup
  • cari tahu apakah metode transfer yang digunakan sudah efisien: apakah bisa mentransfer dengan cepat, dan apakah file sparse tetap sparse, atau bahkan lakukan konversi dari non-sparse menjadi sparse sambil mentransfer file
  • jika disk tidak cukup, dan berurusan dengan file terenkripsi, pertimbangkan membackup hanya bagian yang terenkrip saja dan keynya (lihat artikel saya sebelumnya tentang Babuk PDN)

Tinggalkan Balasan

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses.