| /* |
| * 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; |
| } |
| |