Skip to main content

Αντικατάσταση Χαλασμένου Σκληρού Δίσκου σε ZFS-Only Σύστημα

1. Το Ξεκίνημα της Ιστορίας

Μιας και τα hardware failures δίνουν και παίρνουν τον τελευταίο καιρό, δεν ξέφυγα κι εγώ από την ανάγκη αντικατάστασης ενός σκληρού δίσκου σε FreeBSD Server με ZFS-Only σύστημα αρχείων!

Πιο συγκεκριμένα, πριν από λίγες ημέρες και ενώ ξύπνησα το πρωί και έκανα λίγο chat με τα μέλη του Chania-LUG, κάποια στιγμή το γραφικό περιβάλλον στον υπολογιστή μου πάγωσε! Η οθόνη γέμισε με πράσινες γραμμές, το ποντίκι κόλλησε και γενικά το μηχάνημα σταμάτησε να αποκρίνεται. Η πρώτη κίνηση που έκανα ήταν να μπω στο σύστημα μέσω δικτύου με ssh (από το κινητό γιατί το να στήσω laptop τα χαράματα ήταν μια διαδικασία... Αλλά αυτό δεν έχει καμιά σημασία). Είδα ότι το σύστημα είχε απόκριση, αλλά αρκετά αργή. Το ίδιο έκανα και με τον browser, όπου έλεγξα ότι ο υπολογιστής ανταποκρίνεται σε http requests κ.λ.π. Βασικά έκανα έλεγχο σε όλες τις υπηρεσίες που ήθελα να δουλεύουν. Παντού το ίδιο. Το γραφικό περιβάλλον παγωμένο με τους μπλε και πράσινους κόκκους και γραμμές, ενώ οι υπηρεσίες δουλεύαν όλες, αλλά με αρκετά μικρότερη ταχύτητα απόκρισης. Φυσικά αφού το μηχάνημα έχει και γραφικό περιβάλλον θα καταλάβατε ότι το χρησιμοποιώ και σαν desktop :P

Η πρώτη μου σκέψη ήταν "Μπόρα είναι θα περάσει! Κάτι κάνει το μηχάνημα από πίσω και την κάνει τη δουλειά. Το απόγευμα που θα γυρίσω σπίτι από τη δουλειά θα είναι όλα μια χαρά!" Σωστά σκέφτηκα γιατί όντως το μηχάνημα έκανε δουλειά. Για την ακρίβεια το ZFS Subsystem δούλευε για λογαριασμό μου. Για την ακρίβεια διόρθωνε και έσωζε δεδομένα που έβρισκε εσφαλμένα, εξ αιτίας του σκληρού δίσκου...

Το απόγευμα και αφού γύρισα σπίτι, είδα το μηχάνημα στην ίδια ακριβώς κατάσταση. Ξαναέκανα τον έλεγχο των υπηρεσιών και την έπεσα για έναν υπνάκο μιας και έβλεπα πως θα χρειαζόμουν όλες μου τις δυνάμεις για να μπορέσω να δω τι γίνεται...

Τι θα δούμε σε αυτό το άρθρο


2. Ώρα Να Χάσουμε το uptime... (πάλι...)

Ήρθε η ώρα, λοιπόν, να κάνουμε μια επανεκκίνηση στον υπολογιστή... Μέσω ssh (από το laptop αυτή τη φορά) δίνω τη μαγική εντολή...

eliaschr@pluto:~ > su
Password:
pluto# shutdown -r now
pluto#

Μέχρι το σημείο που είδα ότι... Connection to pluto closed. Από εκεί και πέρα η εργασία γίνεται επάνω στον ίδιο τον υπολογιστή.

Στο σημείο όπου το monitor άρχισε να δείχνει κανονικά τα μηνύματα του πυρήνα άρχισα να βλέπω κάποια μηνύματα του στυλ

ad0: FAILURE - READ_DMA48 status=51 error=40 LBA=383250045
ad0: FAILURE - READ_DMA48 status=51 error=1 LBA=383250045
ZFS: vdev I/O failure, zpool=zroot path=/dev/gpt/disk0 offset=191928776192 size=120320 error=5
ZFS: vdev I/O failure, zpool=zroot path=/dev/gpt/disk0 offset=191928776192 size=120320 error=5
ZFS: zpool I/O failure, zpool=zroot error=5
.
.
.

και πολλά ακόμα τέτοιου τύπου μηνύματα... Ο σκληρός δίσκος είχε αρχίσει να παραδίδει το πνεύμα του. Χμμμμ. Ήρθε η ώρα να μελετήσουμε το ZFS Administration Handbook, να δούμε τι εργαλεία μας δίνει το ZFS για την περίπτωση. Φυσικά το συγκεκριμένο κείμενο το έχω σε έντυπη μορφή για παν ενδεχόμενο.

Αυτό που μου έκανε εντύπωση είναι ότι ακόμα και με την κατάσταση του σκληρού δίσκου, το μηχάνημα κατάφερε και ξεκίνησε, χωρίς να σηκώσει, φυσικά, γραφικό περιβάλλον. Μέσα σε όλα τα λάθη του σκληρού δίσκου, το ZFS χρησιμοποίησε τη μαγεία του και τα δεδομένα, ακόμα, ήταν κατά κάποιο τρόπο ασφαλή! Αυτό και αν δεν το ονειρευόμουν ποτέ!

3. Μήπως Πρέπει Να Πάρω Backup;


α. Λίγες σχετικές πληροφορίες

Φυσικά και την ξέρω την απάντηση. Απλά ήρθε η ώρα να περιγράψω μερικές λειτουργίες του ZFS που βοηθάνε σε αυτό. Παρότι οι λέξη "partition" είναι κάτι τελείως διαφορετικό από το "σημείο διαχείρισης" στο ZFS, στο ακόλουθο κείμενο θα χρησιμοποιώ τη λέξη "partition" σα να είναι ταυτόσημη με την έννοια "σημείο διαχείρισης". Ο λόγος είναι πως ένας καινούργιος χρήστης του ZFS μπορεί να μην έχει ξεκαθαρίσει τις διαφορές και με αυτό τον τρόπο προσπαθώ να γίνω πιο κατανοητός.

Η πρώτη λειτουργία του ZFS που μας ενδιαφέρει είναι η δημιουργία snapshots. Τα snapshots είναι και αυτά κάποια σημεία διαχείρισης του ZFS τα οποία μπορούμε να τα κάνουμε mount και να τα χρησιμοποιήσουμε κανονικά, ως Read-Only Partitions. Το μέγεθός τους αρχικά είναι ελάχιστο, ίσα ίσα για να κρατηθούν πληροφορίες για το κομμάτι από το οποίο κρατήσαμε το snapshot. Όσο εμείς αλλάζουμε αρχεία μέσα στο σύστημα αρχείων από το οποίο προέρχεται το snapshot, το ZFS γράφει τις παλιές πληροφορίες που υπήρχαν μέσα στο κομμάτι του snapshot και μετά αλλάζει τα δεδομένα που θέλουμε στο κανονικό partition. Έτσι, το μέγεθος του snapshot στον σκληρό μας δίσκο έχει το ελάχιστο δυνατό γιατί στην ουσία κρατάει μόνο τις αλλαγές που έχουμε κάνει. Ή καλύτερα την κατάσταση των αλλαγμένων αρχείων, πριν τις αλλαγές μας.

Η δεύτερη λειτουργία που μας ενδιαφέρει να γνωρίζουμε (δεν θα την χρησιμοποιήσουμε εδώ) είναι οι κλώνοι - clones. Οι κλώνοι μπορούν να προέρχονται μόνο από ένα snapshot και στην ουσία είναι ένα αντίγραφο των αρχείων που περιέχει το snapshot σε άλλο σημείο του σκληρού. Ένας κλώνος, λοιπόν, μπορεί να χρησιμοποιηθεί σαν ένα Read/Write partition το οποίο περιέχει όλα τα αρχεία τα οποία αντιστοιχούν στο snapshot από το οποίο προέρχεται. Δε μιλάμε μόνο για τα αρχεία που έχουν αλλαχθεί, αλλά για όλα τα αρχεία που περιέχει το partition από το οποίο προέρχεται και το snapshot. Προσέξτε ότι υπάρχει μια σχέση snapshot προς τον κλώνο. Το snapshot είναι ο "μπαμπάς" του κλώνου. Η σχέση αυτή μπορεί να αντιστραφεί αν το θελήσουμε. Για περισσότερες πληροφορίες σχετικές με τους κλώνους ανατρέξτε στο ZFS Administration Handbook. Δεν θα τους αναλύσουμε περισσότερο γιατί δε θα μας απασχολήσουν στο εγχείρημα αλλαγής του ελαττωματικού σκληρού δίσκου.

Η τρίτη λειτουργία που έχει και τη δύναμη που θέλουμε είναι η send/receive. Μοιάζει πολύ με το dump/restore που όσοι ασχολούμαστε με το FreeBSD πρέπει να γνωρίζουμε καλά. Το ZFS έχει τη δυνατότητα να στείλει ένα ολόκληρο σημείο διαχείρισης σε ένα stream. Αυτό εμείς μπορούμε, είτε να το σώσουμε σαν αρχείο, είτε να το οδηγήσουμε μέσω pipe π.χ. σε ssh για να το στείλουμε σε ένα remote σύστημα. Μοιάζει πολύ με το dump(8). Αυτό που δεν θα πρέπει να παραλείψουμε είναι ότι η λειτουργία send μπορεί να εφαρμοστεί σε snapshot και όχι σε χρησιμοποιούμενο σημείο διαχείρισης!

Η αντίστροφη διαδικασία είναι η receive η οποία μοιάζει με την εντολή restore(8). Η λειτουργία receive παίρνει τα δεδομένα από ένα stream και ξαναδημιουργεί το σημείο διαχείρισης. Θα μπορούσαμε, λοιπόν, σε ένα απομακρυσμένο μηχάνημα να δημιουργήσουμε το σημείο διαχείρισης που στέλνουμε μέσω ssh με τη λειτουργία send.

Με όλες αυτές τις δυνατότητες που γνωρίσαμε, μπορούμε να καταλάβουμε ότι το ZFS μας παρέχει πολλά εργαλεία για να μπορέσουμε να φτιάξουμε αντίγραφο ασφάλειας του συστήματός μας. Είτε χρησιμοποιώντας κλώνους, είτε με το να κάνουμε ενός είδους dump αρχείο, είτε ακόμα και να έχουμε ένα μηχάνημα απομακρυσμένο το οποίο να παίζει τον ρόλο του backup server σε περίπτωση αστοχίας του πρώτου!


β. Γνωριμία με το σύστημα

Είναι κατανοητό πως πρώτα θα πρέπει να δούμε την κατάσταση των ZFS Pools που έχει το σύστημά μας. Με αυτό τον τρόπο θα εξηγήσω τη δομή του εν λόγω μηχανήματος για να μπορέσουμε να δούμε τι συμβαίνει, αλλά ταυτόχρονα θα εξηγήσω γιατί προτίμησα να κάνω αυτή τη διαρρύθμιση στους αποθηκευτικούς μου χώρους. Το μηχάνημα περιέχει ένα σκληρό δίσκο 1.5TB και δύο σκληρούς δίσκους 500GB. Το ακόλουθο σχήμα μπορεί να δώσει λίγο φως στην εξήγηση της διαρρύθμισης:

A Testing ZFS Scheme

Στο σχήμα φαίνονται οι κατατμήσεις του σκληρού δίσκου, δηλαδή partitions και όχι σημεία διαχείρισης του ZFS. Οι σκληροί έχουν χωριστεί σε partitions με το σχήμα GPT και όχι με το κλασικό σχήμα geom(4).

Τα πρώτα 500GB του σκληρού έχουν διατεθεί στο λειτουργικό σύστημα. Εδώ μας χρειάζονται τα ακόλουθα partitions:

  • ad0p1: Partition που περιέχει τον κώδικα για το boot του λειτουργικού. Έχει μικρό μέγεθος, της τάξης των 256KB. Ο τύπος του είναι freebsd-boot και περιέχει τον κώδικα gptzfsboot.
  • ad0p2: Partition της εικονικής μνήμης του λειτουργικού μας. Έχει μέγεθος 4GB και είναι τύπου freebsd-swap. Το όνομά του είναι το swap0
  • ad0p3: Εδώ περιέχεται το λειτουργικό μας. Το μέγεθος του partition είναι τα υπόλοιπα από τα 500GB που περίσσεψαν. Μιας και εκεί μέσα θα βρίσκονται τα σημεία διαχείρισης του ZFS, ο τύπος του partition είναι freebsd-zfs.

Στο μεγάλο κομμάτι βρίσκονται επίσης πληροφορίες που δεν μας ενδιαφέρει τόσο πολύ το να έχουμε mirrored.

Άλλα δύο partitions που έχουμε στον σκληρό μεγέθους 1.5TB είναι και αυτά μεγέθους 500GB. Αυτά τα δύο partitions (ad0p4 και ad0p5 αντίστοιχα) γίνονται mirrored με δύο άλλους σκληρούς δίσκους μεγέθους 500GB ο καθένας (ad1p1 και ad2p1 αντίστοιχα). Ο λόγος που κάνουμε το mirroring είναι για να έχουμε ένα αυτόματο backup των δεδομένων και σε άλλους σκληρούς. Έτσι, ό,τι περιέχεται στο partition ad0p4 περιέχεται αυτόματα και στον σκληρό δίσκο ad1 και ό,τι περιέχεται στο partition ad0p5 περιέχεται αυτόματα και στον σκληρό ad2.

Ο λόγος που προτιμήθηκε αυτός ο διαχωρισμός είναι η ευκολία εύρεσης σκληρών δίσκων 500GB πρόχειρων και σε χαμηλό κόστος. Είναι, λοιπόν, μια τακτική την οποία ακολουθούμε περισσότερο για να μπορούμε ανά πάσα στιγμή να ανακτήσουμε τα δεδομένα μας. Επίσης, αν κάποιος σκληρός δίσκος πάθει κάποια ζημιά (που είναι και ο λόγος ύπαρξης αυτού του άρθρου) τότε είναι καλύτερα να χάσουμε δεδομένα 500GB παρά περισσότερα... Στη δικιά μας περίπτωση ο σκληρός δίσκος που έπαθε τη ζημιά είναι, ποιος άλλος σύμφωνα με το φίλο μας τον Murfy, ο ad0 χωρητικότητας 1.5TB

Για να μπορέσουμε να σώσουμε το σύστημά μας θα χρειαστούμε έναν αντικαταστάτη σκληρό δίσκο χωρητικότητας 1.5TB, τον οποίο θα συνδέσουμε σε ένα USB, εξωτερικά. Αυτό σημαίνει πως η ονομασία του σκληρού θα είναι η da0. Το ακόλουθο σχήμα δείχνει ποια είναι η κατάτμηση που θα κάνουμε στον αντικαταστάτη σκληρό και ποια η σχέση του με τον παλιό και ελαττωματικό.

Replacing The Malfunctioned Disc

Θα παρατηρήσατε ότι στον καινούργιο σκληρό οι κατατμήσεις είναι σχεδιασμένες με διακεκομμένη γραμμή. Αυτό δηλώνει πως οι κατατμήσεις δεν υπάρχουν αλλά θα πρέπει να δημιουργηθούν. Ας μην ξεχνάμε ότι ο σκληρός δίσκος da0 είναι ολοκαίνουργιος.

Στο σχήμα βλέπουμε πως οι κατατμήσεις που χρειάζονται μεταφορά δεδομένων είναι μόνο οι τρεις, ad0p3, ad0p4 και ad0p5. Αυτό συμβαίνει γιατί δεν υπάρχει λόγος να μεταφέρουμε την εικονική μνήμη, ούτε τον κώδικα gptzfsboot. Εξ άλλου, τον τελευταίο θα τον γράψουμε στον καινούργιο σκληρό από την αρχή!


γ. Έλεγχος και διόρθωση των δεδομένων

Πρώτη κίνηση για να μπορέσουμε να πάρουμε ένα σωστό backup είναι να προσπαθήσουμε να έχουμε τα δεδομένα μας ακέραια. Για να το κάνουμε αυτό θα πρέπει να είμαστε root. Ας ελέγξουμε πρώτα την κατάσταση των ZFS Pools:

eliaschr@pluto:~ > su
Password:
pluto# zpool status -v #it could be -x as well
  pool: Common1
 state: ONLINE
status: The pool is formatted using an older on-disk format.  The pool can
        still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the
        pool will no longer be accessible on older software versions.
 scrub: none requested
config:

        NAME             STATE     READ WRITE CKSUM
        Common1          ONLINE       0     0     0
          mirror         ONLINE       0     0     0
            gpt/disk1    ONLINE       0     0     0
            gpt/Mirror1  ONLINE       0     0     0

errors: No known data errors

  pool: Common2
 state: ONLINE
status: The pool is formatted using an older on-disk format.  The pool can
        still be used, but some features are unavailable.
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the
        pool will no longer be accessible on older software versions.
 scrub: none requested
config:

        NAME             STATE     READ WRITE CKSUM
        Common2          ONLINE       0     0     0
          mirror         ONLINE       0     0     0
            gpt/disk2    ONLINE       0     0     0
            gpt/Mirror2  ONLINE       0     0     0

errors: No known data errors

  pool: zroot
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://www.sun.com/msg/ZFS-8000-9P
 scrub: none requested
config:

        NAME         STATE     READ WRITE CKSUM
        zroot        ONLINE       0     0     0
          gpt/disk0  ONLINE     198     0     0

errors: No known data errors
pluto#

Πραγματικά, εδώ βλέπουμε ότι η ZFS Pool που περιέχει το λειτουργικό μας σύστημα, zroot, παρουσιάζει προβλήματα. Ώρα να αφήσουμε το ZFS να προσπαθήσει να κάνει ένα καλό έλεγχο στην pool και αν βρει και άλλα σφάλματα να τα διορθώσει. Αυτό γίνεται ως εξής:

pluto# zpool scrub
pluto# zpool status -v
  pool: Common1                                    
 state: ONLINE                                     
status: The pool is formatted using an older on-disk format.  The pool can
        still be used, but some features are unavailable.                 
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the   
        pool will no longer be accessible on older software versions.     
 scrub: none requested                                                    
config:                                                                   

        NAME             STATE     READ WRITE CKSUM
        Common1          ONLINE       0     0     0
          mirror         ONLINE       0     0     0
            gpt/disk1    ONLINE       0     0     0
            gpt/Mirror1  ONLINE       0     0     0

errors: No known data errors

  pool: Common2
 state: ONLINE 
status: The pool is formatted using an older on-disk format.  The pool can
        still be used, but some features are unavailable.                 
action: Upgrade the pool using 'zpool upgrade'.  Once this is done, the   
        pool will no longer be accessible on older software versions.
 scrub: none requested
config:

        NAME             STATE     READ WRITE CKSUM
        Common2          ONLINE       0     0     0
          mirror         ONLINE       0     0     0
            gpt/disk2    ONLINE       0     0     0
            gpt/Mirror2  ONLINE       0     0     0

errors: No known data errors

  pool: zroot
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://www.sun.com/msg/ZFS-8000-9P
 scrub: scrub completed after 23h20m with 0 errors on Mon Oct 18 23:54:39 2010
config:

        NAME         STATE     READ WRITE CKSUM
        zroot        ONLINE       0     0     0
          gpt/disk0  ONLINE     249     0     0  256K repaired

errors: No known data errors
pluto#

Σε αυτό το σημείο βλέπουμε ότι μετά από πολλές ώρες το ZFS έκανε το πρώτο του θαύμα! Παρότι παρουσιάστηκαν ακόμα περισσότερα σφάλματα διόρθωσε όσα μπορούσε. Στη δικιά μας την περίπτωση, διόρθωσε όλα όσα βρήκε.


δ. Δημιουργία του backup των δεδομένων μας

Το backup δημιουργείται σε δύο βήματα. Το πρώτο είναι να φτιαχτεί ένα snapshot της κατάστασης του συστήματος αρχείων που μας ενδιαφέρει και στη συνέχεια να δημιουργήσουμε το αρχείο που περιέχει το αντίγραφο. Η προτιμώμενη λύση για ένα σύστημα που έχει πρόβλημα είναι η λειτουργία send του ZFS:

pluto# zfs list
NAME                            USED  AVAIL  REFER  MOUNTPOINT
Common1                         274G   182G   274G  /Common
Common2                         224G   233G    18K  /Common2
Common2/Backups                73,1G   233G  73,1G  /Common/Backups
Common2/Datasheets             7,43G   233G  7,43G  /Common/Datasheets
Common2/Documentation Section  3,22G   233G  3,22G  /Common/Documentation Section
Common2/ECh Documents          21,4G   233G  21,4G  /Common/ECh Documents
Common2/Pictures               13,4G   233G  13,4G  /Common/Pictures
Common2/home                    105G   233G   105G  /usr/home
Common2/www                     275M   233G   275M  /usr/local/www
zroot                           107G   346G   221M  legacy
zroot/tmp                       380M   346G   380M  /tmp
zroot/usr                      19,5G   346G  14,6G  /usr
zroot/usr/ports                4,64G   346G   270M  /usr/ports
zroot/usr/ports/distfiles      4,38G   346G  4,38G  /usr/ports/distfiles
zroot/usr/ports/packages         18K   346G    18K  /usr/ports/packages
zroot/usr/src                   303M   346G   303M  /usr/src
zroot/var                      2,32G   346G  13,5M  /var
zroot/var/crash                1024M   346G  1024M  /var/crash
zroot/var/db                   1,15G   346G  1,09G  /var/db
zroot/var/db/pkg               58,6M   346G  58,6M  /var/db/pkg
zroot/var/empty                  18K   346G    18K  /var/empty
zroot/var/log                  92,4M   346G  92,3M  /var/log
zroot/var/mail                  200K   346G   200K  /var/mail
zroot/var/run                   130K   346G   111K  /var/run
zroot/var/tmp                  67,3M   346G  67,3M  /var/tmp
pluto# zfs snapshot -r zroot/var@2010-10-20
pluto# zfs snapshot -r zroot/tmp@2010-10-20
pluto# zfs snapshot -r zroot/usr@2010-10-20
pluto# zfs snapshot zroot@2010-10-20
pluto# zfs list -t snapshot
NAME                                   USED  AVAIL  REFER  MOUNTPOINT
zroot@2010-10-20                        98K      -   221M  -         
zroot/tmp@2010-10-20                      0      -   380M  -         
zroot/usr@2010-10-20                   326K      -  14,6G  -         
zroot/usr/ports@2010-10-20                0      -   270M  -         
zroot/usr/ports/distfiles@2010-10-20      0      -  4,38G  -         
zroot/usr/ports/packages@2010-10-20       0      -    18K  -         
zroot/usr/src@2010-10-20                  0      -   303M  -         
zroot/var@2010-10-20                    21K      -  13,5M  -         
zroot/var/crash@2010-10-20                0      -  1024M  -         
zroot/var/db@2010-10-20                156K      -  1,09G  -         
zroot/var/db/pkg@2010-10-20               0      -  58,6M  -         
zroot/var/empty@2010-10-20                0      -    18K  -         
zroot/var/log@2010-10-20              85,5K      -  92,3M  -         
zroot/var/mail@2010-10-20                 0      -   200K  -         
zroot/var/run@2010-10-20                19K      -   111K  -         
zroot/var/tmp@2010-10-20                  0      -  67,3M  -         
pluto#

Τα snapshots έχουν δημιουργηθεί. Μην ξεχνάμε ότι τα snapshots είναι και αυτά σημεία διαχείρισης και μπορούν να προσαρτηθούν και αυτά στο σύστημά μας. Όμως δεν περιέχουν όλα τα δεδομένα, αλλά μόνο indexes και τα αρχεία τα οποία έχουν υποστεί αλλαγές, όπως ήταν τη στιγμή που πήραμε το snapshot.

Τώρα θα πρέπει να δημιουργήσουμε αντίγραφα των snapshots αλλά με ολόκληρα τα δεδομένα. Το πρόβλημα είναι το που θα τα αποθηκεύσουμε. Αν συνδέσουμε έναν εξωτερικό σκληρό δίσκο σε USB τότε το πιο σύνηθες είναι να είναι μορφοποιημένος ο εν λόγω σκληρός δίσκος σε σύστημα αρχείων FAT32 ή NTFS. Το FAT32 έχει το πρόβλημα του μέγιστου μεγέθους αρχείου των 4GB, το οποίο είναι απαγορευτικό γιατί τα δεδομένα στον σύστημά μας ξεπερνάνε κατά πολύ αυτό το μέγεθος... Από την άλλη, το NTFS έχει το πρόβλημα της αστάθειας στο FreeBSD. Είναι πολύ εύκολο να παρουσιαστεί σφάλμα κατά την εγγραφή των δεδομένων με αποτέλεσμα ένα πανέμορφο core dump του kernel! Άρα, αποφεύγουμε να το χρησιμοποιήσουμε.

Η λύση είναι το εσωτερικό μας mirrored τμήμα. Το καλό που έχουν τα δύο mirrors που έχουμε φτιάξει είναι ότι τα δεδομένα βρίσκονται ταυτόχρονα σε δύο σκληρούς δίσκους και έτσι αν ο ένας παρουσιάζει σφάλματα κατά την εγγραφή, το ZFS ξέρει καλά πως να τα κρατήσει σωστά με τη βοήθεια των δεύτερων σκληρών. Εναλλακτικά θα μπορούσαμε να έχουμε ένα ssh server σε ένα απομακρυσμένο μηχάνημα στο δίκτυό μας και να στείλουμε το backup εκεί. Οπότε λύσεις υπάρχουν, για κάθε γούστο! :P

Η ώρα του πραγματικού backup ήρθε:

pluto# zfs send -Rv zroot/usr@2010-10-20 > /Common2/usr.20101020
.
.
.
pluto# zfs send -Rv zroot/tmp@2010-10-20 > /Common2/tmp.20101020
.
.
.
pluto# zfs send -Rv zroot/var@2010-10-20 > /Common2/var.20101020
.
.
.
pluto# zfs send -v zroot@2010-10-20 > /Common2/root.20101020
.
.
.
pluto# ls -l /Common2
-rw-r--r--  1 root  wheel    240931640 21 Οκτ 00:25 root.20101020
-rw-r--r--  1 root  wheel    563447860 20 Οκτ 22:27 tmp.20101020
-rw-r--r--  1 root  wheel  22777054676 20 Οκτ 20:08 usr.20101020
-rw-r--r--  1 root  wheel   4975268576 20 Οκτ 22:07 var.20101020
pluto#

Τα τέσσερα αρχεία που δημιουργήθηκαν είναι το backup όλου του λειτουργικού. Αυτό δημιουργήθηκε στο δεύτερο mirror που έχει το σύστημά μας. Κατά τη διάρκεια του send βλέπουμε να υπάρχουν πολλά μηνύματα σφάλματος, αλλά αυτό είναι κάτι φυσιολογικό αφού ο σκληρός δίσκος ad0 είναι ελαττωματικός.

4. Αλλαγή του ελαττωματικού σκληρού δίσκου

Αφού τελειώσαμε με το backup, ήρθε και η ώρα να αλλάξουμε τον σκληρό δίσκο. Η λογική είναι να μη χρειαστεί να κάνουμε και πάλι εγκατάσταση στο λειτουργικό, αλλά να επαναφέρουμε όλες τις ZFS Pools σε ένα καινούργιο σκληρό δίσκο και να αποφύγουμε την υπόλοιπη ταλαιπωρία.


α. Προετοιμασία του καινούργιου σκληρού δίσκου

Δεν χρειάζεται να σβήσουμε το μηχάνημα, ούτε και να έχουμε κενό SATA δίαυλο στη μητρική μας για αυτό το βήμα. Η μεταφορά των ZFS Pools από ένα σκληρό σε έναν άλλο, απαιτεί να είναι ο καινούργιος σκληρός χωρισμένος σε partitions, όπως και ο παλιός. Αυτή είναι η προετοιμασία που πρέπει να κάνουμε στον καινούργιο σκληρό δίσκο. Θα επαναλάβουμε τα βήματα που είχαμε κάνει όταν στήναμε το FreeBSD σε ZFS. Η διαφορά είναι ότι αυτό θα το κάνουμε στον σκληρό δίσκο που θα συνδέσουμε σε μια θύρα USB. Αφού τον συνδέσουμε θα δούμε κάποια μηνύματα από το kernel που θα μας δείχνουν:

Oct 23 10:43:21 pluto kernel: ugen4.2:  at usbus4
Oct 23 10:43:21 pluto kernel: umass0:  on usbus4
Oct 23 10:43:21 pluto kernel: umass0:  SCSI over Bulk-Only; quirks = 0x4000
Oct 23 10:43:23 pluto kernel: umass0:2:0:-1: Attached to scbus2
Oct 23 10:43:23 pluto kernel: da0 at umass-sim0 bus 0 scbus2 target 0 lun 0
Oct 23 10:43:23 pluto kernel: da0:  Fixed Direct Access SCSI-2 device
Oct 23 10:43:23 pluto kernel: da0: 40.000MB/s transfers
Oct 23 10:43:23 pluto kernel: da0: 1430799MB (2930277168 512 byte sectors: 255H 63S/T 182401C)

Εδώ φαίνεται καθαρά ότι ο καινούργιος δίσκος έχει προσαρτηθεί στο σύστημα με το όνομα da0. Προσοχή χρειάζεται να μην μπερδέψουμε την ονομασία του με αυτή του ελαττωματικού σκληρού ad0! Η κατάτμηση του σκληρού μας γίνεται ως εξής:

pluto# gpart destroy # may fail
pluto# gpart create -s gpt da0 # Create gpt scheme on external hard disc
pluto# gpart add -s 256K -t freebsd-boot da0
pluto# gpart add -s 4G -t freebsd-swap da0 # Do not label it yet

Σε αυτό το σημείο έχουμε δημιουργήσει τις δύο πρώτες κατατμήσεις του σκληρού για το bootcode και τη μνήμη swap. Η τελευταία δεν έχει ακόμα ετικέτα διότι θα πάρει το όνομα την ετικέτας που ήδη χρησιμοποιείται από τον βασικό, για την ώρα, σκληρό δίσκο. Για να γράψουμε τον κώδικα boot πρέπει να εκτελέσουμε την ακόλουθη εντολή:

pluto# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0
pluto#

Αν τυχών αποτύχει η εντολή με ένα μήνυμα που μας λέει πως ήδη υπάρχει κώδικας μέσα στο Boot Record τότε απλά παραλείπουμε την επιλογή -b, δηλαδή

da0 has bootcode
pluto# gpart bootcode -p /boot/gptzfsboot -i 1 da0
pluto#

Επειδή, αποκλείεται να θυμόμαστε τις ακριβείς διαστάσεις των κατατμήσεων disk0, disk1 και disk2 του βασικού σκληρού δίσκου (ελαττωματικού), καλό είναι να ζητήσουμε από το gpart να μας τις δείξει:

pluto# gpart list ad0
Geom name: ad0             
fwheads: 16                
fwsectors: 63              
last: 2930275021           
first: 34                  
entries: 128               
scheme: GPT                
Providers:                 
1. Name: ad0p1             
   Mediasize: 262144 (256K)
   Sectorsize: 512         
   Mode: r0w0e0            
   rawtype: 83bd6b9d-7f41-11dc-be0b-001560b84f0f
   label: (null)                                
   length: 262144                               
   offset: 17408                                
   type: freebsd-boot                           
   index: 1                                     
   end: 545                                     
   start: 34                                    
2. Name: ad0p2                                  
   Mediasize: 4294967296 (4.0G)                 
   Sectorsize: 512                              
   Mode: r1w1e1                                 
   rawtype: 516e7cb5-6ecf-11d6-8ff8-00022d09712b
   label: swap0                                 
   length: 4294967296                           
   offset: 279552                               
   type: freebsd-swap                           
   index: 2                                     
   end: 8389153                                 
   start: 546                                   
3. Name: ad0p3                                  
   Mediasize: 495790956544 (462G)               
   Sectorsize: 512                              
   Mode: r1w1e2                                 
   rawtype: 516e7cba-6ecf-11d6-8ff8-00022d09712b
   label: disk0                                 
   length: 495790956544                         
   offset: 4295246848                           
   type: freebsd-zfs                            
   index: 3                                     
   end: 976730865                               
   start: 8389154                               
4. Name: ad0p4                                  
   Mediasize: 500107862016 (466G)               
   Sectorsize: 512                              
   Mode: r1w1e2                                 
   rawtype: 516e7cba-6ecf-11d6-8ff8-00022d09712b
   label: disk1                                 
   length: 500107862016                         
   offset: 500086203392                         
   type: freebsd-zfs                            
   index: 4                                     
   end: 1953504033                              
   start: 976730866                             
5. Name: ad0p5                                  
   Mediasize: 500106745856 (466G)               
   Sectorsize: 512                              
   Mode: r1w1e2                                 
   rawtype: 516e7cba-6ecf-11d6-8ff8-00022d09712b
   label: disk2                                 
   length: 500106745856                         
   offset: 1000194065408                        
   type: freebsd-zfs                            
   index: 5                                     
   end: 2930275021                              
   start: 1953504034                            
Consumers:                                      
1. Name: ad0                                    
   Mediasize: 1500300828160 (1.4T)              
   Sectorsize: 512                              
   Mode: r4w4e11                                

pluto#

Τα partitions που μας ενδιαφέρουν είναι αυτά που έχουν τις ετικέτες disk0, disk1 και disk2, δηλαδή αυτά που έχουν index number 3, 4 και 5, αντίστοιχα. Σε κάθε ένα από αυτά τα block η εντολή μας επιστρέφει δύο τιμές που μας ενδιαφέρουν. Η μια είναι η start και η δεύτερη η length. Για να βρούμε το μέγεθος που θα δώσουμε στις ακόλουθες εντολές θα πρέπει να κάνουμε την πραξη end-start+1. Για τις κατατμήσεις που φαίνονται παραπάνω θα έχουμε:

Label Start End Calculated Length
disk0 8389154 976730865 976730865 -8389154 +1 = 968341712
disk1 976730866 1953504033 1953504033 -976730866 +1 = 976773168
disk2 1953504034 2930277134 2930277134 -1953504034 +1 = 976773101

Τώρα μπορούμε να φτιάξουμε τις κατατμήσεις ξανά με το ίδιο μέγεθος. Το μέγεθος που υπολογίσαμε είναι σε blocks. Τα ονόματα που θα δώσουμε στις καινούργιες κατατμήσεις θα είναι τα main0, main1 και main2, αντίστοιχα. Για την τελευταία κατάτμηση δεν χρειάζεται να δηλώσουμε μέγεθος. Με αυτό τον τρόπο απλά θα καταλάβει όλο το υπόλοιπο τμήμα του σκληρού δίσκου, χωρίς να αφήσει καθόλου αχρησιμοποίητο χώρο.

pluto# gpart add -s 968341712 -t freebsd-zfs -l main0 da0
pluto# gpart add -s 976773168 -t freebsd-zfs -l main1 da0
pluto# gpart add -t freebsd-zfs -l main2 da0
pluto#

Τώρα ο καινούργιος σκληρός πληροί τις προϋποθέσεις για να αντικαταστήσει τον παλιό και ελαττωματικό. Μένει μόνο να μεταφερθούν τα δεδομένα.


β. Αντικατάσταση των τμημάτων των pools

Το ZFS έχει απίστευτες δυνατότητες για όλες τις δουλειές που μπορεί να χρειαστεί κάποιος στο σύστημα αρχείων του. Ακόμα και την αλλαγή των pools έχει προβλέψει! Αυτή τη δυνατότητα είναι που θα χρησιμοποιήσουμε και τώρα:

pluto# zpool replace zroot gpt/disk0 gpt/main0
pluto# zpool status zroot
  pool: zroot
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h4m, 1,15% done, 6h15m to go
config:

        NAME           STATE     READ WRITE CKSUM
        zroot          ONLINE       0     0     0
          replacing    ONLINE       0     0     0
            gpt/disk0  ONLINE     259     0     0
            gpt/main0  ONLINE       0     0     0  1,23G resilvered

errors: No known data errors
pluto#

Η πρώτη εντολή (replace) ξεκινάει μια διαδικασία που ονομάζεται resilvering. Αυτή η διαδικασία παίρνει, φυσικά, πολύ χρόνο. Το ZFS Subsystem κάνει ότι χρειάζεται στο background, αφήνοντας τον χρήστη να χειρίζεται το μηχάνημα κανονικά. Απλά ο χειρισμός του μηχανήματος είναι λίγο πιο αργός, πράγμα που ούτως ή άλλως συμβαίνει λόγω της ελαττωματικής κατάστασης του σκληρού δίσκου. Τη δεύτερη (status) μπορεί να τη δίνει κάποιος όποτε θέλει, για να βλέπει σε τι κατάσταση έχει φτάσει το resilvering. Έτσι όταν τελειώσει η διαδικασία θα μπορέσει να συνεχίσει με το resilvering των άλλων δύο ZFS Pools. Οι εντολές είναι οι ακόλουθες:

pluto# zpool replace Common1 gpt/disk1 gpt/main1 #wait until this process is finished and then...
pluto# zpool replace Common2 gpt/disk2 gpt/main2 #again, wait until the end of the process
pluto#

Όταν, με το καλό, τελειώσει όλη η διαδικασία του resilvering σε όλες τις ZFS Pools, ο καινούργιος σκληρός δίσκος θα περιέχει τα δεδομένα του παλιού και οι Pools θα χρησιμοποιούν τον καινούργιο για να δουλέψουν. Άρα ήρθε η ώρα να σβήσει το μηχάνημα και αλλαχθεί ο εσωτερικός και ελαττωματικός σκληρός δίσκος με τον καινούργιο.

pluto# shutdown -p now


5. ΔΕΝ ΤΕΛΕΙΩΣΑΜΕ!!!!

Τι έγινε ρε παιδιά! Γιατί το σύστημα δεν κάνει boot;

Κάνοντας boot το σύστημα βλέπουμε ότι μετά το μενού του loader βγαίνουμε σε mountroot με την παρατήρηση ότι δεν μπορεί να γίνει mount η zfs:zroot! Ό,τι και να κάνουμε το σύστημα δε μπορεί να ξεκινήσει το λειτουργικό μας. Αυτό αμέσως θα έπρεπε να μας πονηρέψει ότι κάτι γίνεται με το αρχείο zpool.cache. Αυτό το αρχείο, με λίγα λόγια, περιέχει πληροφορίες για τη δομή των ZFS Pools και είναι βασικό για την εκκίνηση του μηχανήματος. Κατά τη διάρκεια του resilvering το αρχείο αυτό μεταφέρθηκε από τον παλιό σκληρό στον καινούργιο, αλλά οι πληροφορίες που περιέχει είναι με βάση τον παλιό σκληρό. Έτσι, έχουμε λανθασμένες πληροφορίες για τις ZFS Pools που υπάρχουν αυτή τη στιγμή.

Θα παρατηρήσατε βέβαια ότι οι ονομασίες που είχαμε δώσει στα gpt partitions δεν είναι ίδιες με αυτές που υπήρχαν στον παλιό σκληρό δίσκο. Και όμως, όπως θα δούμε παρακάτω, αυτό δεν το ενδιαφέρει το ZFS γιατί τις κατατμήσεις που χρησιμοποιεί τις καταλαβαίνει από ένα μοναδικό ID αριθμό που έχουν από τη στιγμή της κατασκευής τους.

α. Αλλαγή των ονομάτων των gpt partitions

Από τη διαδικασία που περιγράφεται εδώ, το μόνο αναγκαίο είναι το να δώσουμε στο swap partition την ονομασία που είχε και πριν, ώστε να αποφύγουμε να διορθώσουμε το αρχείο /etc/fstab. Τα υπόλοιπα δεν είναι απαραίτητα να γίνουν. Απλά τα κάνουμε για να επανέλθουν οι ονομασίες που είχαμε συνηθίσει και όχι για κάποιον άλλο λόγο. Αυτό θα το αποδείξουμε αμέσως. Η ακόλουθη διαδικασία απαιτεί να κάνουμε boot από το livefs και να μπούμε στην κονσόλα Fixit. Εκεί, πάμε να ελέγξουμε την κατάσταση των ZFS Pools.

Fixit# #lets load the zfs subsystem
Fixit# kldload /mnt2/boot/kernel/opensolaris.ko
Fixit# kldload /mnt2/boot/kernel/zfs.ko
Fixit# export LD_LIBRARY_PATH=/mnt2/lib

Αυτές οι εντολές θα πρέπει να εκτελούνται κάθε φορά που μπαίνουμε στην κονσόλα Fixit για να μπορέσουμε να έχουμε πρόσβαση στις ZFS Pools μας. Σειρά έχει ο έλεγχος των pools:

Fixit# zpool import
  pool: Common1
    id: 16786791901886102938
 state: ONLINE
action: The pool can be imported using its name or numeric identifier
config:

        NAME             STATE     READ WRITE CKSUM
        Common1          ONLINE       0     0     0
          mirror         ONLINE       0     0     0
            gpt/main1    ONLINE       0     0     0
            gpt/Mirror1  ONLINE       0     0     0

errors: No known data errors

  pool: Common2
    id: 2880185314831596717
 state: ONLINE
action: The pool can be imported using its name or numeric identifier
config:

        NAME             STATE     READ WRITE CKSUM
        Common2          ONLINE       0     0     0
          mirror         ONLINE       0     0     0
            gpt/main2    ONLINE       0     0     0
            gpt/Mirror2  ONLINE       0     0     0

errors: No known data errors

  pool: zroot
    id: 1188189039061593219
 state: ONLINE
action: The pool can be imported using its name or numeric identifier
config:

        NAME         STATE     READ WRITE CKSUM
        zroot        ONLINE       0     0     0
          gpt/main0  ONLINE       0     0     0

errors: No known data errors
Fixit#

Παρατηρούμε ότι τα gpt partitions που χρησιμοποιούν οι pools είναι τα σωστά. Έτσι δεν είναι πραγματικά ανάγκη να αλλάξουμε αυτά τα ονόματα.

Για να αλλάξουμε τα labels των gpt partitions πρώτα θα πρέπει να εκτελέσουμε τις ακόλουθες εντολές:

Fixit# gpart modify -i 2 -l swap0 ad0 #label the swap partition as swap0
Fixit# gpart modify -i 3 -l disk0 ad0
Fixit# gpart modify -i 4 -l disk1 ad0
Fixit# gpart modify -i 5 -l disk2 ad0

Το μεγάλο πρόβλημα που έχουμε με τη δημιουργία του αρχείου zpool.cache είναι ότι οι pools πρέπει να έχουν γίνει import κανονικά και όχι με altroot. Δηλαδή να μη γίνει χρήση της επιλογής -R στην εντολή import. Αυτό όμως με τη σειρά του προκαλεί ένα σωρό προβλήματα γιατί η zroot κάθεται ακριβώς επάνω στο ήδη υπάρχον σύστημα από το Fixit και αντικαθιστά τα πάντα. Αυτό σημαίνει πως το αρχείο που μας ενδιαφέρει αντιγράφεται από αυτό που υπάρχει μέσα στο σύστημά μας, πριν προλάβουμε να το χρησιμοποιήσουμε. Πρέπει να βρούμε μια λύση να έχουμε το σωστό αρχείο και αυτό γίνεται αναγκαστικά σε δύο στάδια. Στο πρώτο κάνουμε import τη zroot με altroot για να μπορέσουμε τα mountpoints.

Fixit# zpool import -fR /zroot zroot
Fixit# zpool import -f Common1
Fixit# zpool import -f Common2
Fixit# zfs unmount -a
Fixit# zfs set mountpoint=none zroot
Fixit# zpool export Common2
Fixit# zpool export Common1
Fixit# zpool export zroot
Fixit#

Αυτά που έχουμε καταφέρει είναι να μην παραπονιέται το σύστημα όταν πάμε να κάνουμε import τις pools, λέγοντας πως χρειάζεται την επιλογή -f και, δεύτερον, το κεντρικό κομμάτι του filesystem της zroot να μη γίνεται mount και έτσι να μην μας απανωγράφει το σύστημα της κονσόλας Fixit. Το πρόβλημα, όμως, που υπάρχει είναι ότι ο κατάλογος /boot/zfs της zroot δεν είναι διαθέσιμος για να γράψουμε μέσα το εν λόγω αρχείο.

Για να δημιουργηθεί το αρχείο zpool.cache θα πρέπει να προϋπάρχει ο κατάλογος /boot/zfs. Αυτό δεν συμβαίνει στην κονσόλα Fixit όπότε τον δημιουργούμε μόνοι μας:

Fixit# mkdir /boot/zfs
Fixit#

Το αρχείο zpool.cache θα δημιουργηθεί αυτόματα όταν γίνουν import οι pools. Έτσι:

Fixit# zpool import zroot
Fixit# zpool import Common1
Fixit# zpool import Common2
Fixit#

Σε αυτό το σημείο το αρχείο /boot/zfs/zpool.cache έχει δημιουργηθεί με τα στοιχεία που χρειάζεται το σύστημά μας για να λειτουργήσει σωστά. Αρκεί να το αντιγράψουμε σε κάποιο άλλο σημείο της zroot που είναι ήδη προσβάσιμο. Το κατάλληλο μέρος είναι το /tmp. Στη συνέχεια θα κάνουμε κανονικά unmount και θα φτιάξουμε το mountpoint που πειράξαμε.

Fixit# cp /boot/zfs/zpool.cache /tmp
Fixit# zfs unmount -a
Fixit# zfs set mountpoint=/ zroot
Fixit# zpool export Common2
Fixit# zpool export Common1
Fixit# zpool export zroot

Τώρα είμαστε σε θέση να επαναφέρουμε το αρχείο zpool.cache στη σωστή του θέση μέσα στην zroot και να φτιάξουμε και το τελικό mountpoint όπως πρέπει να είναι για να γίνει κανονικά η εκκίνηση από το σύστημα.

Fixit# zpool import -fR /zroot zroot
Fixit# zpool import -f Common1
Fixit# zpool import -f Common2
Fixit# cp /zroot/tmp/zpool.cache /zroot/boot/zfs/
Fixit# zfs unmount -a
Fixit# zfs set mountpoint=legacy zroot
Fixit# reboot
.
.
.

Σε αυτό το σημείο αφήνουμε το μηχάνημα να εκκινήσει κανονικά από τον σκληρό μας δίσκο. Το σύστημα θα εκκινήσει κανονικά, χωρίς προβλήματα, αν όλα έχουν πάει καλά. Γιατί, μην ξεχνάμε, είχαμε και έναν ελαττωματικό σκληρό, όπου τα δεδομένα του ανα πάσα στιγμή θα μπορούσαν να είναι τελειώς διαφορετικά από αυτά που θα έπρεπε να είναι.

Σε όσους ξεκίνησαν να κάνουν το εγχείρημα της αλλαγής του σκληρού δίσκου, τους εύχομαι καλή επιτυχία. May the source be with you!

Χρυσοχέρης Ηλίας