1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

o Populating with stuff from experimental

This commit is contained in:
Joe Thornber 2001-08-21 12:56:08 +00:00
parent 537d817f8a
commit df88dece8b
8 changed files with 1508 additions and 0 deletions

618
lib/config/config.c Normal file
View File

@ -0,0 +1,618 @@
/*
* tools/lib/lvm_config.c
*
* Copyright (C) 2001 Sistina Software
*
*
* This LVM library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This LVM library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this LVM library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*
*/
/*
* Changelog
*
* 17/04/2001 - First version [Joe Thornber]
*
*/
#include "config.h"
#include "pool.h"
#include "log.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
enum {
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_COMMA,
TOK_EOF
};
struct parser {
const char *fb, *fe; /* file limits */
int t; /* token limits and type */
const char *tb, *te;
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
struct pool *mem;
};
struct cs {
struct config_file cf;
struct pool *mem;
};
static void _get_token(struct parser *p);
static void _eat_space(struct parser *p);
static struct config_node *_file(struct parser *p);
static struct config_node *_section(struct parser *p);
static struct config_value *_value(struct parser *p);
static struct config_value *_type(struct parser *p);
static void _parse_error(struct parser *p, const char *file, int line,
const char *mess);
static int _match_aux(struct parser *p, int t);
static struct config_value *_create_value(struct parser *p);
static struct config_node *_create_node(struct parser *p);
static char *_dup_tok(struct parser *p);
static int _tok_match(const char *str, const char *b, const char *e);
#define MAX_INDENT 32
#define match(t) do {\
if (!_match_aux(p, (t))) {\
_parse_error(p, __FILE__, __LINE__, "unexpected token"); \
return 0;\
} \
} while(0);
/*
* public interface
*/
struct config_file *create_config_file()
{
struct cs *c;
struct pool *mem = create_pool(10 * 1024);
if (!mem) {
stack;
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
destroy_pool(mem);
return 0;
}
c->mem = mem;
return &c->cf;
}
void destroy_config_file(struct config_file *cf)
{
destroy_pool(((struct cs *) cf)->mem);
}
int read_config(struct config_file *cf, const char *file)
{
struct cs *c = (struct cs *) cf;
struct parser *p;
struct stat info;
int r = 1, fd;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
p->mem = c->mem;
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
log_sys_err("stat");
return 0;
}
if ((fd = open(file, O_RDONLY)) < 0) {
log_sys_err("open");
return 0;
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == MAP_FAILED) {
log_sys_err("mmap");
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_err("munmap failed");
r = 0;
}
close(fd);
return r;
}
static void _write_value(FILE *fp, struct config_value *v)
{
switch (v->type) {
case CFG_STRING:
fprintf(fp, "\"%s\"", v->v.str);
break;
case CFG_FLOAT:
fprintf(fp, "%f", v->v.r);
break;
case CFG_INT:
fprintf(fp, "%d", v->v.i);
break;
}
}
static int _write_config(struct config_node *n, FILE *fp, int level)
{
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
int i;
if (!n)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\0';
while (n) {
fprintf(fp, "%s%s", space, n->key);
if (!n->v) {
/* it's a sub section */
fprintf(fp, " {\n");
_write_config(n->child, fp, level + 1);
fprintf(fp, "%s}", space);
} else {
/* it's a value */
struct config_value *v = n->v;
fprintf(fp, "=");
if (v->next) {
fprintf(fp, "[");
while (v) {
_write_value(fp, v);
v = v->next;
if (v)
fprintf(fp, ", ");
}
fprintf(fp, "]");
} else
_write_value(fp, v);
}
fprintf(fp, "\n");
n = n->sib;
}
/* FIXME: add error checking */
return 1;
}
int write_config(struct config_file *cf, const char *file)
{
int r = 1;
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_err("open");
return 0;
}
if (!_write_config(cf->root, fp, 0)) {
stack;
r = 0;
}
fclose(fp);
return r;
}
/*
* parser
*/
static struct config_node *_file(struct parser *p)
{
struct config_node *root = 0, *n, *l;
while (p->t != TOK_EOF) {
if (!(n = _section(p))) {
stack;
return 0;
}
if (!root)
root = n;
else
l->sib = n;
l = n;
}
return root;
}
static struct config_node *_section(struct parser *p)
{
/* IDENTIFIER '{' VALUE* '}' */
struct config_node *root, *n, *l;
if (!(root = _create_node(p))) {
stack;
return 0;
}
if (!(root->key = _dup_tok(p))) {
stack;
return 0;
}
match (TOK_IDENTIFIER);
if (p->t == TOK_SECTION_B) {
match(TOK_SECTION_B);
while (p->t != TOK_SECTION_E) {
if (!(n = _section(p))) {
stack;
return 0;
}
if (!root->child)
root->child = n;
else
l->sib = n;
l = n;
}
match(TOK_SECTION_E);
} else {
match(TOK_EQ);
if (!(root->v = _value(p))) {
stack;
return 0;
}
}
return root;
}
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
if (p->t == TOK_ARRAY_B) {
match (TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
stack;
return 0;
}
if (!h)
h = l;
else
ll->next = l;
ll = l;
if (p->t == TOK_COMMA)
match(TOK_COMMA);
}
match(TOK_ARRAY_E);
} else
h = _type(p);
return h;
}
static struct config_value *_type(struct parser *p) {
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p);
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 10); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
match(TOK_FLOAT);
break;
case TOK_STRING:
v->type = CFG_STRING;
p->tb++, p->te--; /* strip "'s */
if (!(v->v.str = _dup_tok(p))) {
stack;
return 0;
}
p->te++;
match(TOK_STRING);
break;
default:
_parse_error(p, __FILE__, __LINE__, "expected a value");
return 0;
}
return v;
}
static void _parse_error(struct parser *p, const char *file, int line,
const char *mess)
{
plog(_LOG_ERR, file, line, "parse error at %d: %s", p->line, mess);
}
static int _match_aux(struct parser *p, int t)
{
if (p->t != t)
return 0;
_get_token(p);
return 1;
}
/*
* tokeniser
*/
static void _get_token(struct parser *p)
{
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
p->t = TOK_EOF;
return;
}
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
break;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
p->te++;
p->te++;
}
if (p->te != p->fe)
p->te++;
break;
case '.':
p->t = TOK_FLOAT;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
p->te++;
while (p->te != p->fe) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++;
}
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
}
}
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
p->te++;
p->line++;
}
else if (isspace(*p->te)) {
while ((p->te != p->fe) && isspace(*p->te)) {
if (*p->te == '\n')
p->line++;
p->te++;
}
}
else
return;
p->tb = p->te;
}
}
/*
* memory management
*/
static struct config_value *_create_value(struct parser *p)
{
struct config_value *v = pool_alloc(p->mem, sizeof(*v));
memset(v, 0, sizeof(*v));
return v;
}
static struct config_node *_create_node(struct parser *p)
{
struct config_node *n = pool_alloc(p->mem, sizeof(*n));
memset(n, 0, sizeof(*n));
return n;
}
static char *_dup_tok(struct parser *p)
{
int len = p->te - p->tb;
char *str = pool_alloc(p->mem, len + 1);
if (!str) {
stack;
return 0;
}
strncpy(str, p->tb, len);
str[len] = '\0';
return str;
}
/*
* utility functions
*/
struct config_node *find_config_node(struct config_node *cn,
const char *path, char sep)
{
const char *e;
while (cn) {
/* trim any leading slashes */
while (*path && (*path == sep))
path++;
/* find the end of this segment */
for (e = path; *e && (*e != sep); e++)
;
/* hunt for the node */
while (cn) {
if (_tok_match(cn->key, path, e))
break;
cn = cn->sib;
}
if (cn && *e)
cn = cn->child;
else
break; /* don't move into the last node */
path = e;
}
return cn;
}
const char *
find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
if (n && n->v->type == CFG_STRING)
return n->v->v.str;
return fail;
}
int find_config_int(struct config_node *cn, const char *path,
char sep, int fail)
{
struct config_node *n = find_config_node(cn, path, sep);
if (n && n->v->type == CFG_INT)
return n->v->v.i;
return fail;
}
float find_config_float(struct config_node *cn, const char *path,
char sep, float fail)
{
struct config_node *n = find_config_node(cn, path, sep);
if (n && n->v->type == CFG_FLOAT)
return n->v->v.r;
return fail;
}
static int _tok_match(const char *str, const char *b, const char *e)
{
while (*str && (b != e)) {
if (*str++ != *b++)
return 0;
}
return !(*str || (b != e));
}
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

76
lib/config/config.h Normal file
View File

@ -0,0 +1,76 @@
/*
* tools/lib/config.h
*
* Copyright (C) 2001 Sistina Software
*
*
* This LVM library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This LVM library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this LVM library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*/
#ifndef LVM_CONFIG_H
#define LVM_CONFIG_H
enum {
CFG_STRING,
CFG_FLOAT,
CFG_INT,
};
struct config_value {
int type;
union {
int i;
float r;
char *str;
} v;
struct config_value *next; /* for arrays */
};
struct config_node {
char *key;
struct config_node *sib, *child;
struct config_value *v;
};
struct config_file {
struct config_node *root;
};
struct config_file *create_config_file();
void destroy_config_file(struct config_file *cf);
int read_config(struct config_file *cf, const char *file);
int write_config(struct config_file *cf, const char *file);
struct config_node *find_config_node(struct config_node *cn,
const char *path, char seperator);
const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail);
int find_config_int(struct config_node *cn, const char *path,
char sep, int fail);
float find_config_float(struct config_node *cn, const char *path,
char sep, float fail);
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

152
lib/log/log.c Normal file
View File

@ -0,0 +1,152 @@
/*
* tools/lib/lvm_log.c
*
* Copyright (C) 2001 Sistina Software
*
*
* This LVM library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This LVM library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this LVM library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*
*/
/*
* Changelog
*
* 22/01/2001 - First version (Joe Thornber)
*
*/
#include "log.h"
#include <stdarg.h>
#include <syslog.h>
static FILE *_log = 0;
static int _verbose_level = 0;
static int _test = 0;
static int _debug_level = 0;
static int _syslog = 0;
void init_log(FILE *fp) {
_log = fp;
}
void init_syslog(int facility) {
openlog("lvm", LOG_PID, facility);
_syslog = 1;
}
void fin_log() {
_log = 0;
}
void fin_syslog() {
closelog();
_syslog = 0;
}
void init_verbose(int level) {
_verbose_level = level;
}
void init_test(int level) {
_test = level;
}
int test_mode() {
return _test;
}
void init_debug(int level) {
_debug_level = level;
}
int debug_level() {
return _debug_level;
}
void print_log(int level, const char *file, int line, const char *format, ...) {
va_list ap;
va_start(ap, format);
switch(level) {
case _LOG_DEBUG:
if (_verbose_level > 2) {
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_INFO:
if (_verbose_level > 1) {
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_NOTICE:
if (_verbose_level) {
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_WARN:
printf(" ");
vprintf(format, ap);
putchar('\n');
break;
case _LOG_ERR:
fprintf(stderr, " ");
vfprintf(stderr, format, ap);
fputc('\n',stderr);
break;
case _LOG_FATAL:
vfprintf(stderr, format, ap);
fputc('\n',stderr);
break;
default:
;
}
va_end(ap);
if (level > _debug_level)
return;
if (_log) {
fprintf(_log, "%s:%d ", file, line);
va_start(ap, format);
vfprintf(_log, format, ap);
va_end(ap);
fprintf(_log, "\n");
fflush(_log);
}
if (_syslog) {
va_start(ap, format);
vsyslog(level, format, ap);
va_end(ap);
}
}
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

97
lib/log/log.h Normal file
View File

@ -0,0 +1,97 @@
/*
* tools/lib/lvm_log.h
*
* Copyright (C) 2001 Sistina Software
*
*
* This LVM library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This LVM library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this LVM library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*
*/
/*
* Changelog
*
* 22/01/2001 - First version (Joe Thornber)
* 25/04/2001 - Remove some spurious ##s that annoyed newer gcc versions.
*
*/
#ifndef LVM_LOG_H
#define LVM_LOG_H
#include <stdio.h>
#define _LOG_DEBUG 7
#define _LOG_INFO 6
#define _LOG_NOTICE 5
#define _LOG_WARN 4
#define _LOG_ERR 3
#define _LOG_FATAL 2
void init_log(FILE *fp);
void fin_log();
void init_syslog(int facility);
void fin_syslog(void);
void init_verbose(int level);
void init_test(int level);
void init_debug(int level);
int test_mode(void);
int debug_level(void);
void print_log(int level, const char *file, int line, const char *format, ...);
#define plog(l, x...) print_log(l, __FILE__, __LINE__ , ## x)
#define log_debug(x...) plog(_LOG_DEBUG, x)
#define log_info(x...) plog(_LOG_INFO, x)
#define log_notice(x...) plog(_LOG_NOTICE, x)
#define log_warn(x...) plog(_LOG_WARN, x)
#define log_err(x...) plog(_LOG_ERR, x)
#define log_fatal(x...) plog(_LOG_FATAL, x)
#define log_sys_err(x) log_debug("system call '%s' failed (%s)", \
x, strerror(errno))
#define stack log_debug( "stack trace" )
/*
* Macros to use for messages:
*
* log_error - always print to stderr
* log_print - always print to stdout
* log_verbose - print to stdout if verbose is set (-v)
* log_very_verbose - print to stdout if verbose is set twice (-vv)
* log_debug - print to stdout if verbose is set three times (-vvv)
*
* In addition, messages will be logged to file or syslog if they
* are more serious than the log level specified with -d.
*
*/
#define log_error(fmt, args...) log_err(fmt , ## args)
#define log_print(fmt, args...) log_warn(fmt , ## args)
#define log_verbose(fmt, args...) log_notice(fmt , ## args)
#define log_very_verbose(fmt, args...) log_info(fmt , ## args)
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

214
lib/mm/dbg_malloc.c Normal file
View File

@ -0,0 +1,214 @@
/*
* dbg_malloc.c
*
* Copyright (C) 2000, 2001 Sistina Software
*
* lvm is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* lvm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Changelog
*
* 9/11/2000 - First version by Joe Thornber
*
* TODO:
*
* Thread safety seems to have fallen out, put lock back in.
*/
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include "dbg_malloc.h"
#include "log.h"
struct memblock {
struct memblock *prev, *next; /* All allocated blocks are linked */
size_t length; /* Size of the requested block */
int id; /* Index of the block */
const char *file; /* File that allocated */
int line; /* Line that allocated */
void *magic; /* Address of this block */
};
static struct {
unsigned int blocks, mblocks;
unsigned int bytes, mbytes;
} _mem_stats = {0, 0, 0, 0};
static struct memblock *_head = 0;
static struct memblock *_tail = 0;
void *malloc_aux(size_t s, const char *file, int line)
{
struct memblock *nb;
size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
if (!(nb = malloc(tsize))) {
log_error("couldn't allocate any memory, size = %u", s);
return 0;
}
/* set up the file and line info */
nb->file = file;
nb->line = line;
#ifdef BOUNDS_CHECK
bounds_check();
#endif
/* setup fields */
nb->magic = nb + 1;
nb->length = s;
nb->id = ++_mem_stats.blocks;
nb->next = 0;
nb->prev = _tail;
/* link to tail of the list */
if (!_head)
_head = _tail = nb;
else {
_tail->next = nb;
_tail = nb;
}
/* stomp a pretty pattern across the new memory
and fill in the boundary bytes */
{
char *ptr = (char *) (nb + 1);
int i;
for (i = 0; i < s; i++)
*ptr++ = i & 0x1 ? (char) 0xba : (char) 0xbe;
for (i = 0; i < sizeof(unsigned long); i++)
*ptr++ = (char) nb->id;
}
if (_mem_stats.blocks > _mem_stats.mblocks)
_mem_stats.mblocks = _mem_stats.blocks;
_mem_stats.bytes += s;
if (_mem_stats.bytes > _mem_stats.mbytes)
_mem_stats.mbytes = _mem_stats.bytes;
return nb + 1;
}
void free_aux(void *p)
{
char *ptr;
int i;
struct memblock *mb = ((struct memblock *) p) - 1;
if (!p)
return;
#ifdef BOUNDS_CHECK
bounds_check();
#endif
/* sanity check */
assert(mb->magic == p);
/* check data at the far boundary */
ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
for (i = 0; i < sizeof(unsigned long); i++)
if(*ptr++ != (char) mb->id)
assert(!"Damage at far end of block");
/* have we freed this before ? */
assert(mb->id != 0);
mb->id = 0;
/* stomp a different pattern across the memory */
ptr = ((char *) mb) + sizeof(struct memblock);
for (i = 0; i < mb->length; i++)
*ptr++ = i & 1 ? (char) 0xde : (char) 0xad;
/* unlink */
if (mb->prev)
mb->prev->next = mb->next;
else
_head = mb->next;
if (mb->next)
mb->next->prev = mb->prev;
else
_tail = mb->prev;
assert(_mem_stats.blocks);
_mem_stats.blocks--;
_mem_stats.bytes -= mb->length;
/* free the memory */
free(mb);
}
void *realloc_aux(void *p, unsigned int s, const char *file, int line)
{
void *r;
struct memblock *mb = ((struct memblock *) p) - 1;
r = malloc_aux(s, file, line);
if (p) {
memcpy(r, p, mb->length);
free_aux(p);
}
return r;
}
#ifdef DEBUG_MEM
int dump_memory(void)
{
unsigned long tot = 0;
struct memblock *mb;
if (_head)
log_info("you have a memory leak:");
for (mb = _head; mb; mb = mb->next) {
print_log(_LOG_INFO, mb->file, mb->line,
"block %d at %p, size %d",
mb->id, mb->magic, mb->length);
tot += mb->length;
}
if (_head)
log_info("%ld bytes leaked in total", tot);
return 1;
}
void bounds_check(void)
{
struct memblock *mb = _head;
while (mb) {
int i;
char *ptr = ((char *) (mb + 1)) + mb->length;
for (i = 0; i < sizeof(unsigned long); i++)
if (*ptr++ != (char) mb->id)
assert(!"Memory smash");
mb = mb->next;
}
}
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

56
lib/mm/dbg_malloc.h Normal file
View File

@ -0,0 +1,56 @@
/*
* debug.h - what a wonderfully original name for a file.
*
* Copyright (C) 2000, 2001 Sistina Software
*
* lvm is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* lvm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Changelog
*
* 9/11/2000 - First version by Joe Thornber
*
* TODO:
*
*/
#ifndef DBG_MALLOC_H
#define DBG_MALLOC_H
#ifdef DEBUG_MEM
void *malloc_aux(unsigned int s, const char *file, int line);
void free_aux(void *p);
void *realloc_aux(void *p, unsigned int s, const char *file, int line);
int dump_memory(void);
void bounds_check(void);
#define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
#define dbg_free(p) free_aux(p)
#define dbg_realloc(p, s) realloc_aux(p, s, __FILE__, __LINE__)
#else
#define dbg_malloc(s) malloc(s)
#define dbg_free(p) free(p)
#define dbg_realloc(p, s) realloc(p, s)
#define dump_memory()
#define bounds_check()
#endif
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

231
lib/mm/pool.c Normal file
View File

@ -0,0 +1,231 @@
/*
* tools/lib/pool.c
*
* Copyright (C) 2001 Sistina Software
*
* LVM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* LVM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LVM; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "pool.h"
#include "dbg_malloc.h"
#include "log.h"
#include <stdlib.h>
struct chunk {
char *begin, *end;
struct chunk *prev;
};
struct pool {
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
list to stop 'bobbling' */
size_t chunk_size;
size_t object_len;
unsigned object_alignment;
};
void _align_chunk(struct chunk *c, unsigned alignment);
struct chunk *_new_chunk(struct pool *p, size_t s);
/* FIXME: alignment will need to be 4 to work on SUN boxes */
#define DEFAULT_ALIGNMENT 4
struct pool *create_pool(size_t chunk_hint)
{
size_t new_size = 1024;
struct pool *p = dbg_malloc(sizeof(*p));
if (!p) {
log_err("couldn't create pool");
return 0;
}
memset(p, 0, sizeof(*p));
/* round chunk_hint up to the next power of 2 */
p->chunk_size = chunk_hint + sizeof(struct chunk);
while (new_size < p->chunk_size)
new_size <<= 1;
p->chunk_size = new_size;
return p;
}
void destroy_pool(struct pool *p)
{
struct chunk *c, *pr;
dbg_free(p->spare_chunk);
c = p->chunk;
while (c) {
pr = c->prev;
dbg_free(c);
c = pr;
}
dbg_free(p);
}
void *pool_alloc(struct pool *p, size_t s)
{
return pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
}
void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
{
struct chunk *c = p->chunk;
void *r;
/* realign begin */
if (c)
_align_chunk(c, alignment);
/* have we got room ? */
if(!c || (c->begin > c->end) || (c->end - c->begin < s)) {
/* allocate new chunk */
int needed = s + alignment + sizeof(struct chunk);
c = _new_chunk(p, (needed > p->chunk_size) ?
needed : p->chunk_size);
_align_chunk(c, alignment);
}
r = c->begin;
c->begin += s;
return r;
}
void pool_free(struct pool *p, void *ptr)
{
struct chunk *c = p->chunk;
while (c) {
if (((char *) c < (char *) ptr) &&
((char *) c->end > (char *) ptr)) {
c->begin = ptr;
break;
}
if (p->spare_chunk)
dbg_free(p->spare_chunk);
p->spare_chunk = c;
c = c->prev;
}
if (!c)
log_warn("pool_free asked to free a pointer "
"that wasn't in the pool, doing nothing");
else
p->chunk = c;
}
void *pool_begin_object(struct pool *p, size_t hint, unsigned align)
{
struct chunk *c = p->chunk;
p->object_len = 0;
p->object_alignment = align;
_align_chunk(c, align);
if (c->end - c->begin < hint) {
/* allocate a new chunk */
c = _new_chunk(p,
hint > (p->chunk_size - sizeof(struct chunk)) ?
hint + sizeof(struct chunk) + align :
p->chunk_size);
_align_chunk(c, align);
}
return c->begin;
}
void *pool_grow_object(struct pool *p, unsigned char *buffer, size_t n)
{
struct chunk *c = p->chunk;
if (c->end - (c->begin + p->object_len) < n) {
/* move into a new chunk */
if (p->object_len + n > (p->chunk_size / 2))
_new_chunk(p, (p->object_len + n) * 2);
else
_new_chunk(p, p->chunk_size);
_align_chunk(p->chunk, p->object_alignment);
memcpy(p->chunk->begin, c->begin, p->object_len);
c = p->chunk;
}
memcpy(c->begin + p->object_len, buffer, n);
p->object_len += n;
return c->begin;
}
void *pool_end_object(struct pool *p)
{
struct chunk *c = p->chunk;
void *r = c->begin;
c->begin += p->object_len;
p->object_len = 0u;
p->object_alignment = DEFAULT_ALIGNMENT;
return r;
}
void pool_abandon_object(struct pool *p)
{
p->object_len = 0;
p->object_alignment = DEFAULT_ALIGNMENT;
}
char *pool_strdup(struct pool *p, const char *str)
{
char *ret = pool_alloc(p, strlen(str) + 1);
if (ret)
strcpy(ret, str);
return ret;
}
void _align_chunk(struct chunk *c, unsigned alignment)
{
c->begin += alignment - ((unsigned) c->begin & (alignment - 1));
}
struct chunk *_new_chunk(struct pool *p, size_t s)
{
struct chunk *c;
if (p->spare_chunk &&
((p->spare_chunk->end - (char *) p->spare_chunk) >= s)) {
/* reuse old chunk */
c = p->spare_chunk;
p->spare_chunk = 0;
} else {
c = dbg_malloc(s);
c->end = (char *) c + s;
}
c->prev = p->chunk;
c->begin = (char *) (c + 1);
p->chunk = c;
return c;
}
/*
* Local variables:
* c-file-style: "linux"
* End:
* vim:ai cin ts=8
*/

64
lib/mm/pool.h Normal file
View File

@ -0,0 +1,64 @@
/*
* tools/lib/pool.h
*
* Copyright (C) 2001 Sistina Software
*
* LVM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* LVM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LVM; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef POOL_H
#define POOL_H
#include <stdlib.h>
struct pool;
/* constructor and destructor */
struct pool *create_pool(size_t chunk_hint);
void destroy_pool(struct pool *p);
/* simple allocation/free routines */
void *pool_alloc(struct pool *p, size_t s);
void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment);
void pool_free(struct pool *p, void *ptr);
/* object building routines */
void *pool_begin_object(struct pool *p, size_t hint, unsigned align);
void *pool_grow_object(struct pool *p, unsigned char *buffer, size_t n);
void *pool_end_object(struct pool *p);
void pool_abandon_object(struct pool *p);
/* utilities */
char *pool_strdup(struct pool *p, const char *str);
static inline void *pool_zalloc(struct pool *p, size_t s) {
void *ptr = pool_alloc(p, s);
if (ptr)
memset(ptr, 0, s);
return ptr;
}
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
* vim:ai cin ts=4
*/