Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

File Management και I/O στο UNIX

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "File Management και I/O στο UNIX"— Μεταγράφημα παρουσίασης:

1 File Management και I/O στο UNIX
Λειτουργικά Συστήματα Ντίρλης Νικόλαος- ΕΤΥ Τμήμα Μηχανικών Η/Υ και Πληροφορικής Πάτρας Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

2 Εισαγωγή Ένα από τα βασικά στοιχεία της επιστήμης της Πληροφορικής (όπως άλλωστε φαίνεται και από το όνομά της) είναι η έρευνα της φύσης της πληροφορίας καθώς και η διαχείρισή της με αποδοτικό τρόπο. Πληροφορία (info) εξάγεται μετά από επεξεργασία δεδομένων (data) και η οργάνωση της πληροφορίας σε ένα υπολογιστικό σύστημα ήταν από τα πρώτα προβλήματα που έπρεπε να λύσουν οι επιστήμονες της Πληροφορικής. Η ιδέα της «αρχειοποίησης» της πληροφορίας σε αντιστοιχία με τον τρόπο που λειτουργεί η αρχειοποίηση φυσικών εγγράφων σε ένα γραφείο ήταν μια προφανής και φυσική ιδέα που είναι απλή στην κατανόηση και υλοποίηση. Η δομή και το σύνολο των κανόνων που χρησιμοποιούμε για να διαχειριστούμε ομάδες αρχείων μπορούμε να πούμε πως είναι αυτό που ονομάζουμε file system. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

3 Σκοπός της παρουσίασης
Σκοπός μας σε αυτή την παρουσίαση είναι η κατανόηση της διαχείρισης αρχείων και μεθόδων Ι/Ο στο λειτουργικό σύστημα του UNIX με τελικό στόχο τη δημιουργία ενός flat file system χωρίς ασφάλεια πρόσβασης χρησιμοποιώντας τα εργαλεία που προσφέρει το UNIX. Μέσα από αυτή τη διαδικασία θα κατανοήσουμε καλύτερα τους μηχανισμούς διαχείρισης αρχείων και κάποιες βασικές προγραμματιστικές μεθόδους για την υλοποίηση αυτών σε UNIX-like συστήματα. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

4 Flat File System Ένα file system (FS) είναι “flat” όταν αποτελείται από ένα root folder και έπειτα μόνο από αρχεία, χωρίς δηλ sub-folders. Tέτοια FS (που αλλιώς λέγονται «ενός επιπέδου») έχουν χρησιμοποιηθεί στην πράξη και είναι εύκολο να παρουσιαστούν στον χρήστη ως πολύ-επίπεδα, τεχνική που εφαρμόστηκε στα πρώτα ΛΣ της η Apple. Ένα FS αποτελείται από τρία μέρη, το Directory Service, το Folder Service και το Block Service. Εμείς, στα πλαίσια του στόχου μας για την δημιουργία ενός flat file system, καλούμαστε να υλοποιήσουμε αυτά τα τρία μέρη για ένα FS ενός εικονικού δίσκου. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

5 Κέλυφος Στο υψηλότερο επίπεδο, ο χρήστης θα δίνει εντολές σε ένα κέλυφος που θα δημιουργήσουμε το οποίο θα μετατρέπει τις εντολές του υψηλότερου επιπέδου σε κλίσεις συναρτήσεων των Directory και File Services, οι οποίες με τη σειρά τους θα καλούν τις χαμηλότερου επιπέδου συναρτήσεις του Block Service που αναλαμβάνουν τη μετακίνηση block από και προς τον εικονικό δίσκο. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

6 Ενδεικτικός κώδικας για το κέλυφος
int command = scanf("%c",&argument); if (command<=0) { printf("Error :in scanf\n"); continue; } while(chara!='\n') { if(argument==' ') { argum[g][i]='\0'; g++; i=0;} else{ argum[g][i++]=command;} if (command<0) { printf("Error :in scanf\n"); continue; } } /* add terminal symbol to the last operand */ argum[g][i]='\0'; Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

7 Σχόλια Έχουμε ορίσει έναν πίνακα τριών ορισμάτων ((ή δύο, ανάλογα με το μέγιστο αριθμό ορισμάτων κάθε εντολής) που ονομάσαμε argum και περιμένουμε από τον χρήστη να εισάγει κάποια εντολή (για παράδειγμα μέσα σε ένα while(true)) . Όταν πάρουμε κάποια εντολή μετά μπορούμε να ξεκινήσουμε τη διαδικασία αναγνώρισής της και να καλούμε αντίστοιχα το utility που θα παρέχει το file system μας στον χρήστη (το οποίο θα έχουμε υλοποιήσει εμείς σε κάποιο .h αρχείο) , πχ /* check for each command */ if (strcmp(argum[0],"mkfs")==0) { mkfs(); } Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

8 Μετα-δεδομένα Γνωρίζουμε πως ένα FS διατηρεί κάποιες δομές που περιέχουν μετα-δεδομένα, δηλ βοηθητικά δεδομένα για τα πραγματικά δεδομένα που υπάρχουν στο μέσον (στην περίπτωσή μας στο «δίσκο») που διαχειρίζεται το FS. Οι δομές αυτές θα διατηρούνται στα πρώτα blocks του δίσκου και θα είναι οι εξής: Superblock i-nodes bit map Block bit map Directory Table i-node Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

9 Μέγεθος των βοηθητικών δομών
Λαμβάνοντας κάποιες σχεδιαστικές αποφάσεις, μπορούμε να γνωρίζουμε ακριβώς το μέγεθος σε blocks των παραπάνω δομών. Λαμβάνοντας αυτό υπόψη είναι εύκολο να δημιουργήσουμε το block service χρησιμοποιώντας τις συναρτήσεις lseek(), read() και write() του UNIX (εκτός και αν θέλουμε να δημιουργήσουμε τον δικό μας device manager). Στη συνέχεια της παρουσίασης θα δούμε αναλυτικότερα αυτά τα calls του UNIX. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

10 Τα File I/O calls του UNIX
Στο UNIX, τα calls που παρέχονται για file I/O είναι τα παρακάτω: open close create read write lseek dup Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

11 To open call (ορίσματα)
int open (char*pathname, int oflag, int mode); Το πρώτο όρισμα είναι το όνομα του αρχείου που θα γίνει open. Το δεύτερο όρισμα καθορίζει τον τρόπο που θα γίνει το open, δηλ μόνο για ανάγνωση, μόνο για εγγραφή, για ανάγνωση και εγγραφή, δημιουργία του αρχείου αν δεν υπάρχει κ.α. Το τρίτο όρισμα χρησιμοποιείται μόνο το αρχείο δημιουργείται και θέτει τα permission bits για αυτό. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

12 Το open call (συνέχεια)
Αν το αρχείο γίνει open επιτυχώς, το call επιστρέφει έναν file descriptor για αυτό, ή -1 σε περίπτωση λάθους. Όλα τα υπόλοιπα calls χρησιμοποιούν αυτόν τον descriptor για το αρχείο και όχι το όνομα του αρχείου. Όπως θα δούμε λίγο πιο μετά, ο fd αποθηκεύεται στον kernel μαζί με ένα file pointer (offset) που δείχνει το επόμενο byte από το αρχείο που θα γίνει read ή write από τα αντίστοιχα calls. Δείτε επίσης στα man pages για τις fopen και fwrite. Η create είναι ισοδύναμη της open. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

13 Κάποια βασικά πράγματα για τα errors
Πριν προχωρήσουμε παρακάτω είναι χρήσιμο να αποσαφηνίσουμε κάποια βασικά πράγματα για την διαχείριση των errors στο UNIX. Να τονίσω εδώ πως για το error stream θα μιλήσουμε παρακάτω μαζί με τα άλλα streams. Γενικά στο UNIX οι επιστρεφόμενες τιμές των calls του είναι θετικοί ακέραιοι. Μία αρνητική επιστρεφόμενη τιμή συμβαίνει σαν εξαίρεση. Το global integer variable errno περιέχει πληροφορίες για τα errors και μπορούμε να χρησιμοποιήσουμε τη συνάρτηση perror για να πάρουμε μια περιγραφή του error από το σύστημα. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

14 Παράδειγμα με perror int fd =open(“foo”,O_RDWR); if (fd<0) { perror(“Can’t open foo”);exit(-1); } Αυτό που κάνουμε παραπάνω είναι να προσπαθήσουμε να ανοίξουμε το αρχείο “foo” για ανάγνωση και εγγραφή. Αν η open αποτύχει για κάποιο λόγο στην errno θα περιέχεται ο αντίστοιχος error code. Τότε αυτό που η perror θα επιστρέψει θα είναι: “Can’t open foo: [description of error code in errno]” Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

15 To read call (ορίσματα)
int read(int fd, void*buffer, int nbytes); H read χρησιμοποιείται για να διαβάσει σε ένα buffer (δεύτερο όρισμα) τόσα bytes όσα ορίζονται στο τρίτο όρισμα από το offset και μετά. Ας δούμε ένα παράδειγμα: char buf[10]; int num_read=read(fd,buf,10); Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

16 Το read call (συνέχεια)
Στο παράδειγμά μας γίνεται σαφής η λειτουργία της read αλλά αυτό που δεν είναι σαφές είναι αν όντως η read θα διαβάσει τα 10 αυτά bytes. Αν η read δεν το κάνει θα επιστρέψει μια αρνητική τιμή και στη μεταβλητή errno θα υπάρχει περισσότερη πληροφορία για αυτό. Αν η επιστρεφόμενη τιμή είναι μηδέν, τότε το offset δείχνει στο τέλος του αρχείου. Αν επιστραφεί μια θετική τιμή μικρότερη του 10 τότε αυτό εκφράζει τα bytes που πραγματικά διαβάστηκαν και το offset θα έχει μετακινηθεί όσο είναι αυτή η τιμή. Είναι ευθύνη του προγραμματιστή να καλέσει την read πάλι για να διαβάσει τα bytes που απομένουν. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

17 Το write call Το write λειτουργεί σε αντιστοιχία με το read.
Οι read και write είναι και οι δυο τους «blocking» που σημαίνει πως δεν θα επιστρέψουν μέχρι να συμβεί κάποιο error ή μέχρι να φτάσει το offset στο τέλος του αρχείου ή να διαβαστούν ή γραφούν επιτυχώς κάποια bytes. Είναι δυνατόν να τεθεί ένας file descriptor ως non-blocking και σε αυτή την περίπτωση όταν μια διεργασία είναι να γίνει block επιστρέφει αμέσως μια αρνητική τιμή και το errno γίνεται EWOULDBLOCK. Φυσικά, ένα call μπορεί να διακοπεί από ένα signal και σε αυτή την περίπτωση η errno παίρνει την τιμή EINTR. Ο προγραμματιστής έχει τη δυνατότητα να χρησιμοποιήσει τις τιμές της errno για να διαχειριστεί καταστάσεις σφαλμάτων, interrupts κτλ. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

18 Το lseek call (ορίσματα)
int lseek(int fd, int offset, int whence); Είδαμε πως οι read και write χρησιμοποιούν το offset και του αλλάζουν τιμή. Η αλλαγή του offset μπορεί να γίνει κατά βούληση του προγραμματιστή μέσω της lseek. Τα πρώτα δύο ορίσματα είναι το αρχείο που θα «πειράξουμε» το offset του και πόσο αυτό θα μετακινηθεί. Το τρίτο όρισμα καθορίζει τον τρόπο της μετακίνησης. SEEK_SET  offset is from the beginning of the file SEEK_CUR  offset is from the current position SEEK_END  offset if from the end of the file Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

19 Το lseek call (συνέχεια)
An example from int file=0; if((file=open("testfile.txt",O_RDONLY)) < -1) return 1; char buffer[19]; if(read(file,buffer,19) != 19) return 1; printf("%s\n",buffer); if(lseek(file,10,SEEK_SET) < 0) return 1; printf("%s\n",buffer); return 0; The output of the preceding code is: $ cat testfile.txt This is a test file that will be used to demonstrate the use of lseek. $ ./testing This is a test file test file that will Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

20 Block Service- Υλοποίηση (1/2)
Κάνοντας χρήση των πραγμάτων που έχουμε δει μέχρι τώρα μπορούμε εύκολα να δημιουργήσουμε το block service του file system μας με τη βοήθεια των read, write και lseek. To Block Service παρέχει υπηρεσίες ανάγνωσης και εγγραφής ανά block στα επόμενα επίπεδα και αυτό μπορεί να συντελεστεί ως εξής: Βήμα 1ο: Πήγαινε στην αρχή του αρχείου που θα εξομοιώνει τον εικονικό μας δίσκο (έτσι κι αλλιώς όλα είναι ένα αρχείο στο UNIX) Βήμα 2ο: Προσπέρασε τα structs με τα meta-data (όπως είπαμε αυτά έχουν σταθερό μέγεθος στο project μας) Βήμα 3ο: Βρες το block στο οποίο θα γίνει εγγραφή ή ανάγνωση και κάνε το αντίστοιχο write() ή read() Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

21 Block Service- Υλοποίηση (2/2)
Με την βοήθεια της lseek τα παραπάνω βήματα γίνονται εύκολα. Για να υλοποιηθεί λοιπόν ένα read και write ενός block πριν από τη χρησιμοποίηση αυτών των συναρτήσεων του UNIX αρκεί να εισάγουμε μια lseek() της μορφής: lseek(file,sizeof(Superblock)+ sizeof(inodesbitmap)+ sizeof(Blockbitmap)+ sizeof(inode)+ sizeof(Directory_Table)+ block_number,SEEK_SET); Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

22 Το close call close(fd);
Όταν «τελειώσουμε» με τον fd πρέπει να τον κλείσουμε. Το UNIX (όπως θα δούμε παρακάτω, αλλά όπως ισχύει και στο δικό μας file system) κρατάει σε ένα πίνακα τα ανοικτά αρχεία και αυτός ο πίνακας έχει πεπερασμένο μέγεθος. Άρα υπάρχει περιορισμένος αριθμός αρχείων που ανά πάσα στιγμή είναι ανοιχτά, που σημαίνει πως για να μην επιβαρύνεται το σύστημα, πρέπει τα αρχεία που δεν χρησιμοποιούνται πια να γίνονται απαραιτήτως close. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

23 Το dup call (εισαγωγή) int dup(int fd); int dup2(int fd, int fd2);
Το dup δημιουργεί ένα διπλότυπο του fd. Χρησιμοποιεί την πρώτη κενή θέση στο process file table (θα μιλήσουμε γι αυτό στην επόμενη διαφάνεια) για να αποθηκεύσει αυτό το διπλότυπο. Η dup2 θα τοποθετήσει το διπλότυπο στη θέση fd2. Το γεγονός ότι η dup κάνει δυνατό να έχουμε δύο θέσεις στο process's open file table να δείχνουν στην ίδια θέση του kernel fle table μας παρέχει την δυνατότητα να κάνουμε I/O redirection ή να δημιουργήσουμε pipelines. Για να κατανοήσουμε καλύτερα τα παραπάνω, πρέπει να πούμε δύο λόγια για κάποια data structures για file management του UNIX καθώς επίσης και για τα I/O streams του. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

24 Data Structures για file management στο UNIX
Έναν ανα-διαδικασία πίνακα όπου αποθηκεύονται τα fd. Κάθε entry του πίνακα περιέχει και έναν pointer στο kernel file table. Ο kernel file table που περιέχει κάθε αρχείο που είναι ανοικτό από όλες τις processes. Περιέχει flags που υποδηλώνουν read/write access, blocking/nonblocking κτλ καθώς επίσης το offset και έναν pointer για το v-node table. O v-node table είναι μια in-memory copy του i- node για κάθε ανοικτό αρχείο. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

25 Τα Ι/Ο streams του UNIX Κάθε πρόγραμμα ξεκινά με τρεις ανοικτούς file descriptors: stdin, stdout και stderr Στην αρχή κάθε προγράμματος, οι τιμές των descriptors αυτών είναι 0,1 και 2 αντίστοιχα. Με την freopen μπορεί να γίνει αλλαγή στον αριθμό του descriptor που αντιστοιχεί σε κάθε stream. To stderr είναι unbuffered. To stdout είναι line-buffered όταν δείχνει σε ένα τερματικό. Αυτό σημαίνει πως αν δεν εμφανιστεί το fflush() ή το exit() ή κάποια αλλαγή γραμμής, η έξοδος δεν θα εμφανιστεί αν δεν γεμίσει πρώτα ο buffer. To buffering mode κάθε stream μπορεί να αλλάξει με τις setbuf() και setvbuf() calls. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

26 Ι/Ο redirection με την dup
Στο παράδειγμα που ακολουθεί τα write που γίνονται στο stdout εμφανίζονται στο “stdout.log”. int fd = open(“stdout.log”,O_WRONLY); dup2(fd,fileno(stdout)); Σε ένα άλλο παράδειγμα δείχνουμε πως μπορεί να υλοποιηθεί το σχήμα command < somefile Κάνε fork μια child process; Η child process (cp)cκάνει open το somefile; Η cp κάνει close το standard input (descriptor 0); Ηcp κάνει dup τον fd του somefile (δημιουργία ενός fd στο slot 0); H cp κάνει close τιν αρχικό fd του somefile; Η cp εκτελεί το command; Τώρα, όταν το command κάνει read από το stdin (descriptor 0), θα διαβάζει από το somefile! Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

27 Δημιουργία pipelines Παρόμοια τεχνική χρησιμοποιείται και για την δημιουργία pipelines. Για να υλοποιηθεί το σχήμα command1 | command2 πρέπει Το κέλυφος δημιουργεί ένα pipe και έπειτα κάνει fork δύο child processes.  Μία από αυτές κάνει redirection της εξόδου στο writing end του pipe και εκτελεί την command1. Η άλλη process κάνει redirection την είσοδό της στο reading end του pipe και εκτελεί την command2. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

28 Δημιουργία utilities Σε αυτή την ενότητα θα δούμε πως μπορούμε να δημιουργήσουμε κάποια utilities του file system μας προς τον χρήστη όπως για παράδειγμα η δημιουργία και η διαγραφή αρχείων. Στο σύστημά μας (αλλά και στο fs του UNIX) υπάρχει η δομή του superblock (για λεπτομέρειες κάντε man mkfs) όπου λεπτομέρειες για το file size, name κα συγκεκριμενοποιούνται. Εμείς έχουμε λάβει τη σχεδιαστική απόφαση να έχουμε σταθερό superblock και άρα δεν χρειάζεται πραγματικά να υπάρχει. Στο UNIX μετά το superblock υπάρχει ένας πίνακας δομών που ονομάζονται inodes. Υπάρχει ένα inode για κάθε αρχείο και για κάθε directory όπου υπάρχει και ένα bit που καθορίζει ότι το συγκεκριμένο αρχείο είναι directory. Μία αναφορά σε ένα inode μέσα σε ένα dir file ονομάζεται link Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

29 Το remove Όταν ένα αρχείο διαγράφεται από το σύστημά μας , η διαδικασία διαφέρει από αυτή όπου «διαγράφουμε» (σβήνουμε) κάτι στην πραγματική ζωή. Στο UNIX απλά γίνεται unlink το αρχείο από το parent directory και στα meta-data structures (όπως για παράδειγμα στο block bit map) γίνονται οι απαραίτητες ενέργειες έτσι ώστε να γίνει κατανοητό ότι τα συγκεκριμένα blocks μπορούν να επαναχρησιμοποιηθούν. Ντίρλης Νικόλαος- Λειτουργικά Συστήματα

30 Ενδεικτικός κώδικας για το rm
/*********RM********************* /*var1 contains the name of the file to delete*/ void rm(char *var1){ int i=0; int found=0; for(;i<100;i++){ /* try to find the file in the Directory Table */ if((strcmp( Directory_Table[i].Filename,var1)==0)&& (Directory_Table[i].InodeIndex!=-2)){ found=1; break;}} if(found){ /* use create to clear the blocks it uses */ create(var1); /* set its entry in directory table to not existing */ Directory_Table[i].InodeIndex=-2; for(i=0;i<100;i++){ if(strcmp( FILES[i].filename,var1)==0){ /* set its entry in FILES to not existing */ FILES[i].ufid=-1; break; }} printf("file deleted\n");} //end if else{ printf("file not found\n"); }//end else }//end of RM Ντίρλης Νικόλαος- Λειτουργικά Συστήματα


Κατέβασμα ppt "File Management και I/O στο UNIX"

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google