
Hai, habrozhiteli! Kami sudah menulis tentang buku Michael Kerrisk
“Linux API. Panduan Lengkap .
" Sekarang kami telah memutuskan untuk menerbitkan kutipan dari buku “Mengelola File I / O Buffering yang Dikelola di Kernel”
Menyetel ulang memori buffer kernel untuk file output dapat dipaksa. Kadang-kadang ini diperlukan jika aplikasi, sebelum melanjutkan untuk bekerja (misalnya, proses login basis data berubah), harus memastikan bahwa output aktual ditulis ke disk (atau setidaknya ke cache disk perangkat keras).
Sebelum mempertimbangkan panggilan sistem yang digunakan untuk mengontrol buffering kernel, ada baiknya mempertimbangkan beberapa definisi terkait dari SUSv3.
I / O yang Disinkronkan dengan Integritas Data dan FileDalam SUSv3, konsep penyelesaian I / O tersinkronisasi berarti "operasi I / O yang mengarah pada keberhasilan transfer data [ke disk], atau didiagnosis tidak berhasil."
SUSv3 mendefinisikan dua jenis penghentian I / O yang disinkronkan. Perbedaan antara jenis terkait dengan metadata ("data tentang data") yang menggambarkan file. Kernel menyimpannya bersama dengan data dari file itu sendiri. Detail metadata file akan dibahas di bagian 14.4 saat memeriksa inode file. Sementara itu, akan cukup untuk dicatat bahwa metadata file mencakup informasi seperti informasi tentang pemilik file dan grupnya, hak akses ke file, ukuran file, jumlah tautan keras ke file, stempel waktu yang menunjukkan waktu file terakhir diakses, waktu terakhir diubah dan waktu perubahan metadata terakhir, serta pointer ke blok data.
Jenis penyelesaian I / O tersinkronisasi pertama di SUSv3 adalah penyelesaian integritas data. Saat memperbarui data file, transfer informasi yang memadai untuk memungkinkan ekstraksi lebih lanjut dari data ini untuk terus bekerja harus dipastikan.
- untuk operasi baca, ini berarti bahwa data file yang diminta telah ditransfer (dari disk) ke proses. Jika ada operasi penulisan yang tertunda yang dapat memengaruhi data yang diminta, data tersebut akan ditransfer ke disk sebelum dibaca.
- untuk operasi penulisan, ini berarti bahwa data yang ditentukan dalam permintaan penulisan ditransfer (ke disk), seperti semua metadata file yang diperlukan untuk mengekstrak data ini. Titik kunci untuk memperhatikan: untuk memastikan bahwa data diekstraksi dari file yang dimodifikasi, tidak perlu untuk mentransfer semua file medaten. Contoh atribut metadata dari file yang dimodifikasi yang perlu dimigrasi adalah ukurannya (jika operasi penulisan meningkatkan ukuran file). Sebaliknya, cap waktu file yang akan dimodifikasi tidak perlu ditransfer ke disk sebelum pengambilan data berikutnya terjadi.
Jenis kedua penyelesaian I / O tersinkronisasi yang didefinisikan dalam SUSv3 adalah penyelesaian integritas file. Ini adalah opsi lanjutan untuk menyelesaikan I / O yang disinkronkan dengan integritas data. Perbedaan antara mode ini adalah bahwa selama pembaruan file semua metadata-nya ditransfer ke disk, bahkan jika ini tidak diperlukan untuk ekstraksi data file selanjutnya.
Panggilan sistem untuk mengontrol buffering kernel selama file I / OPanggilan sistem fsync () me-reset semua data buffered dan semua metadata yang terkait dengan file terbuka yang memiliki deskriptor fd. Memanggil fsync () menempatkan file dalam status integritas (file) setelah selesainya I / O sinkron.
Panggilan fsync () mengembalikan kontrol hanya setelah transfer data ke perangkat disk (atau setidaknya ke cache-nya) selesai.
#include <unistd.h> int fsync(int fd);
Pengembalian sukses 0 atau -1 karena kesalahan
Panggilan sistem fdatasync () berfungsi persis seperti fsync (), tetapi menempatkan file dalam status integritas (data) setelah selesainya I / O sinkron.
#include <unistd.h> int fdatasync(int fd);
Pengembalian sukses 0 atau -1 karena kesalahan
Menggunakan fdatasync () berpotensi mengurangi jumlah operasi disk dari dua yang diperlukan oleh panggilan sistem fsync () menjadi satu. Misalnya, jika data file telah berubah, tetapi ukurannya tetap sama, memanggil fdatasync () hanya memaksa data untuk diperbarui. (Telah dicatat di atas bahwa untuk menyelesaikan operasi I / O sinkron dengan integritas data, tidak perlu mentransfer perubahan ke atribut seperti saat file terakhir dimodifikasi.) Sebaliknya, memanggil fsync () juga akan memaksa transfer metadata ke disk.
Pengurangan dalam jumlah operasi disk I / O akan berguna untuk aplikasi individual yang kinerjanya dan pembaruan metadata spesifik secara akurat (misalnya, stempel waktu) memainkan peran yang menentukan. Ini dapat menyebabkan peningkatan kinerja yang signifikan untuk aplikasi yang menghasilkan banyak pembaruan file sekaligus. Karena data file dan metadata biasanya terletak di berbagai bagian disk, memperbarui keduanya akan memerlukan pencarian maju dan mundur berulang pada disk.
Di Linux 2.2 dan sebelumnya, fdatasync () diimplementasikan sebagai panggilan ke fsync (), sehingga tidak memberikan peningkatan kinerja.
Dimulai dengan kernel versi 2.6.17, Linux menyediakan panggilan sistem non-standar sync_file_range (). Ini memungkinkan Anda untuk lebih mengontrol proses pembilasan data file ke disk daripada fdatasync (). Saat memanggil, Anda dapat menentukan area yang akan dijatuhkan dalam file dan mengatur flag yang mengatur kondisi untuk memblokir panggilan ini. Lihat halaman manual sync_file_range (2) untuk lebih jelasnya.
Panggilan sistem sinkronisasi () menyebabkan semua buffer kernel yang berisi informasi file yang diperbarui (mis. Blok data, blok pointer, metadata, dll.) Dibuang ke disk.
#include <unistd.h> void sync(void);
Dalam implementasi Linux, fungsi sync () mengembalikan kontrol hanya setelah semua data telah ditransfer ke perangkat disk (atau setidaknya ke cache-nya). Tetapi dalam SUSv3, diizinkan bahwa sinkronisasi () cukup memperkenalkan transfer data untuk operasi I / O ke dalam rencana dan mengembalikan kontrol hingga transfer selesai.
Thread kernel yang dieksekusi terus menerus mem-flush buffer kernel yang dimodifikasi ke disk jika tidak disinkronkan secara eksplisit selama 30 detik. Hal ini dilakukan untuk mencegah buffer data tidak sinkron dengan file disk yang sesuai untuk jangka waktu yang lama (dan tidak membuat mereka terpapar pada risiko kehilangan jika terjadi kegagalan sistem). Di Linux 2.6, tugas ini dilakukan oleh utas kernel pdflush. (Di Linux 2.4, ini dieksekusi oleh utas kernel yang didudukkan.)
Periode waktu (dalam seratus detik) setelah buffer yang dimodifikasi harus dibilas ke disk oleh kode aliran pdflush didefinisikan dalam file / proc / sys / vm / dirty_expire_centisecs. File tambahan di direktori yang sama mengontrol fitur lain dari operasi yang dilakukan oleh aliran pdflush.
Aktifkan mode sinkronisasi untuk semua catatan: O_SYNCMenentukan flag O_SYNC saat memanggil open () menyebabkan semua operasi output selanjutnya dilakukan dalam mode sinkron:
fd = open(pathname, O_WRONLY | O_SYNC);
Setelah panggilan ini untuk membuka (), setiap operasi write () yang dilakukan pada file secara otomatis mem-flush data dan file metadata ke disk (artinya, penulisan dilakukan sebagai operasi tulis yang disinkronkan dengan integritas file).
Dalam versi sistem BSD yang lebih lama, flag O_FSYNC digunakan untuk menyediakan fungsionalitas yang disertakan dengan flag O_SYNC. Dalam glibc, flag O_FSYNC didefinisikan sebagai sinonim untuk O_SYNC.
Dampak Kinerja Bendera O_SYNCMenggunakan flag O_SYNC (atau sering menelepon ke fsync (), fdatasync (), atau sync ()) dapat sangat memengaruhi kinerja. Di atas meja. Gambar 13.3 menunjukkan waktu yang diperlukan untuk menulis 1 juta byte ke file yang baru saja dibuat (dalam sistem file ext2) untuk berbagai ukuran buffer dengan flag O_SYNC ditetapkan dan tidak dicentang. Hasilnya diperoleh (menggunakan program filebuff / write_bytes.c yang disediakan dalam kode sumber untuk buku) menggunakan kernel "vanilla" versi 2.6.30 dan sistem file ext2 dengan ukuran blok 4096 byte. Setiap baris berisi nilai rata-rata yang diperoleh setelah 20 dimulai untuk ukuran buffer yang diberikan.
Tabel 13.3. Efek dari flag O_SYNC pada kecepatan tulis 1 juta byte
Seperti yang Anda lihat, menentukan flag O_SYNC mengarah ke peningkatan mengerikan dalam waktu yang dihabiskan saat menggunakan buffer 1 byte lebih dari 1000 kali. Harap perhatikan juga perbedaan besar yang terjadi saat menjalankan catatan dengan tanda O_SYNC antara waktu yang berlalu dan waktu penggunaan CPU. Ini adalah konsekuensi dari memblokir eksekusi program ketika konten aktual masing-masing buffer dibilas ke disk.
Dalam hasil yang ditunjukkan pada tabel. 13.3, faktor lain yang memengaruhi kinerja saat menggunakan O_SYNC tidak diperhitungkan. Disk drive modern memiliki cache internal yang besar, dan secara default pengaturan flag O_SYNC hanya mentransfer data ke cache ini. Jika Anda menonaktifkan caching disk (menggunakan perintah hdparm –W0), dampak kinerja O_SYNC akan menjadi lebih signifikan. Dengan ukuran buffer 1 byte, waktu yang berlalu akan meningkat dari 1030 detik menjadi sekitar 16.000 detik. Dengan ukuran buffer 4096 byte, waktu yang berlalu akan meningkat dari 0,34 detik menjadi 4 detik. Akibatnya, jika Anda perlu memaksa buffer kernel untuk mem-flush ke disk, Anda harus mempertimbangkan apakah Anda dapat mendesain aplikasi Anda menggunakan buffer yang lebih besar untuk write (), atau mempertimbangkan untuk menggunakan panggilan periodik fsync () atau fdatasync () daripada flag O_SYNC.
Tandai O_DSYNC dan O_RSYNCSUSv3 mendefinisikan dua flag status file-terbuka tambahan yang terkait dengan I / O yang disinkronkan: O_DSYNC dan O_RSYNC.
Bendera O_DSYNC menghasilkan operasi penulisan tersinkronisasi berikutnya dengan integritas data I / O yang diakhiri (mirip dengan menggunakan fdatasync ()). Efek operasinya berbeda dari efek yang disebabkan oleh flag O_SYNC, yang penggunaannya mengarah ke operasi tulis selanjutnya yang disinkronkan dengan integritas file (seperti fsync ()).
Bendera O_RSYNC ditentukan bersama dengan O_SYNC atau O_DSYNC dan mengarah ke ekstensi perilaku yang terkait dengan bendera ini selama operasi membaca. Menentukan flag O_RSYNC dan O_DSYNC saat membuka hasil file dalam operasi baca yang disinkronkan berikutnya dengan integritas data (yaitu, sebelum membaca selesai, semua entri file yang tertunda diselesaikan karena kehadiran O_DSYNC). Menentukan flag O_RSYNC dan O_SYNC ketika membuka file mengarah ke operasi baca yang disinkronkan berikutnya dengan integritas file (yaitu, sebelum membaca selesai, semua entri file yang tertunda diselesaikan karena kehadiran O_SYNC).
Sebelum rilis kernel versi 2.6.33, flag O_DSYNC dan O_RSYNC tidak diimplementasikan di Linux, dan konstanta ini didefinisikan dalam file header glibc sebagai pengaturan flag O_SYNC. (Dalam kasus O_RSYNC, ini tidak benar, karena O_SYNC tidak memengaruhi fitur fungsional operasi baca apa pun.)
Dimulai dengan kernel versi 2.6.33, Linux mengimplementasikan flag O_DSYNC, dan implementasi flag O_RSYNC kemungkinan akan ditambahkan dalam rilis kernel di masa depan.
Sebelum rilis kernel 2.6.33 di Linux, tidak ada implementasi semantik O_SYNC sepenuhnya. Sebaliknya, bendera O_SYNC diimplementasikan sebagai O_DSYNC. Dalam aplikasi yang terhubung dengan versi lama GNU C library untuk kernel yang lebih tua, pada Linux versi 2.6.33 dan yang lebih baru, flag O_SYNC masih berperilaku seperti O_DSYNC. Hal ini dilakukan untuk menjaga perilaku program-program semacam itu. (Untuk menjaga kompatibilitas biner mundur di kernel 2.6.33, flag O_DSYNC ditetapkan sebagai flag O_SYNC lama, dan flag O_SYNC baru termasuk flag O_DSYNC (masing-masing 04010000 dan 010000 pada salah satu mesin). Ini memungkinkan aplikasi dikompilasi dengan file header baru , dapatkan setidaknya semantik O_DSYNC dalam kernel yang dirilis sebelum versi 2.6.33.)
13.4. Ikhtisar Penyangga I / O
Dalam gbr. Gambar 13.1 menunjukkan skema buffering yang digunakan (untuk file output) oleh perpustakaan stdio dan kernel, dan juga menunjukkan mekanisme untuk mengendalikan setiap jenis buffering. Jika Anda turun grafik ke tengahnya, Anda akan melihat transfer data pengguna dengan fungsi perpustakaan stdio ke buffer stdio, yang bekerja di ruang memori pengguna. Ketika buffer ini penuh, perpustakaan stdio resor ke system call write (), yang mentransfer data ke cache buffer kernel (terletak di memori kernel). Sebagai hasilnya, kernel memulai operasi disk untuk mentransfer data ke disk.
Di bagian kiri sirkuit dalam gambar. 13.1 menunjukkan panggilan yang dapat digunakan kapan saja untuk secara paksa memaksa buffer apa pun. Bagian kanan menunjukkan panggilan yang dapat digunakan untuk secara otomatis melakukan reset, baik dengan mematikan buffering di perpustakaan stdio atau dengan menyalakan output file dari mode eksekusi sinkron untuk panggilan sistem, sehingga setiap panggilan tulis () akan segera dialihkan ke disk.
13.5. Kernel I / O Notification
Panggilan sistem posix_fadvise () memungkinkan proses untuk menginformasikan kernel tentang metode yang disukai untuk mengakses data file.
Kernel dapat (tetapi tidak harus) menggunakan informasi yang disediakan oleh pemanggilan sistem posix_fadvise () untuk mengoptimalkan penggunaan cache buffer, sehingga meningkatkan kinerja I / O untuk proses dan untuk sistem secara keseluruhan. Memanggil posix_fadvise () tidak memengaruhi semantik program.
#define _XOPEN_SOURCE 600 #include <fcntl.h> int posix_fadvise(int fd, off_t offset, off_t len, int advice);
Mengembalikan pada kesuksesan 0 atau angka kesalahan positif ketika itu terjadi
Argumen fd adalah deskriptor file yang mengidentifikasi file yang perlu dihubungi kernel. Argumen offset dan len mengidentifikasi area file yang terkait dengan notifikasi: offset menunjukkan offset awal area, dan len menunjukkan ukurannya dalam byte. Pengaturan len ke 0 berarti semua byte dimaksudkan, dimulai dengan ofset dan berakhir dengan akhir file. (Dalam versi kernel sebelum 2.6.6, nilai 0 untuk len diartikan secara harfiah sebagai 0 byte.)
Argumen saran menunjukkan sifat yang dimaksud dari akses proses ke file. Ini didefinisikan dengan salah satu dari nilai berikut.
POSIX_FADV_NORMAL - proses tidak memiliki pemberitahuan khusus mengenai pola perawatan. Ini adalah perilaku default jika tidak ada pemberitahuan yang diberikan untuk file tersebut. Di Linux, operasi ini menetapkan jendela untuk secara proaktif membaca data dari file ke ukuran aslinya (128 KB).
POSIX_FADV_SEQUENTIAL - proses ini melibatkan pembacaan data secara berurutan dari offset kecil ke yang lebih besar. Di Linux, operasi ini menetapkan jendela untuk secara proaktif membaca data dari file untuk menggandakan nilai aslinya.
POSIX_FADV_RANDOM - proses ini melibatkan mengakses data dalam urutan acak. Di Linux, opsi ini menonaktifkan pembacaan proaktif data dari file.
POSIX_FADV_WILLNEED - proses melibatkan mengakses area file yang ditentukan dalam waktu dekat. Kernel sebelumnya membaca data untuk mengisi cache buffer dengan data file dalam kisaran yang ditentukan oleh argumen offset dan len. Panggilan read () selanjutnya ke file tidak memblokir I / O disk, tetapi hanya mengambil data dari cache buffer. Kernel tidak memberikan jaminan berapa lama data yang diambil dari file ada di cache buffer. Jika selama operasi proses atau kernel lain ada kebutuhan khusus untuk memori, halaman tersebut pada akhirnya akan digunakan kembali. Dengan kata lain, jika memori dalam permintaan tinggi, kita perlu menjamin kesenjangan waktu kecil antara panggilan ke posix_fadvise () dan panggilan berikutnya (atau panggilan) untuk membaca (). (Fungsionalitas yang setara dengan operasi POSIX_FADV_WILLNEED disediakan oleh pemanggilan sistem readahead () khusus Linux.)
POSIX_FADV_DONTNEED - proses tidak melibatkan panggilan ke area file yang ditentukan dalam waktu dekat. Dengan cara ini, kernel diberitahu bahwa ia dapat membebaskan halaman cache yang sesuai (jika ada). Di Linux, operasi ini dilakukan dalam dua tahap. Pertama, jika antrian tulis pada perangkat host tidak penuh dengan serangkaian permintaan, kernel membuang semua halaman cache yang dimodifikasi di area yang ditentukan. Kernel kemudian mencoba untuk membebaskan semua halaman cache dari area yang ditentukan. Untuk halaman yang dimodifikasi di area ini, tahap kedua akan diselesaikan dengan sukses hanya jika mereka direkam ke perangkat dasar selama tahap pertama, yaitu, antrian perekaman pada perangkat tidak penuh. Karena aplikasi tidak dapat memeriksa status antrian pada perangkat, Anda dapat menjamin bahwa halaman cache dibebaskan dengan memanggil fsync () atau fdatasync () pada pegangan fd sebelum menerapkan POSIX_FADV_DONTNEED.
POSIX_FADV_NOREUSE - proses ini melibatkan akses satu kali ke data di area file yang ditentukan, tanpa menggunakannya kembali. Dengan demikian, kernel diberitahu bahwa ia dapat membebaskan halaman setelah akses tunggal ke sana. Di Linux, operasi ini saat ini sedang diabaikan.
Spesifikasi posix_fadvise () hanya muncul di SUSv3, dan antarmuka ini tidak didukung oleh semua implementasi UNIX. Di Linux, panggilan posix_fadvise () telah disediakan sejak kernel versi 2.6.
13.6. Buffer Cache Bypass: I / O Langsung
Dimulai dengan kernel versi 2.4, Linux memungkinkan aplikasi untuk mem-bypass cache buffer ketika menjalankan disk I / O dengan memindahkan data langsung dari ruang memori pengguna ke file atau ke perangkat disk. Kadang mode ini disebut I / O langsung atau tidak diproses.
Informasi yang disediakan di sini hanya untuk Linux dan tidak terstandarisasi dalam SUSv3. Namun, beberapa opsi akses I / O langsung untuk perangkat atau file disediakan oleh sebagian besar implementasi UNIX.
Terkadang I / O langsung disalahpahami sebagai cara untuk mencapai kinerja I / O yang tinggi. Tetapi untuk sebagian besar aplikasi, menggunakan I / O langsung dapat secara signifikan mengurangi kinerja. Faktanya adalah bahwa kernel melakukan beberapa optimasi untuk meningkatkan kinerja I / O melalui penggunaan cache buffer, termasuk pembacaan data proaktif berurutan, melakukan I / O dalam kelompok blok disk, dan memungkinkan proses mengakses volume yang sama file yang sama, bagikan buffer dalam cache. Semua jenis optimasi ini ketika menggunakan I / O langsung hilang. Ini hanya ditujukan untuk aplikasi dengan persyaratan I / O khusus, misalnya, sistem manajemen basis data yang melakukan caching sendiri dan optimalisasi I / O, dan yang tidak memerlukan kernel untuk membuang waktu dan memori CPU untuk melakukan tugas yang sama.
Input-output langsung dapat dilakukan dalam kaitannya dengan satu file, atau dalam kaitannya dengan perangkat blok (misalnya, disk). Untuk melakukan ini, ketika membuka file atau perangkat menggunakan panggilan open (), flag O_DIRECT ditentukan.
Bendera O_DIRECT berfungsi sejak kernel versi 2.4.10. Penggunaan flag ini tidak didukung oleh semua sistem file dan versi kernel Linux. Sebagian besar sistem file dasar mendukung flag O_DIRECT, tetapi banyak sistem file non-UNIX (seperti VFAT) tidak. Anda dapat menguji dukungan untuk fitur ini dengan menguji sistem file yang dipilih (jika sistem file tidak mendukung O_DIRECT, panggilan terbuka () akan gagal dengan kesalahan EINVAL) atau dengan memeriksa kode sumber kernel untuk ini.
Jika satu proses membuka file dengan flag O_DIRECT, dan yang lainnya dengan cara biasa (yaitu, menggunakan cache buffer), maka tidak ada konsistensi antara konten cache buffer dan data yang dibaca atau ditulis melalui I / O langsung. Perkembangan seperti itu harus dihindari.
Informasi tentang metode yang sudah ketinggalan zaman (sekarang tidak disarankan) untuk mendapatkan akses mentah ke perangkat disk dapat ditemukan di halaman manual raw (8).
Batasan keselarasan untuk I / O langsungKarena I / O langsung (baik pada perangkat disk maupun dalam kaitannya dengan file) melibatkan akses langsung ke disk, beberapa batasan harus diperhatikan ketika melakukan I / O.
- buffer data portabel harus disejajarkan pada batas memori, kelipatan dari ukuran blok.
- Offset dalam file atau di perangkat tempat data yang ditransfer dimulai harus merupakan kelipatan dari ukuran blok.
- Panjang data yang ditransfer harus merupakan kelipatan dari ukuran blok.
Kegagalan untuk mematuhi salah satu dari pembatasan ini akan menghasilkan kesalahan EINVAL. Dalam daftar di atas, ukuran blok mengacu pada ukuran blok fisik perangkat (biasanya 512 byte).
Saat melakukan I / O langsung di Linux 2.4, lebih banyak pembatasan dikenakan daripada di Linux 2.6: penyelarasan, panjang dan offset harus merupakan kelipatan dari ukuran blok logis dari sistem file yang digunakan. (Biasanya, ukuran blok logis dalam sistem file adalah 1024, 2048, atau 4096 byte.)
Contoh program13.1 O_DIRECT . , ( ) , , , , , , , read(). 4096 .
, :
$ ./direct_read /test/x 512 512 0 Read 512 bytes $ ./direct_read /test/x 256 ERROR [EINVAL Invalid argument] read 512 $ ./direct_read /test/x 512 1 ERROR [EINVAL Invalid argument] read 512 $ ./direct_read /test/x 4096 8192 512 Read 4096 bytes $ ./direct_read /test/x 4096 512 256 ERROR [EINVAL Invalid argument] read 512
13.1 , , , memalign(). memalign() 7.1.4.
#define _GNU_SOURCE /* O_DIRECT <fcntl.h> */ #include <fcntl.h> #include <malloc.h> #include "tlpi_hdr.h" int main(int argc, char *argv[]) { int fd; ssize_t numRead; size_t length, alignment; off_t offset; void *buf; if (argc < 3 || strcmp(argv[1], "–help") == 0) usageErr("%s file length [offset [alignment]]\n", argv[0]); length = getLong(argv[2], GN_ANY_BASE, "length"); offset = (argc > 3) ? getLong(argv[3], GN_ANY_BASE, "offset") : 0; alignment = (argc > 4) ? getLong(argv[4], GN_ANY_BASE, "alignment") : 4096; fd = open(argv[1], O_RDONLY | O_DIRECT); if (fd == -1) errExit("open"); /* memalign() , , . 'buf' , 'alignment', . , , , , 256 , , 512- . '(char *)' ( 'void *', memalign(). */ buf = (char *) memalign(alignment * 2, length + alignment) + alignment; if (buf == NULL) errExit("memalign"); if (lseek(fd, offset, SEEK_SET) == -1) errExit("lseek"); numRead = read(fd, buf, length); if (numRead == -1) errExit("read"); printf("Read %ld bytes\n", (long) numRead); exit(EXIT_SUCCESS); } _______________________________________________________________filebuff/direct_read.c
»
»
Isi»
Kutipan20% —
Linux