blob: b5e01223caa25d99cfe7ecc2352a64c6def379c8 [file] [log] [blame]
/*
* Copyright (c) 2000-2001 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program 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.
*
* This program is distributed in the hope that it would 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 this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <xfs/xfs.h>
#include <xfs/jdm.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <assert.h>
#include <string.h>
#include "config.h"
#include "types.h"
#include "mlog.h"
#include "inv_priv.h"
/*----------------------------------------------------------------------*/
/* insert_invindexentry */
/* */
/* given a time, find the invindex that has the time-period it can fit */
/* into. */
/*----------------------------------------------------------------------*/
uint
idx_insert_newentry(int fd, /* kept locked EX by caller */
int *stobjfd, /* OUT */
invt_entry_t *iarr, invt_counter_t *icnt,
time32_t tm)
{
uint i;
inv_oflag_t forwhat = INV_SEARCH_N_MOD;
/* invt_entry_t ient;
ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = tm; */
/* If time period of the new entry is before our first invindex,
we have to insert a new invindex in the first slot */
if (iarr[0].ie_timeperiod.tp_start > tm) {
/* *stobjfd = idx_put_newentry(fd, 0, iarr, icnt, &ient); */
*stobjfd = open(iarr[0].ie_filename, INV_OFLAG(forwhat));
return 0;
}
for (i = 0; i < icnt->ic_curnum; i++) {
/* if our time is nicely within an existing entry's time
period, hellalujah */
if (IS_WITHIN(&iarr[i].ie_timeperiod, tm)) {
#ifdef INVT_DEBUG
mlog(MLOG_DEBUG | MLOG_INV, "INV: is_within %d\n", i);
#endif
*stobjfd = open(iarr[i].ie_filename, INV_OFLAG(forwhat));
return i;
}
if (iarr[i].ie_timeperiod.tp_end == 0 &&
iarr[i].ie_timeperiod.tp_start == 0) {
#ifdef INVT_DEBUG
mlog(MLOG_DEBUG | MLOG_INV, "INV: end = start \n");
mlog(MLOG_DEBUG | MLOG_INV,"BEF: st %ld end %ld\n",
iarr[i].ie_timeperiod.tp_start,
iarr[i].ie_timeperiod.tp_end);
#endif
iarr[i].ie_timeperiod.tp_start =
iarr[i].ie_timeperiod.tp_end = tm;
PUT_REC_NOLOCK(fd, iarr,
icnt->ic_curnum * sizeof(invt_entry_t),
(off64_t) sizeof(invt_counter_t));
#ifdef INVT_DEBUG
mlog(MLOG_DEBUG | MLOG_INV,"AFT: st %ld end %ld\n",
iarr[i].ie_timeperiod.tp_start,
iarr[i].ie_timeperiod.tp_end);
#endif
*stobjfd = open(iarr[i].ie_filename, INV_OFLAG(forwhat));
return i;
}
/* if it is beyond the end of this timeperiod, see if we
belong to a timeperiod that doesn't have an entry */
if (iarr[i].ie_timeperiod.tp_end < tm) {
/* see if we're the last entry here */
if (i == icnt->ic_curnum - 1) {
/* our slot is (i+1)th entry. Make the
timeperiod's the same as it was. As far
as I can see there is no way that
timeperiods can overlap.
insert the new entry and write back
icnt and invindex entry */
/* *stobjfd = idx_put_newentry(fd, i+1, iarr,
icnt, &ient); */
*stobjfd = open(iarr[i].ie_filename, INV_OFLAG(forwhat));
return i;
}
/* see if the next entry starts later than us */
if (iarr[i+1].ie_timeperiod.tp_start > tm) {
/* We have the option of pushing entries
after (i) forward by one slot, and
taking the (i+1)th slot, OR just hooking
up with the next entry.
We choose the former. */
/* the timeperiods had better not overlap */
assert((tm > iarr[i].ie_timeperiod.tp_end) &&
(tm < iarr[i+1].ie_timeperiod.tp_start));
/* shift everything from (i+1) onwards by
one. Then insert the new entry and write
back icnt and invindex entries */
/* *stobjfd = idx_put_newentry(fd, i+1, iarr,
icnt, &ient); */
*stobjfd = open(iarr[i].ie_filename, INV_OFLAG(forwhat));
return i;
}
}
}
/* We couldnt find anything that fits */
assert(0); /* We can't get here ! */
return -1;
}
/*----------------------------------------------------------------------*/
/* idx_put_newentry */
/* */
/* */
/*----------------------------------------------------------------------*/
int
idx_put_newentry(
invt_idxinfo_t *idx,
invt_entry_t *ient)
{
invt_entry_t *idxarr;
int stobjfd;
int fd = idx->invfd; /* kept locked EX by caller */
uint index = idx->index + 1;
invt_entry_t *iarr = idx->iarr;
invt_counter_t *icnt = idx->icnt;
stobj_makefname(ient->ie_filename);
if ((stobjfd = stobj_create(ient->ie_filename)) < 0)
return -1;
icnt->ic_curnum++; /* there is no maximum */
idxarr = (invt_entry_t *) calloc (icnt->ic_curnum,
sizeof(invt_entry_t));
memcpy(idxarr, iarr, (size_t) (sizeof(invt_entry_t) * index));
/* shift everything from (i+1) onwards by one */
if (index < icnt->ic_curnum - 1)
memcpy(&idxarr[index + 1], &iarr[index],
(size_t) ((icnt->ic_curnum - index - 1) *
sizeof(invt_entry_t)));
/* insert the new entry */
memcpy(&idxarr[index], ient, sizeof(invt_entry_t));
if ((PUT_COUNTERS(fd, icnt) < 0) ||
(PUT_REC_NOLOCK(fd, idxarr,
icnt->ic_curnum * sizeof(invt_entry_t),
sizeof(invt_counter_t)) < 0)) {
/* XXX delete the stobj that we just created */
memset(ient->ie_filename, 0, INV_STRLEN);
free(idxarr);
return -1;
}
free(iarr);
idx->iarr = idxarr;
return stobjfd;
}
/*----------------------------------------------------------------------*/
/* idx_find_stobj */
/* */
/* */
/*----------------------------------------------------------------------*/
int
idx_find_stobj(invt_idxinfo_t *idx,
time32_t tm)
{
int stobjfd;
/* since sessions can be inserted in random order, the invindex
table can contain time-periods that don't have corresponding
entries for */
if (GET_ALLHDRS_N_CNTS_NOLOCK(idx->invfd, (void **)&idx->iarr,
(void **)&idx->icnt,
sizeof(invt_entry_t),
sizeof(invt_counter_t)) < 0) {
return -1;
}
#ifdef INVT_DEBUG
printf("idx_find_stobj Time: %ld\n", tm);
idx_DEBUG_printinvindices(idx->iarr, idx->icnt->ic_curnum);
#endif
/* Now figure out where we are going to insert this stobj among the
invindices and put it there */
idx->index = idx_insert_newentry(idx->invfd, &stobjfd, idx->iarr,
idx->icnt, tm);
return stobjfd;
}
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
inv_idbtoken_t
idx_create(char *fname, inv_oflag_t forwhat)
{
int stobjfd, fd;
inv_idbtoken_t tok;
/* This is not to be called when the user wants to open
the db for SEARCH_ONLY. */
assert(forwhat != INV_SEARCH_ONLY);
if ((fd = open (fname, INV_OFLAG(forwhat) | O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
INV_PERROR (fname);
return INV_TOKEN_NULL;
}
INVLOCK(fd, LOCK_EX);
fchmod(fd, INV_PERMS);
#ifdef INVT_DEBUG
mlog(MLOG_NITTY | MLOG_INV, "creating InvIndex %s\n", fname);
#endif
/* create the first entry in the new inv_index */
stobjfd = idx_create_entry(&tok, fd, BOOL_TRUE);
INVLOCK(fd, LOCK_UN);
if (stobjfd < 0)
return INV_TOKEN_NULL;
return tok;
}
/*----------------------------------------------------------------------*/
/* idx_recons_time */
/* */
/* */
/*----------------------------------------------------------------------*/
int
idx_recons_time(time32_t tm, invt_idxinfo_t *idx)
{
invt_timeperiod_t *tp = &idx->iarr[idx->index].ie_timeperiod;
if (tp->tp_start && IS_WITHIN(tp, tm))
return 1;
if (tm > tp->tp_end || tp->tp_end == 0)
tp->tp_end = tm;
if (tm < tp->tp_start || tp->tp_start == 0)
tp->tp_start = tm;
PUT_REC_NOLOCK(idx->invfd, &idx->iarr[idx->index],
sizeof(invt_entry_t), IDX_HDR_OFFSET(idx->index));
return 1;
}
/*----------------------------------------------------------------------*/
/* put_sesstime */
/* */
/* */
/*----------------------------------------------------------------------*/
int
idx_put_sesstime(inv_sestoken_t tok, bool_t whichtime)
{
int rval;
invt_entry_t ent;
int fd = tok->sd_invtok->d_invindex_fd;
INVLOCK(fd, LOCK_EX);
rval = GET_REC_NOLOCK(fd, &ent, sizeof(invt_entry_t),
tok->sd_invtok->d_invindex_off);
if (rval < 0) {
INVLOCK(fd, LOCK_UN);
return -1;
}
ent.ie_timeperiod.tp_end = tok->sd_sesstime;
if (whichtime == INVT_STARTTIME || ent.ie_timeperiod.tp_start == 0) {
ent.ie_timeperiod.tp_start = tok->sd_sesstime;
}
#ifdef INVT_DEBUG
mlog(MLOG_DEBUG | MLOG_INV,"Putsestime: st %ld end %ld\n",
ent.ie_timeperiod.tp_start,
ent.ie_timeperiod.tp_end);
#endif
rval = PUT_REC_NOLOCK(fd, &ent, sizeof(invt_entry_t),
tok->sd_invtok->d_invindex_off);
#ifdef INVT_DEBUG
{
int nindices;
invt_entry_t *iarr = NULL;
invt_counter_t *icnt = NULL;
if ((nindices = GET_ALLHDRS_N_CNTS_NOLOCK(fd,
(void **)&iarr,
(void **)&icnt,
sizeof(invt_entry_t),
sizeof(invt_counter_t))) < 0) {
return -1;
}
idx_DEBUG_printinvindices(iarr, (uint) nindices);
free(iarr);
free(icnt);
}
#endif
INVLOCK(fd, LOCK_UN);
return rval;
}
/* an inventory index entry keeps track of a single storage object;
it knows about its name (ie filename) and the timeperiod that the
it contains dump sessions for.
note that each file system has its own (set of) inventory indices.
*/
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
int
idx_create_entry(
inv_idbtoken_t *tok,
int invfd, /* kept locked EX by caller */
bool_t firstentry)
{
invt_entry_t ent;
int fd;
off64_t hoff;
memset (&ent, 0, sizeof(ent));
/* initialize the start and end times to be the same */
ent.ie_timeperiod.tp_start = ent.ie_timeperiod.tp_end = (time32_t)0;
stobj_makefname(ent.ie_filename);
if (firstentry) {
invt_counter_t cnt;
cnt.ic_maxnum = INVT_MAX_INVINDICES;
cnt.ic_curnum = 1;
cnt.ic_vernum = INV_VERSION;
fd = stobj_create(ent.ie_filename);
if (fd < 0) {
return -1;
}
if (PUT_REC_NOLOCK(invfd, &cnt, sizeof(cnt), (off64_t)0) < 0)
return -1;
hoff = sizeof(invt_counter_t);
if (PUT_REC_NOLOCK(invfd, &ent, sizeof(ent), hoff) < 0)
return -1;
} else {
invt_counter_t *cnt = NULL;
if (GET_COUNTERS(invfd, &cnt) < 0) {
return -1;
}
/* XXX check if there are too many indices. if so, create
another and leave a pointer to that in here */
/* create the new storage object */
fd = stobj_create(ent.ie_filename);
if (fd < 0) {
return -1;
}
++(cnt->ic_curnum);
if (PUT_COUNTERS(invfd, cnt) < 0) {
return -1;
}
/* add the new index entry to the array, at the end */
hoff = IDX_HDR_OFFSET(cnt->ic_curnum - 1);
free (cnt);
#ifdef INVT_DEBUG
mlog(MLOG_NITTY | MLOG_INV, "new stobj name %s @ offset %d\n",
ent.ie_filename,(int)hoff);
#endif
if (PUT_REC_NOLOCK(invfd, &ent, sizeof(ent), hoff) < 0)
return -1;
}
*tok = get_token(invfd, fd);
(*tok)->d_invindex_off = hoff;
(*tok)->d_update_flag |= NEW_INVINDEX;
(*tok)->d_oflag = INV_SEARCH_N_MOD;
return fd;
}
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
int
idx_get_stobj(int invfd, inv_oflag_t forwhat, int *index)
{
invt_entry_t *ent = 0;
int fd;
/* if there's space anywhere at all, then it must be in the last
entry. get_lastheader() does the locking */
if ((*index = get_lastheader(invfd, (void **)&ent,
sizeof(invt_entry_t),
sizeof(invt_counter_t))) < 0)
return -1;
/* at this point we know that there should be at least one invindex
entry present */
assert (ent != NULL);
assert (ent->ie_filename);
fd = open(ent->ie_filename, INV_OFLAG(forwhat));
if (fd < 0)
INV_PERROR(ent->ie_filename);
free (ent);
return fd;
}
int
idx_DEBUG_printinvindices(invt_entry_t *iarr, uint num)
{
uint i;
uint k;
char s[9];
printf("\n ==================================\n"
" InvIndex\n # StObjs\t%d\n", num);
#define INV_UUID_STR_LEN 36 /* not exported via uuid.h */
for (i = 0; i < num; i++) {
k = strlen(iarr[i].ie_filename);
strncpy(s, (char *) iarr[i].ie_filename + k -
(INV_UUID_STR_LEN + strlen(INV_STOBJ_PREFIX)), 8);
s[8]= 0;
printf("%d. %s \t( %d - %d )\n", i, s,
iarr[i].ie_timeperiod.tp_start,
iarr[i].ie_timeperiod.tp_end);
}
#undef INV_UUID_STR_LEN
printf("\n ==================================\n");
return 1;
}
int
idx_DEBUG_print (int fd)
{
int nindices;
invt_entry_t *iarr = NULL;
invt_counter_t *icnt = NULL;
if ((nindices = GET_ALLHDRS_N_CNTS_NOLOCK(fd,
(void **)&iarr,
(void **)&icnt,
sizeof(invt_entry_t),
sizeof(invt_counter_t))) < 0) {
return -1;
}
idx_DEBUG_printinvindices(iarr, (uint) nindices);
free(iarr);
free(icnt);
return 1;
}
int
DEBUG_displayallsessions(int fd, invt_seshdr_t *hdr, uint ref,
invt_pr_ctx_t *prctx)
{
inv_session_t *ses;
if (stobj_make_invsess(fd, &ses, hdr) < 1)
return -1;
DEBUG_sessionprint(ses, ref, prctx);
free(ses->s_streams);
free(ses);
return 0;
}