File system: system call e strutture dati a run-time Indice 1. Accesso ai file: system call e strutture dati di base 2. Redirezione dell’input/output 3. Pipelines 4. Altre strutture dati 1. Accesso ai file: system call e strutture dati di base Gestione dei file: filosofia • open carica in memoria l’i-node del file • read / write accedono al file tramite il suo i-node • close rilascia le strutture dati di memoria del file Gestione dei file: strutture dati del kernel NON RESIDENTE (U-AREA) RESIDENTE File descriptor Table File Table in-core i-node table I-node Table Ø 1 ... 2 ... ... m 1 (Processo 1) read ... 1 p 2 write File descriptor Table ... ... Ø 1 1 n 2 2 write ... n ... (Processo 2) Una entry per ogni file aperto da ogni processo ref count modalità di apertura offset di ultimo byte letto/scritto ref count in-core i-node (copia dell'i-node statico) • i-number • logical device number • flag di modificato (Globale) (Globale) Una entry per ogni modalità di apertura di ogni file aperto Una entry per ogni file aperto La system call open fd=open(pathname, mode) 5 File Descriptor Table 1. 2. 3. 4. 5. 6. 7. File table tramite il pathname del file cerca il suo i-node nella i-list su disco se il file non esiste o non è accessibile nella modalità richiesta restituisce un codice di errore altrimenti: copia il suo i-node nella in-core i-node table e la completa crea una entry nella File Table, e inizializza modalità di apertura, reference count e offset crea una entry nella File Descriptor Table del processo utilizzando la prima entry libera restituisce al chiamante l’indice di tale entry (fd) (se l’i-node esiste già nella in-core i-node table, inizia da 4) in-core i-node table Ricerca nel file system tramite pathname a 567 a b 458 b /a/b/c c 234 c superblock i-list data blocks Esempio int fd; … fd=open (pathname, …); if (fd=-1) /* gestione errore */ …. read (fd, …); …. close(fd); NB: Un file può essere aperto più volte, e quindi avere più file descriptor associati contemporaneamente La system call close i=close(fd); 5 File Descriptor Table File table in-core i-node table • dealloca la entry nella File Descriptor Table • se il reference count nella File Table è >1, lo decrementa e conclude • altrimenti – dealloca la File Table entry – se il reference count nell’in-core i-node è >1 lo decrementa e conclude – altrimenti: dealloca l’in-core i-node • restituisce l’esito dell’operazione (0 o 1) Esempio Processo A fd1=open("/etc/passwd",O_RD ONLY); fd2=open("local",O_RDWR); fd3=open("/etc/passwd",O_WR ONLY); Processo B fd1=open("/etc/passwd",O_RD ONLY); fd2=open("private",O_RDONLY ); La system call read n=read(fd, buffer, nbytes) File Descript or Table File table • accede alla File Table entry a partire da fd e controlla • • • • • • la modalità di apertura accede all’in-core i-node; lock l’in-core i-node trasforma l’offset nella File Table entry in un indirizzo fisico (indirizzo blocco + offset all’interno del blocco), attraverso la tabella di indirizzamento nell’in-core inode legge il blocco/i richiesto/i nella buffer cache e copia gli nbytes richiesti in *buffer aggiorna l’i-node; unlock i-node aggiorna l’offset in File Table entry restituisce al chiamante il numero di byte letti in-core i-node table La buffer cache: lettura buffer buffer cache read(fd, buffer, n) processo kernel disco La system call write File Descript or Table File table size=write(fd, buffer, nbytes) • • • • • • • accede alla File Table entry a partire da fd e controlla la modalità di apertura accede all’in-core i-node; lock l’in-core i-node trasforma l’offset nella File Table entry in un indirizzo fisico (indirizzo blocco + offset all’interno del blocco), attraverso la tabella di indirizzamento nell’in-core i-node scrive gli nbytes di buffer nella buffer cache aggiorna l’i-node; unlock i-node aggiorna l’offset in File Table entry restituisce al chiamante il numero di byte scritti in-core i-node table La buffer cache: scrittura buffer buffer cache write(fd, buffer, n) processo kernel disco La system call lseek File Descript or Table File table currpos=lseek (fd, offset, dadove) • sposta la posizione corrente del file fd di offset bytes a partire dalla posizione specificata nel terzo parametro • restituisce la posizione corrente dopo la operazione, o –1 se errore NB: Non effettua alcuna operazione di I/O in-core i-node table Altre system call • creat (pathname, permissions) • • • • • • • crea un file vuoto e lo apre in scrittura link (pathname1, pathname2) creazione di un (hard) link a un file unlink (pathname) distrugge il link indicato (se è l’ultimo, rimuove il file) rename (oldname, newname) cambia nome a un file chmod (pathname, mode) cambia i permessi di un file chown (pathname, uid, gid) cambia l’owner di un file stat (pathname, buffer) fornisce informazioni di stato sul file ecc. Directories: system call • mkdir (pathname, mode) • • • • • • creazione di una directory rmdir (pathname) distruzione di una directory chdir (pathname) cambia la working directory opendir (pathname) apre una directory readdir (dp) legge da una directory entry closedir (dp) chiude una directory ecc. Visione d’insieme Kernel Switcher Ready queue System calls Interrupt Handlers i-node table File table Process Table I/O drivers Buffer pool U-Area Stack U-Area File descriptor table Stack Stack ... Dati Dati Dati Testo Testo Testo Processo 1 Processo 2 Processo n Introduzione al linguaggio Java 6 2. Redirezione dell’input/output La system call dup File Descript or Table File table i= dup (fd); • duplica il file descriptor fd nella prima posizione libera della File Descriptor Table • restituisce il nuovo file descriptor o –1 se errore in-core i-node table dup: esempio 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 File descriptor table dup (5) File table in-core i-node table dup: esempio 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 File descriptor table dup (5) File table in-core i-node table Standard files 0 stdin stdout stderr 0 0 1 1 2 2 3 3 3 4 4 4 5 5 5 6 6 6 1 2 File Descriptor Table File Table in-core i-node table Redirezione dell’input 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 File descriptor table close (0) File table in-core i-node table Redirezione dell’input 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 File descriptor table close (0) File table dup (5) in-core i-node table Redirezione dell’input 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 File descriptor table close (0) File table dup (5) in-core i-node table close (5) Redirezione dell’input 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 File descriptor table close (0) File table dup (5) in-core i-node table close (5) Struttura generale della shell $file args<> <output> $ write (1, PROMPT); while ((n=read(0,buffer,80)=!0) { riconosci nome file e args; FIGLIO If ( (pid=fork()) ==0) { /* I/O redirection */ if (exec(file, args)==-1) exit (1) } procid=wait(status); PADRE If (status !=0) write (2, error); write(1,PROMPT) } Se il comando è eseguito in background, non viene eseguita la wait Shell: redirezione dell’input If ((pid=fork())==0 { /* processo figlio */ if (input redirection) { fd=open(“f1”, …); close (0); dup (fd); close (fd); } exec (…); } $cmd < f1 Shell: redirezione dell’output If ((pid=fork())==0 { /* processo figlio */ if (output redirection) { fd=creat(“f1”, …); close (1); dup (fd); close (fd); } exec (…); } $cmd > f1 3. Pipelines Pipelines L’operatore di pipe richiede alla shell di connettere fra loro due (o più) comandi: comando1 comando2 … redirigendo lo standard output del primo nello standard input del successivo, e così via Pipeline: come funzionano Per eseguire AB la shell: • crea un file temporaneo di tipo speciale, chiamato pipe (invisibile all’utente) • redirige lo stdout di A sulla pipe, e crea un processo che esegue A (produttore) • redirige lo stdin di B sulla pipe, e crea un processo che esegue B (consumatore) • Il produttore A e il consumatore B si sincronizzano automaticamente • quando A e B terminano, la pipe viene distrutta A B "pipe" Pipe Una pipe è un file di dimensione limitata gestita come una coda FIFO: – un processo produttore deposita dati (e resta in attesa se la pipe è piena) – un processo consumatore legge dati (e resta in attesa se la pipe è vuota) Produttore Consumatore Tipi di pipe • Pipe con nome create da mknod (devono essere aperte con open) • Pipe senza nome create e aperte da pipe su un “pipe device” definito al momento della configurazione Creazione di una pipe senza nome: pipe i = pipe ( fd[2] ) • crea una “pipe” senza nome, e la apre in lettura e scrittura • restituisce l’esito dell’operazione (0 o –1) • assegna a fd[0] il file descriptor del lato aperto in lettura, e a fd[1] quello del lato aperto in scrittura Pipe e file ordinari Creazione e uso di un file ordinario: int fd; If ((fd=creat(filename,…) <0 ) err(); write(fd,…); … Creazione e uso di una pipe (senza nome): int fd[2]; If ( pipe(fd) < 0 ) err(); write(fd[1],…); read(fd[0],…); … File descriptor table File table I-node table 0 1 2 ..... n ..... 1 read 1 write 2 m ..... fd_pipe pipe ( n m 0 1 ) read e write offset (stanno qui e non nella file table, perché devono essere visti da entrambi i processi) Pipe: uso tipico padre pipe (fd); fork ( ); figlio eredita i file aperti, e quindi anche le pipe pipe write (fd[1],...); read (fd[0],...); pipe read (fd[0],...); write (fd[1],...); in alternativa u-area padre 0 0 1 1 2 2 3 4 .... dati/stack figlio strutture dati che rappresentano la pipe 3 4 .... fd 3 4 fd 3 4 0 1 0 1 pipe (fd); fork ( ); close (fd[0]); write (fd[1],...); close (fd[1]); read (fd[0],...); Realizzazione di una pipeline shell produttore $cmd1 cmd2 fork ( ) (wait or proceed) pipe (fd); fork ( ); consumatore close (1); dup (fd[1]); close (fd[0]); close (fd[1]); close (0); dup (fd[0]); close (fd[0]); close (fd[1]); exec (cmd1,...); exec (cmd2,...); Realizzazione di una pipeline (segue) • if ((pid=fork()) == 0) { • /* processo figlio */ • if (pipeline) { • pipe (fd_pipe); • if (fork()==0) { /* produttore */ • close(1); • dup(fd_pipe[1]); • close(fd_pipe[0]); • close(fd_pipe[1]); • exec (cmd1, ...); • } • • • • • • • • consumatore */ close (0); dup (fd_pipe[0]); close (fd_pipe[0]); close(fd_pipe[1]); exec (cmd2, ...); } ... } /* 4. Altre strutture dati Mount table Tabella sempre residente, aggiornata da mount e umount, che contiene, per ogni file system montato: – major e minor number del device – puntatore al superblocco del file system – puntatore alla root del file system a cui è montato – puntatore alla directory su cui è montato Visione d’insieme Kernel Switcher Ready queue Process Table System calls Mount Table Interrupt Handlers I/O drivers i-node table File table Buffer pool U-Area Stack U-Area Stack Stack ... Dati Dati Dati Testo Testo Testo Processo 1 Processo 2 Processo n Introduzione al linguaggio Java 6