Commit b31ddc86 authored by Siddharth Aggarwal's avatar Siddharth Aggarwal
Browse files

Initial checkin of disk checkpointing code. Trie merge doesn't work correctly yet

parent 97f3da16
# $FreeBSD: src/sbin/shdconfig/Makefile,v 1.2.10.1 2001/04/25 10:58:12 ru Exp $
PROG= shdconfig
SRCS= shdconfig.c trie.c
CFLAGS+= -I${.CURDIR}/../../sys -g
LDADD+= -lkvm
DPADD+= ${LIBKVM}
BINGRP= kmem
BINMODE= 2555
.include <bsd.prog.mk>
#include "trie.h"
#include "block_alloc.h"
void SetShadowSize (long size)
{
shadow_size = size;
}
void InitBlockAllocator (int method, long range_start, long range_size)
{
reclaim_method = method;
block_range.start = range_start;
block_range.end = range_start + range_size;
block_range.ptr = range_start;
printf ("Initialized block allocator to start = %ld, end = %ld\n", block_range.ptr, block_range.end);
SetShadowSize (range_size);
}
void DeleteCheckpoint (int version)
{
/* dummy function. write code to merge checkpoints */
return;
}
void CopyTree (Trie * trie, long size)
{
/* dummy function. Iterate through the trie and adjust each block
number by "size". Also Copy the blocks to new locations respectively */
if (0 != trie)
{
TrieIterator pos;
}
}
long GetLastBlock ()
{
/* dummy function. Returns the largest block number allocated to
a given checkpoint */
return 0;
}
long CurrentFreeBlockSize ()
{
if (block_range.end < block_range.ptr)
return (block_range.ptr + shadow_size - block_range.end);
else
return (block_range.end - block_range.ptr);
}
int BlockFree (long start, long end)
{
/* called only for EXPLICIT_CKPT_DELETE. Shouldn't be called for
LAST_CKPT_AUTO_DELETE at all */
struct FreeSpaceQueue* temp = head;
while (temp != 0)
{
if (temp->start == (end + 1) % shadow_size)
{
temp->start = start;
return 0;
}
else
if ((temp->end + 1) % shadow_size == start)
{
temp->end = end;
return 0;
}
temp = temp->next;
}
AddFreeSpaceToQueue (start, end);
return 0;
}
long BlockAlloc (int size)
{
struct FreeSpaceQueue* temp = 0;
long retVal;
printf ("\nCalling BlockAlloc\n");
switch (reclaim_method)
{
case LAST_CKPT_AUTO_DELETE:
while (CurrentFreeBlockSize () < size)
{
DeleteCheckpoint (first_checkpoint);
block_range.end = GetLastBlock (first_checkpoint);
/* Delete the corresponding trie and merge changes with
next checkpoint */
first_checkpoint++;
}
break;
case EXPLICIT_CKPT_DELETE:
while (CurrentFreeBlockSize () < size)
{
printf ("size = %d, free_block_size = %d\n", size, CurrentFreeBlockSize());
printf ("end = %ld, ptr = %ld\n", block_range.end, block_range.ptr);
if (-1 == MergeWithNextFreeBlockRange ( CurrentFreeBlockSize() ))
{
printf ("Error! No more free space on disk\n");
return -1;
}
}
break;
}
retVal = block_range.ptr;
block_range.ptr += size;
printf ("Allocating %d blocks starting %d\n", size, retVal);
return retVal;
}
long MergeWithNextFreeBlockRange (long size)
{
int done = 0;
Trie * trie;
struct FreeSpaceQueue* temp = GetNextFreeSpaceFromQueue ();
if (0 == temp)
return -1;
while (1)
{
CopyTree (trie, size);
if ((GetLastBlock() + size) % shadow_size >= temp->start)
{
block_range.start = block_range.ptr = GetLastBlock();
block_range.end = temp->end;
DeleteFreeSpace (temp);
break;
}
}
return (size + temp->end - temp->start);
}
int initFreeSpaceQueue (void)
{
head = tail = 0;
}
int AddFreeSpaceToQueue (long start, long end)
{
struct FreeSpaceQueue* new = malloc (sizeof (struct FreeSpaceQueue), M_DEVBUF, M_NOWAIT);
new->start = start;
new->end = end;
if (0 == head)
head = tail = new;
else
{
new->next = head;
head->prev = new;
head = new;
}
return 0;
}
struct FreeSpaceQueue* GetNextFreeSpaceFromQueue (void)
{
struct FreeSpaceQueue* temp = 0;
if (0 == tail)
return 0;
else
{
temp = tail;
tail = tail->prev;
}
return temp;
}
int PrintFreeSpaceQueue()
{
struct FreeSpaceQueue* current = head;
while (current != 0)
{
printf ("%ld %ld\n", current->start, current->end);
current = current->next;
}
return 0;
}
int DeleteFreeSpace (struct FreeSpaceQueue* temp)
{
if (head == temp)
head = 0;
free (temp, M_DEVBUF);
temp = temp->next = temp->prev = 0;
return 0;
}
int main ()
{
struct FreeSpaceQueue* temp;
AddFreeSpaceToQueue (10, 15);
AddFreeSpaceToQueue (2, 4);
PrintFreeSpaceQueue();
temp = GetNextFreeSpaceFromQueue();
printf ("%d %d\n", temp->start, temp->end);
DeleteFreeSpace (temp);
temp = GetNextFreeSpaceFromQueue();
printf ("%d %d\n", temp->start, temp->end);
DeleteFreeSpace (temp);
PrintFreeSpaceQueue();
return 0;
}
/* Change to correct value */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/namei.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/disklabel.h>
#include <ufs/ffs/fs.h>
#include <sys/devicestat.h>
#include <sys/fcntl.h>
#include <sys/vnode.h>
#define LAST_CKPT_AUTO_DELETE 1
#define EXPLICIT_CKPT_DELETE 2
#define SRC_TO_SHADOW 1
#define SHADOW_TO_SRC 2
int first_checkpoint;
int reclaim_method;
long shadow_size;
struct CurrentFreeBlockRange
{
long start;
long end;
long ptr;
} block_range;
struct FreeSpaceQueue
{
long start;
long end;
struct FreeSpaceQueue *next;
struct FreeSpaceQueue *prev;
} *head, *tail;
void SetShadowSize (long size);
void InitBlockAllocator (int method, long range_start, long range_size);
void DeleteCheckpoint (int version);
void CopyTree (Trie * trie, long size);
long GetLastBlock ();
long CurrentFreeBlockSize ();
int BlockFree (long start, long end);
long BlockAlloc (int size);
long MergeWithNextFreeBlockRange (long size);
int initFreeSpaceQueue (void);
int AddFreeSpaceToQueue (long start, long end);
struct FreeSpaceQueue* GetNextFreeSpaceFromQueue (void);
int PrintFreeSpaceQueue();
int DeleteFreeSpace (struct FreeSpaceQueue* temp);
This diff is collapsed.
#define NSHD 1
#ifndef lint
static const char rcsid[] =
"$FreeBSD: src/sbin/shdconfig/shdconfig.c,v 1.16.2.2 2000/12/11 01:03:25 obrien Exp $";
#endif /* not lint */
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <sys/module.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/devicestat.h>
#include <sys/shdvar.h>
#include "pathnames.h"
#include "trie.h"
#define MAXBUF 65316
#define BLOCKSIZE 512
static int lineno = 0;
static int verbose = 0;
static char *shdconf = _PATH_SHDCONF;
static char *core = NULL;
static char *kernel = NULL;
struct flagval {
char *fv_flag;
int fv_val;
} flagvaltab[] = {
{ "SHDF_ONETOONE", SHDF_ONETOONE },
{ "SHDF_COMPACT", SHDF_COMPACT },
{ "SHDF_COR", SHDF_COR },
{ "SHDF_COW", SHDF_COW },
{ NULL, 0 },
};
static struct nlist nl[] = {
{ "_shd_softc" },
#define SYM_SHDSOFTC 0
{ "_numshd" },
#define SYM_NUMSHD 1
{ NULL },
};
#define SHD_CONFIG 0 /* configure a device */
#define SHD_CONFIGALL 1 /* configure all devices */
#define SHD_UNCONFIG 2 /* unconfigure a device */
#define SHD_UNCONFIGALL 3 /* unconfigure all devices */
#define SHD_DUMP 4 /* dump a shd's configuration */
//#define SHDCHECKPOINT 5575937
static int checkdev __P((char *));
static int do_io __P((char *, u_long, struct shd_ioctl *));
static int do_single __P((int, char **, int, int));
static int do_all __P((int));
static int dump_shd __P((int, char **));
static int getmaxpartitions __P((void));
static int getrawpartition __P((void));
static int flags_to_val __P((char *));
static void print_shd_info __P((struct shd_softc *, kvm_t *));
static char *resolve_shdname __P((char *));
static void usage __P((void));
int save_checkpoint (char * shd, int version);
int
main(argc, argv)
int argc;
char **argv;
{
int ch, options = 0, action = SHD_CONFIG;
int flags = 0;
if (modfind("shd") < 0) {
/* Not present in kernel, try loading it */
if (kldload("shd") < 0 || modfind("shd") < 0)
warn("shd module not available!");
}
exit(do_single(argc, argv, action, flags));
return (0);
}
static int
do_single(argc, argv, action, flags)
int argc;
char **argv;
int action;
int flags;
{
struct shd_ioctl shio;
char *shd, *cp, *cp2, *srcdisk, *copydisk;
int noflags = 0, i, ileave, j;
int version;
bzero(&shio, sizeof(shio));
*argv++; --argc;
/* First argument is the shd to configure. */
cp = *argv++; --argc;
if ((shd = resolve_shdname(cp)) == NULL) {
warnx("invalid shd name: %s", cp);
return (1);
}
/* Next argument is the source disk */
cp = *argv++; --argc;
if ((j = checkdev(cp)) == 0)
srcdisk = cp;
else {
warnx("%s: %s", cp, strerror(j));
return (1);
}
/* Next argument is the 1st copy disk */
cp = *argv++; --argc;
if ((j = checkdev(cp)) == 0)
copydisk = cp;
else {
warnx("%s: %s", cp, strerror(j));
return (1);
}
/* Fill in the shio. */
shio.shio_srcdisk = srcdisk;
shio.shio_copydisk = copydisk;
shio.shio_flags = flags;
cp = *argv++; --argc;
shio.shio_flags |= SHDF_INITIALIZE;
if (strcmp (cp, "-i") == 0)
{
if (do_io(shd, SHDIOCSET, &shio))
return (1);
}
else
if (strcmp (cp, "-c") == 0)
{
if (do_io(shd, SHDCHECKPOINT, &shio))
return (1);
}
else
if (strcmp (cp, "-g") == 0)
{
if (do_io(shd, SHDGETCHECKPOINTS, &shio))
return (1);
}
else
if (strcmp (cp, "-e") == 0)
{
if (do_io(shd, SHDENABLECHECKPOINTING, &shio))
return (1);
}
else
if (strcmp (cp, "-d") == 0)
{
if (do_io(shd, SHDDISABLECHECKPOINTING, &shio))
return (1);
}
else
if (strcmp (cp, "-r") == 0)
{
version = atoi(*argv++); --argc;
printf ("Rolling back to version %d\n", version);
shio.version = version;
if (do_io(shd, SHDROLLBACK, &shio))
return (1);
}
else
if (strcmp (cp, "-s") == 0)
{
version = atoi(*argv++); --argc;
printf ("Saving version %d\n", version);
save_checkpoint (shd, version);
}
else
if (strcmp (cp, "-l") == 0)
{
version = atoi(*argv++); --argc;
printf ("Saving version %d\n", version);
save_checkpoint (shd, version);
}
printf("shd%d: ", shio.shio_unit);
printf("%lu blocks ", (u_long)shio.shio_size);
return (0);
}
static int
do_all(action)
int action;
{
FILE *f;
char line[_POSIX2_LINE_MAX];
char *cp, **argv;
int argc, rval;
gid_t egid;
rval = 0;
egid = getegid();
setegid(getgid());
if ((f = fopen(shdconf, "r")) == NULL) {
setegid(egid);
warn("fopen: %s", shdconf);
return (1);
}
setegid(egid);
while (fgets(line, sizeof(line), f) != NULL) {
argc = 0;
argv = NULL;
++lineno;
if ((cp = strrchr(line, '\n')) != NULL)
*cp = '\0';
/* Break up the line and pass it's contents to do_single(). */
if (line[0] == '\0')
goto end_of_line;
for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
if (*cp == '#')
break;
if ((argv = realloc(argv,
sizeof(char *) * ++argc)) == NULL) {
warnx("no memory to configure shds");
return (1);
}
argv[argc - 1] = cp;
/*
* If our action is to unconfigure all, then pass
* just the first token to do_single() and ignore
* the rest. Since this will be encountered on
* our first pass through the line, the Right
* Thing will happen.
*/
if (action == SHD_UNCONFIGALL) {
if (do_single(argc, argv, action, 0))
rval = 1;
goto end_of_line;
}
}
if (argc != 0)
if (do_single(argc, argv, action, 0))
rval = 1;
end_of_line:
if (argv != NULL)
free(argv);
}
(void)fclose(f);
return (rval);
}
static int
checkdev(path)
char *path;
{
struct stat st;
if (stat(path, &st) != 0)
return (errno);
if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode) &&
!S_ISREG(st.st_mode))
return (EINVAL);
return (0);
}
static int
pathtounit(path, unitp)
char *path;
int *unitp;
{
struct stat st;
int maxpartitions;
if (stat(path, &st) != 0)
return (errno);
if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
return (EINVAL);
if ((maxpartitions = getmaxpartitions()) < 0)
return (errno);
*unitp = minor(st.st_rdev) / maxpartitions;
return (0);
}
static char *
resolve_shdname(name)
char *name;
{
char c, *path;
size_t len, newlen;
int rawpart;
if (name[0] == '/' || name[0] == '.') {
/* Assume they gave the correct pathname. */
return (strdup(name));
}
len = strlen(name);
c = name[len - 1];
newlen = len + 8;
if ((path = malloc(newlen)) == NULL)
return (NULL);
bzero(path, newlen);
if (isdigit(c)) {
if ((rawpart = getrawpartition()) < 0) {
free(path);
return (NULL);
}
(void)sprintf(path, "%s%s%c", _PATH_DEV, name, 'a' + rawpart);
} else
(void)sprintf(path, "%s%s", _PATH_DEV, name);
return (path);
}
static int
do_io(path, cmd, shiop)
char *path;
u_long cmd;
struct shd_ioctl *shiop;
{