Esercizio - Frammentazione interna di un file con stat e statvfs (laboratorio 10)
In questa pagina 4
Testo (laboratorio 10 del corso di Sistemi Operativi, Ing. Informatica UniPD).
- Task 1. Verificare che anche un file di 1 byte occupa almeno 4096 byte (cioè byte): scrivere un carattere in
abcde.txte controllare constat. Poi scaricare nella propria home il fileENIAC_Penn1.jpg(conwget), controllare il numero di blocchi allocati, calcolare i byte "sprecati" per frammentazione interna e consegnare il risultato. - Task 2. Modificare
fileinfo.c(che stampa le informazioni di un file conlstat()estatvfs()) per crearefraginfo.c, un programma che calcola la frammentazione interna di un file dato. Verificare che il risultato sia coerente con quello del Task 1.
Il comando stat
stat nomefile stampa (tra le altre cose) la dimensione in byte, il numero di blocchi allocati e la dimensione del blocco di I/O:
File: abcde.txt
Size: 1948 Blocks: 8 IO Block: 4096 regular filePer ragioni storiche i blocchi contati da stat (campo st_blocks) sono sempre unità da 512 byte, mentre il blocco fisico di I/O del file system (campo IO Block, st_blksize, e f_bsize di statvfs) è di 4096 byte. Una unità fisica corrisponde quindi a blocchi contati.
| dimensione del file | blocchi fisici da 4096 | Blocks (da 512) |
frammentazione interna |
|---|---|---|---|
| 1 byte | 1 | 8 | byte |
| 1948 byte | 1 | 8 | byte |
| 4096 byte | 1 | 8 | 0 |
| 4097 byte | 2 | 16 | byte |
| 17 112 byte | 5 | 40 | byte |
| 1 981 975 byte | 484 | 3872 | byte |
Task 1
File da 1 byte. Occupa comunque un blocco fisico da 4096 byte: Blocks: 8 (8 blocchi da 512), 4095 byte sprecati. Un file vuoto ha invece Blocks: 0.
File ENIAC_Penn1.jpg. La dimensione è 1 981 975 byte e il blocco fisico 4096 byte:
La memoria allocata è byte e la frammentazione interna
Il risultato coincide con la soluzione del corso (nell'ultimo blocco sono usati byte su 4096, ne avanzano ).
Task 2: fraginfo.c
Si parte da fileinfo.c, che chiama lstat(argv[1], &sfile) (come stat, ma non segue i link simbolici) e statvfs(argv[1], &sdisk):
sdisk.f_bsizeè la dimensione del blocco del file system;sfile.st_sizeè la dimensione in byte del file.
Il numero di blocchi occupati è , e la frammentazione interna è lo spazio allocato meno quello usato:
/* fraginfo.c - frammentazione interna dell'ultimo blocco di un file.
* Compilare: gcc -Wall -Wextra -o fraginfo fraginfo.c
* Usare: ./fraginfo abcde.txt
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
int main(int argc, char *argv[]) {
struct stat sf;
struct statvfs sv;
if (argc != 2) { fprintf(stderr, "uso: %s file\n", argv[0]); return EXIT_FAILURE; }
if (lstat(argv[1], &sf) < 0) { perror("lstat"); return EXIT_FAILURE; }
if (statvfs(argv[1], &sv) < 0) { perror("statvfs"); return EXIT_FAILURE; }
intmax_t blocco = (intmax_t)sv.f_bsize; /* blocco del file system */
intmax_t dim = (intmax_t)sf.st_size; /* byte del file */
intmax_t blocchi = (dim + blocco - 1) / blocco; /* blocchi occupati, per eccesso */
intmax_t sprecati = blocchi * blocco - dim; /* 0 se la dimensione e' multipla */
printf("blocco del file system: %jd byte\n", blocco);
printf("dimensione del file: %jd byte\n", dim);
printf("blocchi necessari: %jd (stat dice %jd da 512 byte)\n", blocchi, (intmax_t)sf.st_blocks);
printf("frammentazione interna: %jd byte\n", sprecati);
return EXIT_SUCCESS;
}Compilato con zig cc per Linux, senza avvisi; non eseguito. Per ENIAC_Penn1.jpg l'uscita attesa è: blocco 4096, dimensione 1981975, blocchi necessari 484, frammentazione 489.
Differenza dalla soluzione del corso. La soluzione distribuita calcola
int wasted = sdisk.f_bsize - sfile.st_size % sdisk.f_bsize;cioè . Per quasi tutti i file dà il risultato giusto (per esempio 4096 − 3607 = 489 per il file del laboratorio) ma è sbagliata quando la dimensione è un multiplo del blocco: per un file di 4096 byte il resto è 0 e wasted vale 4096, mentre la frammentazione è 0; lo stesso per un file vuoto (0 blocchi, nessuno spreco). Il calcolo è corretto in tutti i casi. In più, il programma del corso usa int per un valore che arriva a intmax_t e non controlla gli argomenti.
Altre osservazioni: st_blocks può essere maggiore del valore calcolato se il file system ha allocato blocchi aggiuntivi (per esempio blocchi di indirezione per file grandi, o preallocazione); per file piccoli o medi su ext4 il valore coincide con quello calcolato qui. Il numero st_blocks è la verifica incrociata richiesta dal testo: .
Errori tipici
- Contare i blocchi di
statcome da 4096 (sono da 512). - Usare la divisione per difetto: servono i blocchi per eccesso (
dim / bloccoperde l'ultimo blocco parziale). - Dimenticare il caso di un file lungo esattamente un multiplo del blocco (frammentazione 0, non ).
- Confondere la dimensione del file (
st_size) con lo spazio allocato (st_blocks). - Scambiare
lstatestatsu un link simbolico:lstatdescrive il link,statil file puntato.
Versione ripasso
stat. Blocks è in unità da 512 byte, IO Block (e f_bsize) è 4096: un blocco fisico blocchi contati. 1 byte Blocks: 8, 4095 byte sprecati; 1948 byte 8 blocchi; 17 112 byte 40 blocchi, frammentazione .
Task 1. ENIAC_Penn1.jpg: 1 981 975 byte blocchi ; frammentazione byte.
Task 2. lstat(argv[1], &sf), statvfs(argv[1], &sv): , con f_bsize. La formula del corso dà (invece di 0) se è multiplo di .
Passaggi. lstat e statvfs; f_bsize (4096); ; ; controllo con st_blocks (). Esempi: 1 byte 8 blocchi da 512, 4095 byte sprecati; 4096 byte 0 (la formula del corso dà 4096); 4097 byte 2 blocchi, 4095; 17 112 byte 5 blocchi (Blocks: 40), 3368; 1 981 975 byte 484 blocchi ( da 512), 489.
Errori tipici: blocchi di stat da 4096; divisione per difetto; multiplo del blocco 0; st_size contro st_blocks; lstat contro stat.