aboutsummaryrefslogtreecommitdiffstats
path: root/super-ddf.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-08-07 16:59:26 +1000
committerNeilBrown <neilb@suse.de>2013-08-07 17:09:24 +1000
commit3921e41a9d20fa0055968f8b35f3642c81249d83 (patch)
treec7d1b45bb756e1979390eb26a4a7ed2203de3f5f /super-ddf.c
parent7d8a70bf236bd18bf175dddf4af6aa8f79b7eb25 (diff)
downloadmdadm-3921e41a9d20fa0055968f8b35f3642c81249d83.tar.gz
DDF: Write new conf entries with a single write.
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>
Diffstat (limited to 'super-ddf.c')
-rw-r--r--super-ddf.c67
1 files changed, 26 insertions, 41 deletions
diff --git a/super-ddf.c b/super-ddf.c
index b7c61429..8ebc0030 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -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");
}