]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
DDF: Write new conf entries with a single write.
authorNeilBrown <neilb@suse.de>
Wed, 7 Aug 2013 06:59:26 +0000 (16:59 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 7 Aug 2013 07:09:24 +0000 (17:09 +1000)
The recent change to skip over invalid conf entries was bad because
it could leave garbage on the disk.
But we don't to write each entry separately as the writes a O_DIRECT
and so synchronous so it takes way too long.

So allocate a large buffer (probably the one used to read the config records)
and fill that then write it all at once.

Reported-by: Martin Wilck <mwilck@arcor.de>
Signed-off-by: NeilBrown <neilb@suse.de>
super-ddf.c

index b7c614298bbbcd4d5a9798253009b7b9204db22b..8ebc00307183b28d1cbb8cd6881addb86b246b8d 100644 (file)
@@ -439,6 +439,7 @@ struct ddf_super {
        struct ddf_header *active;
        struct phys_disk        *phys;
        struct virtual_disk     *virt;
+       char                    *conf;
        int pdsize, vdsize;
        unsigned int max_part, mppe, conf_rec_len;
        int currentdev;
@@ -791,11 +792,7 @@ static void *load_section(int fd, struct ddf_super *super, void *buf,
 
        if (len > 1024)
                return NULL;
-       if (buf) {
-               /* All pre-allocated sections are a single block */
-               if (len != 1)
-                       return NULL;
-       } else if (posix_memalign(&buf, 512, len<<9) != 0)
+       if (!buf && posix_memalign(&buf, 512, len<<9) != 0)
                buf = NULL;
 
        if (!buf)
@@ -1031,11 +1028,11 @@ static int load_ddf_local(int fd, struct ddf_super *super,
         * the conflist
         */
 
-       conf = load_section(fd, super, NULL,
+       conf = load_section(fd, super, super->conf,
                            super->active->config_section_offset,
                            super->active->config_section_length,
                            0);
-
+       super->conf = conf;
        vnum = 0;
        for (confsec = 0;
             confsec < be32_to_cpu(super->active->config_section_length);
@@ -1103,7 +1100,6 @@ static int load_ddf_local(int fd, struct ddf_super *super,
                if (i < max_virt_disks)
                        vcl->vcnum = i;
        }
-       free(conf);
 
        return 0;
 }
@@ -1201,6 +1197,7 @@ static void free_super_ddf(struct supertype *st)
                return;
        free(ddf->phys);
        free(ddf->virt);
+       free(ddf->conf);
        while (ddf->conflist) {
                struct vcl *v = ddf->conflist;
                ddf->conflist = v->next;
@@ -2823,21 +2820,13 @@ static int remove_from_super_ddf(struct supertype *st, mdu_disk_info_t *dk)
  */
 #define NULL_CONF_SZ   4096
 
-static char *null_aligned;
-static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type,
-                                int update)
+static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type)
 {
        unsigned long long sector;
        struct ddf_header *header;
-       int fd, i, n_config, conf_size;
+       int fd, i, n_config, conf_size, buf_size;
        int ret = 0;
-
-       if (null_aligned == NULL) {
-               if (posix_memalign((void **)&null_aligned, 4096, NULL_CONF_SZ)
-                   != 0)
-                       return 0;
-               memset(null_aligned, 0xff, NULL_CONF_SZ);
-       }
+       char *conf;
 
        fd = d->fd;
 
@@ -2876,6 +2865,13 @@ static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type,
        /* Now write lots of config records. */
        n_config = ddf->max_part;
        conf_size = ddf->conf_rec_len * 512;
+       conf = ddf->conf;
+       buf_size = conf_size * (n_config + 1);
+       if (!conf) {
+               if (posix_memalign((void**)&conf, 512, buf_size) != 0)
+                       goto out;
+               ddf->conf = conf;
+       }
        for (i = 0 ; i <= n_config ; i++) {
                struct vcl *c;
                struct vd_config *vdc = NULL;
@@ -2900,21 +2896,11 @@ static int __write_ddf_structure(struct dl *d, struct ddf_super *ddf, __u8 type,
                                vdc->sec_elmnt_seq);
                        vdc->seqnum = header->seq;
                        vdc->crc = calc_crc(vdc, conf_size);
-                       if (write(fd, vdc, conf_size) < 0)
-                               break;
-               } else if (!update) {
-                       unsigned int togo = conf_size;
-                       while (togo > NULL_CONF_SZ) {
-                               if (write(fd, null_aligned, NULL_CONF_SZ) < 0)
-                                       break;
-                               togo -= NULL_CONF_SZ;
-                       }
-                       if (write(fd, null_aligned, togo) < 0)
-                               break;
+                       memcpy(conf + i*conf_size, vdc, conf_size);
                } else
-                       lseek(fd, conf_size, SEEK_CUR);
+                       memset(conf + i*conf_size, 0xff, conf_size);
        }
-       if (i <= n_config)
+       if (write(fd, conf, buf_size) != buf_size)
                goto out;
 
        d->disk.crc = calc_crc(&d->disk, 512);
@@ -2933,8 +2919,7 @@ out:
        return ret;
 }
 
-static int _write_super_to_disk(struct ddf_super *ddf, struct dl *d,
-                               int update)
+static int _write_super_to_disk(struct ddf_super *ddf, struct dl *d)
 {
        unsigned long long size;
        int fd = d->fd;
@@ -2972,10 +2957,10 @@ static int _write_super_to_disk(struct ddf_super *ddf, struct dl *d,
        ddf->anchor.seq = cpu_to_be32(0xFFFFFFFF); /* no sequencing in anchor */
        ddf->anchor.crc = calc_crc(&ddf->anchor, 512);
 
-       if (!__write_ddf_structure(d, ddf, DDF_HEADER_PRIMARY, update))
+       if (!__write_ddf_structure(d, ddf, DDF_HEADER_PRIMARY))
                return 0;
 
-       if (!__write_ddf_structure(d, ddf, DDF_HEADER_SECONDARY, update))
+       if (!__write_ddf_structure(d, ddf, DDF_HEADER_SECONDARY))
                return 0;
 
        lseek64(fd, (size-1)*512, SEEK_SET);
@@ -2986,7 +2971,7 @@ static int _write_super_to_disk(struct ddf_super *ddf, struct dl *d,
 }
 
 #ifndef MDASSEMBLE
-static int __write_init_super_ddf(struct supertype *st, int update)
+static int __write_init_super_ddf(struct supertype *st)
 {
        struct ddf_super *ddf = st->sb;
        struct dl *d;
@@ -3000,7 +2985,7 @@ static int __write_init_super_ddf(struct supertype *st, int update)
         */
        for (d = ddf->dlist; d; d=d->next) {
                attempts++;
-               successes += _write_super_to_disk(ddf, d, update);
+               successes += _write_super_to_disk(ddf, d);
        }
 
        return attempts != successes;
@@ -3061,7 +3046,7 @@ static int write_init_super_ddf(struct supertype *st)
                if (!currentconf)
                        for (d = ddf->dlist; d; d=d->next)
                                while (Kill(d->devname, NULL, 0, -1, 1) == 0);
-               return __write_init_super_ddf(st, 0);
+               return __write_init_super_ddf(st);
        }
 }
 
@@ -3805,7 +3790,7 @@ static int store_super_ddf(struct supertype *st, int fd)
                }
                ofd = dl->fd;
                dl->fd = fd;
-               ret = (_write_super_to_disk(ddf, dl, 0) != 1);
+               ret = (_write_super_to_disk(ddf, dl) != 1);
                dl->fd = ofd;
                return ret;
        }
@@ -4261,7 +4246,7 @@ static void ddf_sync_metadata(struct supertype *st)
        if (!ddf->updates_pending)
                return;
        ddf->updates_pending = 0;
-       __write_init_super_ddf(st, 1);
+       __write_init_super_ddf(st);
        dprintf("ddf: sync_metadata\n");
 }