]> sourceware.org Git - lvm2.git/commitdiff
Use the MD device's stripe-width, instead of chunk_size, to align the
authorsnitzer <snitzer>
Mon, 6 Jul 2009 19:04:24 +0000 (19:04 +0000)
committersnitzer <snitzer>
Mon, 6 Jul 2009 19:04:24 +0000 (19:04 +0000)
data blocks of a Physical Volume that is placed directly upon an MD
device.

WHATS_NEW
doc/example.conf
lib/device/dev-md.c
lib/device/device.h
lib/metadata/metadata.c
man/lvm.conf.5.in

index 7594a27523c8cd268cb5b44fe7738620accadc34..f35d56b1e06b2cc0bc7db7b326020222c0d5496c 100644 (file)
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
 Version 2.02.49 - 
 ================================
+  Update 'md_chunk_alignment' to use stripe-width to align PV data area.
   Update test/t-inconsistent-metadata.sh to match new vg_read interface.
   Add lvmcache_init() to polldaemon initialization.
   Convert tools to use new vg_read / vg_read_for_update.
index 73f17c27935d91718ac2bfcc755b2a8b30779e66..0682415a1e7e236681cff4649a5fa42b8996bd8d 100644 (file)
@@ -94,7 +94,7 @@ devices {
     md_component_detection = 1
 
     # By default, if a PV is placed directly upon an md device, LVM2
-    # will align its data blocks with the the chunk_size exposed in sysfs.
+    # will align its data blocks with the md device's stripe-width.
     # 1 enables; 0 disables.
     md_chunk_alignment = 1
 
index 190bc887af560b6c91e476c2c349e0291fac6abf..618509d0aebf608c9a1d53fce6d9fef6172ab309 100644 (file)
@@ -125,39 +125,57 @@ out:
        return ret;
 }
 
-/*
- * Retrieve chunk size from md device using sysfs.
- */
-unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev)
+static int _md_sysfs_attribute_snprintf(char *path, size_t size,
+                                       const char *sysfs_dir,
+                                       struct device *dev,
+                                       const char *attribute)
 {
-       char path[PATH_MAX+1], buffer[64];
-       FILE *fp;
        struct stat info;
-       unsigned long chunk_size_bytes = 0UL;
+       int ret = -1;
 
        if (MAJOR(dev->dev) != md_major())
-               return 0;
+               return ret;
 
        if (!sysfs_dir || !*sysfs_dir)
-               return_0;
+               return ret;
 
-       if (dm_snprintf(path, PATH_MAX, "%s/dev/block/%d:%d/md/chunk_size",
-           sysfs_dir, MAJOR(dev->dev), MINOR(dev->dev)) < 0) {
-               log_error("dm_snprintf md chunk_size failed");
-               return 0;
+       ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s",
+             sysfs_dir, MAJOR(dev->dev), MINOR(dev->dev), attribute);
+       if (ret < 0) {
+               log_error("dm_snprintf md %s failed", attribute);
+               return ret;
        }
 
-       /* old sysfs structure */
-       if (stat(path, &info) &&
-           dm_snprintf(path, PATH_MAX, "%s/block/md%d/md/chunk_size",
-                       sysfs_dir, MINOR(dev->dev)) < 0) {
-               log_error("dm_snprintf old md chunk size failed");
-               return 0;
+       if (stat(path, &info) < 0) {
+               /* old sysfs structure */
+               ret = dm_snprintf(path, size, "%s/block/md%d/md/%s",
+                                 sysfs_dir, MINOR(dev->dev), attribute);
+               if (ret < 0) {
+                       log_error("dm_snprintf old md %s failed", attribute);
+                       return ret;
+               }
        }
 
+       return ret;
+}
+
+static int _md_sysfs_attribute_scanf(const char *sysfs_dir,
+                                    struct device *dev,
+                                    const char *attribute_name,
+                                    const char *attribute_fmt,
+                                    void *attribute_value)
+{
+       char path[PATH_MAX+1], buffer[64];
+       FILE *fp;
+       int ret = 0;
+
+       if (_md_sysfs_attribute_snprintf(path, PATH_MAX, sysfs_dir,
+                                        dev, attribute_name) < 0)
+               return ret;
+
        if (!(fp = fopen(path, "r"))) {
                log_sys_error("fopen", path);
-               return 0;
+               return ret;
        }
 
        if (!fgets(buffer, sizeof(buffer), fp)) {
@@ -165,22 +183,130 @@ unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev)
                goto out;
        }
 
-       if (sscanf(buffer, "%lu", &chunk_size_bytes) != 1) {
-               log_error("sysfs file %s not in expected format: %s", path,
-                         buffer);
+       if ((ret = sscanf(buffer, attribute_fmt, attribute_value)) != 1) {
+               log_error("%s sysfs attr %s not in expected format: %s",
+                         dev_name(dev), attribute_name, buffer);
                goto out;
        }
 
-       log_very_verbose("Device %s md chunk size is %lu bytes.",
-                        dev_name(dev), chunk_size_bytes);
-
 out:
        if (fclose(fp))
                log_sys_error("fclose", path);
 
+       return ret;
+}
+
+/*
+ * Retrieve chunk size from md device using sysfs.
+ */
+static unsigned long dev_md_chunk_size(const char *sysfs_dir,
+                                      struct device *dev)
+{
+       const char *attribute = "chunk_size";
+       unsigned long chunk_size_bytes = 0UL;
+
+       if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
+                                     "%lu", &chunk_size_bytes) != 1)
+               return 0;
+
+       log_very_verbose("Device %s %s is %lu bytes.",
+                        dev_name(dev), attribute, chunk_size_bytes);
+
        return chunk_size_bytes >> SECTOR_SHIFT;
 }
 
+/*
+ * Retrieve level from md device using sysfs.
+ */
+static int dev_md_level(const char *sysfs_dir, struct device *dev)
+{
+       const char *attribute = "level";
+       int level = -1;
+
+       if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
+                                     "raid%d", &level) != 1)
+               return -1;
+
+       log_very_verbose("Device %s %s is raid%d.",
+                        dev_name(dev), attribute, level);
+
+       return level;
+}
+
+/*
+ * Retrieve raid_disks from md device using sysfs.
+ */
+static int dev_md_raid_disks(const char *sysfs_dir, struct device *dev)
+{
+       const char *attribute = "raid_disks";
+       int raid_disks = 0;
+
+       if (_md_sysfs_attribute_scanf(sysfs_dir, dev, attribute,
+                                     "%d", &raid_disks) != 1)
+               return 0;
+
+       log_very_verbose("Device %s %s is %d.",
+                        dev_name(dev), attribute, raid_disks);
+
+       return raid_disks;
+}
+
+/*
+ * Calculate stripe width of md device using its sysfs files.
+ */
+unsigned long dev_md_stripe_width(const char *sysfs_dir, struct device *dev)
+{
+       unsigned long chunk_size_sectors = 0UL;
+       unsigned long stripe_width_sectors = 0UL;
+       int level, raid_disks, data_disks;
+
+       chunk_size_sectors = dev_md_chunk_size(sysfs_dir, dev);
+       if (!chunk_size_sectors)
+               return 0;
+
+       level = dev_md_level(sysfs_dir, dev);
+       if (level < 0)
+               return 0;
+
+       raid_disks = dev_md_raid_disks(sysfs_dir, dev);
+       if (!raid_disks)
+               return 0;
+
+       /* The raid level governs the number of data disks. */
+       switch (level) {
+       case 0:
+               /* striped md does not have any parity disks */
+               data_disks = raid_disks;
+               break;
+       case 1:
+       case 10:
+               /* mirrored md effectively has 1 data disk */
+               data_disks = 1;
+               break;
+       case 4:
+       case 5:
+               /* both raid 4 and 5 have a single parity disk */
+               data_disks = raid_disks - 1;
+               break;
+       case 6:
+               /* raid 6 has 2 parity disks */
+               data_disks = raid_disks - 2;
+               break;
+       default:
+               log_error("Device %s has an unknown md raid level: %d",
+                         dev_name(dev), level);
+               return 0;
+       }
+
+       stripe_width_sectors = chunk_size_sectors * data_disks;
+
+       log_very_verbose("Device %s stripe-width is %lu bytes.",
+                        dev_name(dev),
+                        stripe_width_sectors << SECTOR_SHIFT);
+
+       return stripe_width_sectors;
+}
+
 #else
 
 int dev_is_md(struct device *dev __attribute((unused)),
@@ -189,8 +315,8 @@ int dev_is_md(struct device *dev __attribute((unused)),
        return 0;
 }
 
-unsigned long dev_md_chunk_size(const char *sysfs_dir __attribute((unused)),
-                               struct device *dev  __attribute((unused)))
+unsigned long dev_md_stripe_width(const char *sysfs_dir __attribute((unused)),
+                                 struct device *dev  __attribute((unused)))
 {
        return 0UL;
 }
index 94f17b43e7abef3fb2a5c85db56cc4bef9d4ae9b..b01682346b2e2435e79a4d28a3aa3f4e43edabff 100644 (file)
@@ -96,7 +96,7 @@ const char *dev_name_confirmed(struct device *dev, int quiet);
 /* Does device contain md superblock?  If so, where? */
 int dev_is_md(struct device *dev, uint64_t *sb);
 int dev_is_swap(struct device *dev, uint64_t *signature);
-unsigned long dev_md_chunk_size(const char *sysfs_dir, struct device *dev);
+unsigned long dev_md_stripe_width(const char *sysfs_dir, struct device *dev);
 
 int is_partitioned_dev(struct device *dev);
 
index dc7e759d96e85030bc1eb97d8a15278ad97d7c06..fda07be1fbfbe2a895a6e563c7aaaee8902abb82 100644 (file)
@@ -81,13 +81,13 @@ unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignm
                goto out;
 
        /*
-        * Align to chunk size of underlying md device if present
+        * Align to stripe-width of underlying md device if present
         */
        if (find_config_tree_bool(pv->fmt->cmd, "devices/md_chunk_alignment",
                                  DEFAULT_MD_CHUNK_ALIGNMENT))
                pv->pe_align = MAX(pv->pe_align,
-                                  dev_md_chunk_size(pv->fmt->cmd->sysfs_dir,
-                                                    pv->dev));
+                                  dev_md_stripe_width(pv->fmt->cmd->sysfs_dir,
+                                                      pv->dev));
 
        log_very_verbose("%s: Setting PE alignment to %lu sectors.",
                         dev_name(pv->dev), pv->pe_align);
index 68024b65d5d0098f6c367b1dbdab5f91a96d2f0f..0e3a949d9fbf10f29e5d3290f136a8fbe0ad33ca 100644 (file)
@@ -134,8 +134,8 @@ superblocks. This doesn't always work satisfactorily e.g. if a device
 has been reused without wiping the md superblocks first.
 .IP
 \fBmd_chunk_alignment\fP \(em If set to 1, and a Physical Volume is placed
-directly upon an md device, LVM2 will align its data blocks with the the
-chunk_size exposed in sysfs.
+directly upon an md device, LVM2 will align its data blocks with the
+md device's stripe-width.
 .IP
 \fBdata_alignment\fP \(em Default alignment (in KB) of start of data area
 when creating a new Physical Volume using the \fBlvm2\fP format.
This page took 0.048376 seconds and 5 git commands to generate.