blob: 145745ae268493f9ea1ec61e6ac8f7fe28575998 [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 <time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/dir.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. */
/*----------------------------------------------------------------------*/
u_int
idx_insert_newentry( int fd, /* kept locked EX by caller */
int *stobjfd, /* OUT */
invt_entry_t *iarr, invt_counter_t *icnt,
time32_t tm )
{
u_int 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 */
/* */
/* */
/*----------------------------------------------------------------------*/
intgen_t
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 */
u_int 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 */
/* */
/* */
/*----------------------------------------------------------------------*/
intgen_t
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 */
/* */
/* */
/*----------------------------------------------------------------------*/
intgen_t
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_SEEKCUR( fd, &ent, sizeof( invt_entry_t ),
-(off64_t)(sizeof( invt_entry_t )));
#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, (u_int) 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.
*/
/*----------------------------------------------------------------------*/
/* */
/* */
/* */
/*----------------------------------------------------------------------*/
intgen_t
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;
}
intgen_t
idx_DEBUG_printinvindices( invt_entry_t *iarr, u_int num )
{
u_int i;
u_int 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;
}
intgen_t
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, (u_int) nindices );
free( iarr );
free( icnt );
return 1;
}
intgen_t
DEBUG_displayallsessions( int fd, invt_seshdr_t *hdr, u_int 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;
}