sabato 12 giugno 2010

Partizioni in FreeBSD: il concetto di slice

FreeBSD non partiziona i dischi seguendo lo schema "classico" di Linux o MS-DOS, ma utilizza un concetto differente: le slice.
Una slice è da intendersi come una normale partizione, ossia su un disco formattato ci possono essere al massimo 4 slice. All'interno delle slice ci possono essere quante partizioni si vuole, seguendo il concetto di disklabel. L'idea è questa: una slice rappresenta una delle quattro partizioni primarie di un disco, all'interno della slice posso avere differenti partizioni (logiche a questo punto). Le slice sono sempre numerate (ad esempio s1) mentre le partizioni sono sempre identificate da lettere (ad esempio a). Quindi la prima partizione (in senso FreeBSD) potrebbe essere la s1a, ovvero la prima partizione logica che si trova nella prima partizione primaria. Il disklabel è l'informazione sulle partizioni interne di FreeBSD, visto che le slice sono memorizzate nella normale tavola delle partizioni del disco. Il disklabel è un file che si trova all'inizio della partizione primaria (slice) e che contiene un array di partizioni (logiche) FreeBSD. E' facile rendersi conto di questo analizzando i sorgenti del comando bsdlabel (che consente di visualizzare/modificare la tabella delle partizioni estese di FreeBSD). In particolare si ha che il file che viene letto è all'inizio del disco stesso:

static int
readlabel(int flag)
{
 uint32_t lba;
 int f, i;
 int error;

 f = open(specname, O_RDONLY);
 if (f < 0)
  err(1, specname);
 if (is_file)
  get_file_parms(f);
 else {
  mediasize = g_mediasize(f);
  secsize = g_sectorsize(f);
  if (secsize < 0 || mediasize < 0)
   err(4, "cannot get disk geometry");
 }
 if (mediasize > (off_t)0xffffffff * secsize)
  errx(1,
      "disks with more than 2^32-1 sectors are not supported");
 (void)lseek(f, (off_t)0, SEEK_SET);
 if (read(f, bootarea, BBSIZE) != BBSIZE)
  err(4, "%s read", specname);
 close (f);
 error = bsd_disklabel_le_dec(
     bootarea + (labeloffset + labelsoffset * secsize),
     &lab, MAXPARTITIONS);
 if (flag && error)
  errx(1, "%s: no valid label found", specname);

 if (is_file)
  return(0);

 /*
  * Compensate for absolute block addressing by finding the
  * smallest partition offset and if the offset of the 'c'
  * partition is equal to that, subtract it from all offsets.
  */
 lba = ~0;
 for (i = 0; i < lab.d_npartitions; i++) {
  if (lab.d_partitions[i].p_size)
   lba = MIN(lba, lab.d_partitions[i].p_offset);
 }
 if (lba != 0 && lab.d_partitions[RAW_PART].p_offset == lba) {
  for (i = 0; i < lab.d_npartitions; i++) {
   if (lab.d_partitions[i].p_size)
    lab.d_partitions[i].p_offset -= lba;
  }
  /*
   * Save the offset so that we can write the label
   * back with absolute block addresses.
   */
  lba_offset = lba;
 }
 return (error);
}
Come si vede la lseek posiziona il prossimo punto di lettura all'inizio della partizione primaria corrente. Da qui poi si legge una certa mole di dati equivalenti ad una struct C che si trova nel file header:

struct disklabel {
 u_int32_t d_magic;  /* the magic number */
 u_int16_t d_type;  /* drive type */
 u_int16_t d_subtype;  /* controller/d_type specific */
 char   d_typename[16]; /* type name, e.g. "eagle" */

 char      d_packname[16]; /* pack identifier */

   /* disk geometry: */
 u_int32_t d_secsize;  /* # of bytes per sector */
 u_int32_t d_nsectors;  /* # of data sectors per track */
 u_int32_t d_ntracks;  /* # of tracks per cylinder */
 u_int32_t d_ncylinders;  /* # of data cylinders per unit */
 u_int32_t d_secpercyl;  /* # of data sectors per cylinder */
 u_int32_t d_secperunit;  /* # of data sectors per unit */

   /* filesystem and partition information: */
 u_int16_t d_npartitions; /* number of partitions in following */
 u_int32_t d_bbsize;  /* size of boot area at sn0, bytes */
 u_int32_t d_sbsize;  /* max size of fs superblock, bytes */
 struct partition {  /* the partition table */
  u_int32_t p_size; /* number of sectors in partition */
  u_int32_t p_offset; /* starting sector */
  u_int32_t p_fsize; /* filesystem basic fragment size */
  u_int8_t p_fstype; /* filesystem type, see below */
  u_int8_t p_frag; /* filesystem fragments per block */
  u_int16_t p_cpg; /* filesystem cylinders per group */
 } d_partitions[MAXPARTITIONS]; /* actually may be more */};


Come si nota la struttura, oltre a contenere i dati di base del disco (geometria, ecc.) contiene un array di partizioni, che altro non sono che le partizioni logiche di FreeBSD. Da notare che ogni partizione contiene l'offset, la dimensione e il filesystem, che sono le stesse informazioni, presentate in modo testuale, da bsdlabel.


Nessun commento: