bug-parted
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC/PATCH 2/2] dasd: add read-only support for CMS labeled minidisks


From: Jonathan Nieder
Subject: [RFC/PATCH 2/2] dasd: add read-only support for CMS labeled minidisks
Date: Fri, 16 Apr 2010 22:54:31 -0500
User-agent: Mutt/1.5.20 (2009-06-14)

From: Stephen Powell <address@hidden>

CMS-formatted disks are supported by the S/390 Linux kernel, but they
are not supported by parted.  Correct the omission.  As before, the
DASD driver only supports Extended Count Key Data devices.

Just as for LDL disks, for an CMS formatted disk which has been
processed by the CMS RESERVE command, additional CMS metadata (the
directory, allocation map, pointer blocks, etc.) has to be skipped
over.  The reserved file itself is the partition.

For a CMS formatted disk which has been processed by the CMS RESERVE
command, additional CMS metadata (the directory, allocation map,
pointer blocks, etc.) must be skipped over.  The reserved file itself
is the partition.  Since the reserved file is explicitly allocated by
CMS, the partition is considered an explicit partition.  The number of
blocks to be skipped over is stored in the disk_offset field of the
CMS format volume label.

The assistance of Boyd Stephen Smith Jr. with general C programming
questions is gratefully acknowledged.

Signed-off-by: Jonathan Nieder <address@hidden>
---
A cast to void* was changed to a cast to union* to avoid breaking
strict aliasing rules.  Maybe the original cast to void * was fine,
but this way is sure to work.  See ‘casting through union (2)’ in
Mike Acton’s “Understanding Strict Aliasing” [1].

Aside from that, this is pretty much identical to Stephen’s patch.
I hope I did not ruin it.  I look forward to your thoughts.

Thanks,
Jonathan

[1] 
http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

 NEWS                     |    3 +++
 include/parted/vtoc.h    |   43 +++++++++++++++++++++++++++++++++++++++++++
 libparted/labels/dasd.c  |   25 ++++++++++++++++++++-----
 libparted/labels/fdasd.c |   15 ++++++++-------
 4 files changed, 74 insertions(+), 12 deletions(-)

diff --git a/NEWS b/NEWS
index 4735990..36fd0bf 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ GNU parted NEWS                                    -*- outline 
-*-
 
   parted now recognizes Linux Software RAID Arrays
 
+  dasd: parted now can read CMS-formatted disk labels (on IBM
+  z/Architecture machines)
+
 ** Bug fixes
 
   When libparted deferenced a /dev/mapper/foo symlink, it would keep the
diff --git a/include/parted/vtoc.h b/include/parted/vtoc.h
index 6b41584..12fc963 100644
--- a/include/parted/vtoc.h
+++ b/include/parted/vtoc.h
@@ -49,6 +49,7 @@ typedef struct cchhb            cchhb_t;
 typedef struct cchh             cchh_t;
 typedef struct labeldate        labeldate_t;
 typedef struct volume_label     volume_label_t;
+typedef struct cms_volume_label cms_volume_label_t;
 typedef struct extent           extent_t;
 typedef struct dev_const        dev_const_t;
 typedef struct format1_label    format1_label_t;
@@ -95,6 +96,48 @@ struct __attribute__ ((packed)) volume_label {
        char res3[29];          /* reserved                                  */
 };
 
+/*
+ * See:
+ *     z/VM V5R2.0 CMS Planning and Administration
+ *     SC24-6078-01
+ *     What CMS Does / Disk and File Management / Disk File Format
+ * 
http://publib.boulder.ibm.com/infocenter/zvm/v5r4/topic/com.ibm.zvm.v54.dmsd1/hcsg2b1018.htm
+ */
+struct __attribute__ ((packed)) cms_volume_label {
+       char label_id[4];       /* Label identifier ("CMS1")                 */
+       char vol_id[6];         /* Volume identifier                         */
+       char version_id[2];     /* Version identifier ("\0\0")               */
+       u_int32_t block_size;   /* Disk block size (512, 1024, 2048 or 4096) */
+       u_int32_t origin_ptr;   /* Disk origin pointer (4 or 5)              */
+       u_int32_t usable_count; /* Number of usable cylinders/blocks         */
+       u_int32_t formatted_count; /* Max # of formatted cylinders/blocks    */
+       u_int32_t block_count;  /* Disk size in CMS blocks                   */
+       u_int32_t used_count;   /* Number of CMS blocks in use               */
+       u_int32_t fst_size;     /* File Status Table (FST) size (64)         */
+       u_int32_t fst_count;    /* Number of FSTs per CMS block              */
+       char format_date[6];    /* Disk FORMAT date (YYMMDDhhmmss)           */
+       char reserved1[2];      /* Reserved fields.
+                                  The low-order bit of the first byte is a
+                                  century flag.  0 = 1900s, 1 = 2000s.
+                                  It is used in conjunction with
+                                  "format_date" to determine the
+                                  four-digit year.                          */
+       u_int32_t disk_offset;  /* Offset in blocks to the start of the
+                                  reserved file when the disk is reserved.
+                                  This is the number of blocks to skip
+                                  before the partition starts.              */
+       u_int32_t map_block;    /* Allocation map block with next hole       */
+       u_int32_t hblk_disp;    /* Displacement in HBLK data of next hole    */
+       u_int32_t user_disp;    /* Disp into user part of allocation map     */
+       u_int32_t open_files;   /* Count of SFS open files for this ADT.
+                                  open_files is not really part of the
+                                  volume label.  It is not used for
+                                  minidisks.                                */
+       char segment_name[8];   /* Name of the shared segment.
+                                  segment_name is not really part of the
+                                  volume label.  It is not stored on disk.  */
+};
+
 struct __attribute__ ((packed)) extent {
         u_int8_t  typeind;      /* extent type indicator */
         u_int8_t  seqno;        /* extent sequence number */
diff --git a/libparted/labels/dasd.c b/libparted/labels/dasd.c
index 1b29fcf..74e57a9 100644
--- a/libparted/labels/dasd.c
+++ b/libparted/labels/dasd.c
@@ -255,6 +255,7 @@ dasd_read (PedDisk* disk)
        LinuxSpecific* arch_specific;
        DasdDiskSpecific* disk_specific;
        struct fdasd_anchor anchor;
+       bool is_cms, is_ldl;
 
        PDEBUG;
 
@@ -286,14 +287,28 @@ dasd_read (PedDisk* disk)
 
        ped_disk_delete_all (disk);
 
-       if (strncmp(anchor.vlabel->volkey,
-                               vtoc_ebcdic_enc ("LNX1", str, 4), 4) == 0) {
+       is_ldl = strncmp(anchor.vlabel->volkey,
+                        vtoc_ebcdic_enc("LNX1", str, 4), 4) == 0;
+       is_cms = strncmp(anchor.vlabel->volkey,
+                        vtoc_ebcdic_enc("CMS1", str, 4), 4) == 0;
+       if (is_ldl || is_cms) {
                DasdPartitionData* dasd_data;
 
-               /* LDL format, old one */
+               union vollabel {
+                       volume_label_t unused;
+                       cms_volume_label_t cms;
+               };
+               union vollabel *cms_ptr1 = (union vollabel *) anchor.vlabel;
+               cms_volume_label_t *cms_ptr = &cms_ptr1->cms;
+
                disk_specific->format_type = 1;
-               start = (long long) arch_specific->real_sector_size
-                       / (long long)disk->dev->sector_size * 3;
+               if (is_ldl || cms_ptr->disk_offset == 0)
+                       start = (long long) arch_specific->real_sector_size
+                               / (long long)disk->dev->sector_size * 3;
+               else
+                       start = (long long) arch_specific->real_sector_size
+                               / (long long) disk->dev->sector_size
+                               * (long long) cms_ptr->disk_offset;
                end = (long long)(long long) anchor.geo.cylinders
                      * (long long)anchor.geo.heads
                      * (long long)disk->dev->hw_geom.sectors
diff --git a/libparted/labels/fdasd.c b/libparted/labels/fdasd.c
index 6397f27..62baa52 100644
--- a/libparted/labels/fdasd.c
+++ b/libparted/labels/fdasd.c
@@ -698,15 +698,15 @@ fdasd_valid_vtoc_pointer(fdasd_anchor_t *anc, unsigned 
long b, int fd)
        /* VOL1 label contains valid VTOC pointer */
        vtoc_read_label (fd, b, NULL, anc->f4, NULL, NULL);
 
-       if (anc->f4->DS4IDFMT != 0xf4) {
-               if 
(strncmp(anc->vlabel->volkey,vtoc_ebcdic_enc("LNX1",str,4),4) == 0)
-                       return 0;
-               fdasd_error(anc, wrong_disk_format, _("Invalid VTOC."));
-       } else {
+       if (anc->f4->DS4IDFMT == 0xf4) {
                fdasd_process_valid_vtoc (anc, b, fd);
+               return 0;
        }
+       if (strncmp(anc->vlabel->volkey, vtoc_ebcdic_enc("LNX1",str,4),4) == 0 
||
+           strncmp(anc->vlabel->volkey, vtoc_ebcdic_enc("CMS1",str,4),4) == 0)
+               return 0;
 
-       return 0;
+       fdasd_error(anc, wrong_disk_format, _("Invalid VTOC."));
 }
 
 /*
@@ -737,7 +737,8 @@ fdasd_check_volume (fdasd_anchor_t *anc, int fd)
                } else {
                        return 1;
                }
-       } else if (strncmp (v->volkey, vtoc_ebcdic_enc ("LNX1", str, 4), 4) == 
0) {
+       } else if (strncmp (v->volkey, vtoc_ebcdic_enc ("LNX1", str, 4), 4) == 
0 ||
+                  strncmp (v->volkey, vtoc_ebcdic_enc ("CMS1", str, 4), 4) == 
0) {
                return 0;
        }
 
-- 
1.7.1.rc1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]