mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
- Change label format to include a string disk_type and a version number.
- The iterator can find labels by string and also appropriate version number (==, <= or any) if you want. - Add labels_match() call that compares the two labels and returns an error if they do not match. - Write labels in sector 1 & last rather than 2 & last as per Joe.
This commit is contained in:
parent
5b82db9a17
commit
f4a7ce7c49
@ -7,6 +7,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "device.h"
|
||||
@ -27,16 +28,19 @@ static void *label_pool = NULL;
|
||||
struct label_ondisk
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t format_type;
|
||||
uint32_t checksum;
|
||||
uint16_t datalen;
|
||||
uint16_t pad;
|
||||
|
||||
char disk_type[32];
|
||||
uint32_t version[3];
|
||||
};
|
||||
|
||||
struct filter_private
|
||||
{
|
||||
void *mem;
|
||||
uint32_t format_type;
|
||||
char disk_type[32];
|
||||
uint32_t version[3];
|
||||
int version_match;
|
||||
};
|
||||
|
||||
|
||||
@ -47,7 +51,9 @@ static uint32_t calc_checksum(struct label *label)
|
||||
int i;
|
||||
|
||||
csum += label->magic;
|
||||
csum += label->format_type;
|
||||
csum += label->version[0];
|
||||
csum += label->version[1];
|
||||
csum += label->version[2];
|
||||
csum += label->datalen;
|
||||
|
||||
for (i=0; i<label->datalen; i++)
|
||||
@ -55,6 +61,11 @@ static uint32_t calc_checksum(struct label *label)
|
||||
csum += label->data[i];
|
||||
}
|
||||
|
||||
for (i=0; i<strlen(label->disk_type); i++)
|
||||
{
|
||||
csum += label->disk_type[i];
|
||||
}
|
||||
|
||||
return csum;
|
||||
}
|
||||
|
||||
@ -76,7 +87,7 @@ int label_read(struct device *dev, struct label *label)
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
if (!dev_open(dev, O_RDWR))
|
||||
if (!dev_open(dev, O_RDONLY))
|
||||
return 0;
|
||||
|
||||
if (label_pool == NULL)
|
||||
@ -86,38 +97,59 @@ int label_read(struct device *dev, struct label *label)
|
||||
if (!block)
|
||||
{
|
||||
stack;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
ondisk = (struct label_ondisk *)block;
|
||||
|
||||
status = dev_read(dev, sectsize*2, sectsize, block);
|
||||
|
||||
/* If the first label is bad then use the second */
|
||||
for (iter = 0; iter <= 1; iter++)
|
||||
{
|
||||
if (iter == 0)
|
||||
status = dev_read(dev, sectsize*2, sectsize, block);
|
||||
status = dev_read(dev, sectsize, sectsize, block);
|
||||
else
|
||||
status = dev_read(dev, size*512 - sectsize, sizeof(struct label_ondisk) + label->datalen, block);
|
||||
status = dev_read(dev, size*512 - sectsize, sectsize, block);
|
||||
|
||||
if (status)
|
||||
{
|
||||
struct label incore;
|
||||
int i;
|
||||
int found_nul;
|
||||
|
||||
/* Copy and convert endianness */
|
||||
/* If the MAGIC doesn't match there's no point in
|
||||
carrying on */
|
||||
if (xlate32(ondisk->magic) != LABEL_MAGIC)
|
||||
continue;
|
||||
|
||||
/* Look for a NUL in the disk_type string so we don't
|
||||
SEGV is something has gone horribly wrong */
|
||||
found_nul = 0;
|
||||
for (i=0; i<sizeof(ondisk->disk_type); i++)
|
||||
if (ondisk->disk_type[i] == '\0')
|
||||
found_nul = 1;
|
||||
|
||||
if (!found_nul)
|
||||
continue;
|
||||
|
||||
/* Copy and convert endianness */
|
||||
incore.magic = xlate32(ondisk->magic);
|
||||
incore.format_type = xlate32(ondisk->format_type);
|
||||
incore.version[0] = xlate32(ondisk->version[0]);
|
||||
incore.version[1] = xlate32(ondisk->version[1]);
|
||||
incore.version[2] = xlate32(ondisk->version[2]);
|
||||
for (i=0; i<strlen(ondisk->disk_type)+1; i++)
|
||||
incore.disk_type[i] = ondisk->disk_type[i];
|
||||
incore.checksum = xlate32(ondisk->checksum);
|
||||
incore.datalen = xlate16(ondisk->datalen);
|
||||
incore.data = block + sizeof(struct label_ondisk);
|
||||
|
||||
if (incore.magic != LABEL_MAGIC)
|
||||
/* Make sure datalen is a sensible size too */
|
||||
if (incore.datalen > sectsize)
|
||||
continue;
|
||||
|
||||
/* Check Checksum */
|
||||
if (incore.checksum != calc_checksum(&incore))
|
||||
{
|
||||
log_error("Checksum %d on device %s does not match. got %x, need %x", iter, dev_name(dev), incore.checksum, calc_checksum(&incore));
|
||||
log_error("Checksum %d on device %s does not match. got %x, expected %x",
|
||||
iter, dev_name(dev), incore.checksum, calc_checksum(&incore));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -127,10 +159,9 @@ int label_read(struct device *dev, struct label *label)
|
||||
if (!label->data)
|
||||
{
|
||||
stack;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
memcpy(label->data, incore.data, incore.datalen);
|
||||
label->pool = label_pool;
|
||||
|
||||
pool_free(label_pool, block);
|
||||
dev_close(dev);
|
||||
@ -152,6 +183,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
char *block;
|
||||
struct label_ondisk *ondisk;
|
||||
int status1, status2;
|
||||
int i;
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
return 0;
|
||||
@ -170,7 +202,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
if (!block)
|
||||
{
|
||||
stack;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ondisk = (struct label_ondisk *)block;
|
||||
@ -178,7 +210,12 @@ int label_write(struct device *dev, struct label *label)
|
||||
/* Make into ondisk format */
|
||||
label->magic = LABEL_MAGIC;
|
||||
ondisk->magic = xlate32(LABEL_MAGIC);
|
||||
ondisk->format_type = xlate32(label->format_type);
|
||||
|
||||
ondisk->version[0] = xlate32(label->version[0]);
|
||||
ondisk->version[1] = xlate32(label->version[1]);
|
||||
ondisk->version[2] = xlate32(label->version[2]);
|
||||
for (i=0; i<strlen(label->disk_type)+1; i++)
|
||||
ondisk->disk_type[i] = label->disk_type[i];
|
||||
ondisk->datalen = xlate16(label->datalen);
|
||||
ondisk->checksum = xlate32(calc_checksum(label));
|
||||
memcpy(block+sizeof(struct label_ondisk), label->data, label->datalen);
|
||||
@ -190,7 +227,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
return 0;
|
||||
}
|
||||
|
||||
status1 = dev_write(dev, sectsize*2, sizeof(struct label_ondisk) + label->datalen, block);
|
||||
status1 = dev_write(dev, sectsize, sizeof(struct label_ondisk) + label->datalen, block);
|
||||
|
||||
/* Write another at the end of the device */
|
||||
status2 = dev_write(dev, size*512 - sectsize, sizeof(struct label_ondisk) + label->datalen, block);
|
||||
@ -210,7 +247,7 @@ int is_labelled(struct device *dev)
|
||||
int status;
|
||||
|
||||
status = label_read(dev, &l);
|
||||
if (status) pool_free(l.pool, l.data);
|
||||
if (status) label_free(&l);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -220,15 +257,42 @@ static int _accept_format(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct label l;
|
||||
int status;
|
||||
struct filter_private *fp = (struct filter_private *) f->private;
|
||||
|
||||
status = label_read(dev, &l);
|
||||
if (status) pool_free(l.pool, l.data);
|
||||
if (status) label_free(&l);
|
||||
|
||||
if (status && l.format_type == (uint32_t)f->private)
|
||||
return 1;
|
||||
if (status)
|
||||
{
|
||||
if (strcmp(l.disk_type, fp->disk_type) == 0)
|
||||
{
|
||||
switch (fp->version_match)
|
||||
{
|
||||
case VERSION_MATCH_EQUAL:
|
||||
if (l.version[0] == fp->version[0] &&
|
||||
l.version[1] == fp->version[1] &&
|
||||
l.version[2] == fp->version[2])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
else
|
||||
return 0;
|
||||
case VERSION_MATCH_LESSTHAN:
|
||||
if (l.version[0] == fp->version[0] &&
|
||||
l.version[1] < fp->version[1])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case VERSION_MATCH_LESSEQUAL:
|
||||
if (l.version[0] == fp->version[0] &&
|
||||
l.version[1] <= fp->version[1])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case VERSION_MATCH_ANY:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We just want to know if it's labelled or not */
|
||||
@ -244,12 +308,20 @@ static void _destroy(struct dev_filter *f)
|
||||
}
|
||||
|
||||
/* A filter to find devices with a particular label type on them */
|
||||
struct dev_filter *label_format_filter_create(uint32_t format_type)
|
||||
struct dev_filter *label_format_filter_create(char *disk_type, uint32_t version[3], int match_type)
|
||||
{
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
struct pool *mem;
|
||||
struct filter_private *fp;
|
||||
struct dev_filter *f;
|
||||
|
||||
/* Validate the match type */
|
||||
if (match_type != VERSION_MATCH_EQUAL &&
|
||||
match_type != VERSION_MATCH_LESSTHAN &&
|
||||
match_type != VERSION_MATCH_LESSEQUAL &&
|
||||
match_type != VERSION_MATCH_ANY)
|
||||
return 0;
|
||||
|
||||
mem = pool_create(10 * 1024);
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
@ -266,7 +338,11 @@ struct dev_filter *label_format_filter_create(uint32_t format_type)
|
||||
}
|
||||
|
||||
fp->mem = mem;
|
||||
fp->format_type = format_type;
|
||||
strcpy(fp->disk_type, disk_type);
|
||||
fp->version[0] = version[0];
|
||||
fp->version[1] = version[1];
|
||||
fp->version[2] = version[2];
|
||||
fp->version_match = match_type;
|
||||
f->passes_filter = _accept_format;
|
||||
f->destroy = _destroy;
|
||||
f->private = fp;
|
||||
@ -311,3 +387,85 @@ struct dev_filter *label_filter_create()
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return 1 if both labels are identical, 0 if not or there was an error */
|
||||
int labels_match(struct device *dev)
|
||||
{
|
||||
uint64_t size;
|
||||
uint32_t sectsize;
|
||||
char *block1;
|
||||
char *block2;
|
||||
struct label_ondisk *ondisk1;
|
||||
struct label_ondisk *ondisk2;
|
||||
int status = 0;
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
if (label_pool == NULL)
|
||||
label_pool = pool_create(512);
|
||||
|
||||
/* ALlocate some space for the blocks we are going to read in */
|
||||
block1 = pool_alloc(label_pool, sectsize);
|
||||
if (!block1)
|
||||
{
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
block2 = pool_alloc(label_pool, sectsize);
|
||||
if (!block2)
|
||||
{
|
||||
stack;
|
||||
pool_free(label_pool, block1);
|
||||
return 0;
|
||||
}
|
||||
ondisk1 = (struct label_ondisk *)block1;
|
||||
ondisk2 = (struct label_ondisk *)block2;
|
||||
|
||||
/* Fetch em */
|
||||
if (!dev_open(dev, O_RDONLY))
|
||||
goto finish;
|
||||
|
||||
if (!dev_read(dev, sectsize, sectsize, block1))
|
||||
goto finish;
|
||||
|
||||
if (!dev_read(dev, size*512 - sectsize, sectsize, block2))
|
||||
goto finish;
|
||||
|
||||
dev_close(dev);
|
||||
|
||||
/* Is it labelled? */
|
||||
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
|
||||
goto finish;
|
||||
|
||||
/* Compare the whole structs */
|
||||
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
|
||||
goto finish;
|
||||
|
||||
/* OK, check the data area */
|
||||
if (memcmp(block1 + sizeof(struct label_ondisk),
|
||||
block2 + sizeof(struct label_ondisk),
|
||||
xlate16(ondisk1->datalen)) != 0)
|
||||
goto finish;
|
||||
|
||||
/* They match !! */
|
||||
status = 1;
|
||||
|
||||
finish:
|
||||
pool_free(label_pool, block2);
|
||||
pool_free(label_pool, block1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free data area allocated by label_read() */
|
||||
void label_free(struct label *label)
|
||||
{
|
||||
if (label->data)
|
||||
pool_free(label_pool, label->data);
|
||||
}
|
||||
|
||||
|
@ -7,18 +7,25 @@
|
||||
struct label
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t format_type;
|
||||
uint32_t checksum;
|
||||
uint16_t datalen;
|
||||
char *data;
|
||||
void *pool; /* Pool that data is allocated from */
|
||||
|
||||
char disk_type[32];
|
||||
uint32_t version[3];
|
||||
|
||||
char *data; /* Should be freed with label_free() */
|
||||
};
|
||||
|
||||
#define VERSION_MATCH_EQUAL 1
|
||||
#define VERSION_MATCH_LESSTHAN 2
|
||||
#define VERSION_MATCH_LESSEQUAL 3
|
||||
#define VERSION_MATCH_ANY 4
|
||||
|
||||
|
||||
extern int label_write(struct device *dev, struct label *label);
|
||||
extern int label_read(struct device *dev, struct label *label);
|
||||
extern int is_labelled(struct device *dev);
|
||||
extern int label_write(struct device *dev, struct label *label);
|
||||
extern int label_read(struct device *dev, struct label *label);
|
||||
extern void label_free(struct label *label);
|
||||
extern int is_labelled(struct device *dev);
|
||||
extern int labels_match(struct device *dev);
|
||||
|
||||
extern struct dev_filter *label_filter_create();
|
||||
extern struct dev_filter *label_format_filter_create(uint32_t format_type);
|
||||
extern struct dev_filter *label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);
|
||||
|
Loading…
Reference in New Issue
Block a user