blob: 183b8c0d5edb1161beb2834db60c3c434eadc006 [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 <assert.h>
#include "config.h"
#include "inv_priv.h"
#include "inv_oref.h"
/*
* Resolve a stobj, invidx or fstab
*/
int
oref_resolve_(
invt_oref_t *obj,
invt_objtype_t type)
{
int rval;
type &= INVT_OTYPE_MASK;
assert(type);
assert(!OREF_ISRESOLVED(obj, INVT_OTYPE_MASK));
switch (type) {
case INVT_OTYPE_INVIDX:
rval = oref_resolve_invidx(obj);
break;
case INVT_OTYPE_STOBJ:
rval = oref_resolve_stobj(obj);
break;
case INVT_OTYPE_FSTAB:
rval = oref_resolve_fstab(obj);
break;
default:
assert(0);
break;
}
return rval;
}
/*
* Resolve an object reference upto a specified point
*/
int
oref_resolve_upto(
invt_oref_t *obj,
invt_objtype_t type)
{
int rval = INV_OK;
assert (OREF_ISRESOLVED(obj, INVT_OTYPE_MASK));
assert (OREF_ISLOCKED(obj));
/* we arent interested in anything else */
type &= INVT_RES_MASK;
assert(type);
if (type >= INVT_RES_COUNTERS) {
rval = oref_resolve_counters(obj);
}
if (type >= INVT_RES_ENTRIES && rval != INV_ERR) {
rval = oref_resolve_entries(obj);
}
if (type >= INVT_RES_HDRS && rval != INV_ERR) {
rval = oref_resolve_hdrs(obj);
}
if (type >= INVT_RES_SESSIONS && rval != INV_ERR) {
rval = oref_resolve_sessions(obj);
}
if (type >= INVT_RES_STRMS && rval != INV_ERR) {
rval = oref_resolve_strms(obj);
}
if (type >= INVT_RES_MFILES && rval != INV_ERR) {
rval = oref_resolve_mfiles(obj);
}
return rval;
}
int
oref_resolve_entries(
invt_oref_t *obj)
{
if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES))
return INV_OK;
assert(!OREF_ISRESOLVED(INVT_OTYPE_STOBJ));
if (OREF_ISRESOLVED(INVT_OTYPE_INVIDX)) {
invt_entry_t *ent;
assert(OREF_CNT_CURNUM(obj));
if (GET_ENTRIES(obj->fd, &ent, OREF_CNT_CURNUM(obj),
sizeof(invt_entry_t)) < 0){
return INV_ERR;
}
obj->eu_ent = ent;
}
else {
invt_fstab_t *ent;
assert(OREF_CNT_CURNUM(obj));
if (GET_ENTRIES(obj->fd, &ent, OREF_CNT_CURNUM(obj),
sizeof(invt_fstab_t)) < 0){
return INV_ERR;
}
obj->eu_fstabent = ent;
}
OREF_SET_TYPE(obj, INVT_RES_COUNTERS);
return INV_OK;
}
int
oref_resolve_counters(
invt_oref_t *obj)
{
if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS))
return INV_OK;
if (OREF_ISRESOLVED(INVT_OTYPE_STOBJ)) {
invt_sescounter_t *sescnt;
sescnt = calloc(1, sizeof(invt_sescounter_t));
if (GET_SESCOUNTERS(obj->fd, sescnt) < 0){
free(sescnt);
return INV_ERR;
}
obj->cu_sescnt = sescnt;
}
else {
invt_counter_t *cnt;
cnt = calloc(1, sizeof(invt_counter_t));
if (GET_COUNTERS(obj->fd, cnt) < 0){
free(cnt);
return INV_ERR;
}
obj->cu_cnt = cnt;
}
OREF_SET_TYPE(obj, INVT_RES_COUNTERS);
return INV_OK;
}
int
oref_sync(
invt_oref_t *obj,
invt_objtype_t type)
{
int rval;
type &= INVT_RES_MASK;
assert(type);
assert(OREF_ISRESOLVED(obj, INVT_OTYPE_MASK));
assert(OREF_ISRESOLVED(obj, type));
assert(OREF_ISLOCKED(obj));
switch (type) {
case INVT_RES_COUNTERS:
rval = PUT_REC_NOLOCK(obj->fd,
OREF_CNT(obj),
sizeof(*OREF_CNT(obj)),
(off64_t) 0);
break;
case INVT_RES_ENTRIES:
assert(!OREF_ISRESOLVED(obj, INVT_OTYPE_STOBJ));
rval = PUT_REC_NOLOCK(obj->fd,
OREF_ENTRIES(obj),
sizeof(*OREF_ENTRIES(obj)),
(off64_t) sizeof(*OREF_CNT(obj)));
break;
default:
assert(0);
break;
}
return rval;
}
int
oref_sync_append(
invt_oref_t *obj,
invt_objtype_t type,
void *entry,
size_t entsz)
{
int rval;
type &= INVT_RES_MASK;
assert(type);
assert(OREF_ISRESOLVED(obj, INVT_OTYPE_MASK));
assert(OREF_ISLOCKED(obj));
switch (type) {
case INVT_RES_ENTRIES:
assert(!OREF_ISRESOLVED(obj, INVT_OTYPE_STOBJ));
rval = PUT_REC_NOLOCK(obj->fd,
entry,
entsz,
IDX_HDR_OFFSET(OREF_CNT_CURNUM(obj) - 1));
if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES))
free((oref)->eu_ent);
OREF_UNSET_TYPE(obj, INVT_RES_ENTRIES);
break;
default:
assert(0);
break;
}
return rval;
}
void
_oref_free(
invt_oref_t *obj,
bool_t freethis)
{
/*
* Unlock the object *if* it is locked.
* We dont want to actually close the fd because,
* the tokens still need it.
*/
OREF_UNLOCK(obj);
if (OREF_ISRESOLVED(obj, INVT_OTYPE_STOBJ)){
if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS))
free((oref)->cu_sescnt);
if (OREF_ISRESOLVED(obj, INVT_RES_HDRS))
free((oref)->eu_hdr);
if (OREF_ISRESOLVED(obj, INVT_RES_SESSIONS))
free((oref)->eu_ses);
if (OREF_ISRESOLVED(obj, INVT_RES_STRMS))
free((oref)->eu_strm);
if (OREF_ISRESOLVED(obj, INVT_RES_MFILES))
free((oref)->eu_mfile);
}
else if (OREF_ISRESOLVED(obj, INVT_OTYPE_INVIDX)) {
if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS))
free((oref)->cu_cnt);
if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES))
free((oref)->eu_ent);
}
else if (OREF_ISRESOLVED(obj, INVT_OTYPE_FSTAB)) {
if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS))
free((oref)->cu_cnt);
if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES))
free((oref)->eu_fstabent);
}
OREF_INIT(obj);
if (freethis)
free(obj);
}
/*
* Resolve the invidx and a suitable stobj.
* Also resolves an idb_token as a side effect.
*/
int
oref_resolve(
invt_oref_t *invidx,
inv_predicate_t bywhat,
void *pred)
{
char fname[INV_STRLEN];
char uuname[INV_STRLEN];
int fd;
invt_oref_t *stobj;
int index;
assert(!OREF_ISRESOLVED(invidx, INVT_OTYPE_MASK));
OREF_SET_TYPE(invidx, INVT_OTYPE_INVIDX);
/* come up with the unique file suffix that refers to this
filesystem */
if (fstab_get_fname(pred, uuname, bywhat) < 0) {
return INV_ERR;
}
(void) strcpy(fname, uuname);
strcat(fname, INV_INVINDEX_PREFIX);
/* first check if the inv_index file exists: if not create it */
if ((fd = open(fname, O_RDWR)) == -1) {
if (errno != ENOENT) {
INV_PERROR (fname);
return INV_ERR;
}
/* create the invidx */
return oref_resolve_new_invidx(invidx, fname);
}
invidx->fd = fd;
OREF_LOCK(invidx, LOCK_EX);
if (oref_resolve_child(invidx, &index) == INV_ERR) {
OREF_UNLOCK(invidx);
return INV_ERR;
}
stobj = OREF_CHILD(invidx);
/* Now we need to make sure that this has enough space */
OREF_LOCK(stobj, LOCK_SH);
if (oref_resolve_upto(stobj, INVT_RES_COUNTERS) == INV_ERR) {
OREF_UNLOCK(stobj);
OREF_UNLOCK(invidx);
return INV_ERR;
}
/* create another storage object (and, an inv_index entry for it
too) if we've filled this one up */
if (OREF_CNT_CURNUM(stobj) >= OREF_CNT_MAXNUM(stobj)) {
int rval;
#ifdef INVT_DEBUG
mlog(MLOG_DEBUG | MLOG_INV, "$ INV: creating a new storage obj & "
"index entry. \n");
#endif
/* Close(), Destroy() and mark unresolved */
OREF_UNRESOLVE_CHILD(invidx);
rval = oref_resolve_new_stobj(invidx, BOOL_FALSE);
/* rval = oref_idx_create_entry(invidx, BOOL_FALSE); */
OREF_UNLOCK(invidx);
return rval;
}
OREF_UNLOCK(stobj);
OREF_UNLOCK(invidx);
tok = get_token(invidx->fd, stobj->fd);
tok->d_invindex_off = IDX_HDR_OFFSET(index - 1);
OREF_SET_TOKEN(tok);
return INV_OK;
}
/*
* Resolve the invidx entirely, and open the StObj.
* Invidx is kept locked by caller
*/
int
oref_resolve_child(
invt_oref_t *invidx,
int *index)
{
invt_entry_t *ent;
assert(OREF_IS_LOCKED(invidx));
if (oref_resolve_upto(invidx, INVT_RES_ENTRIES) == INV_ERR)
return INV_ERR;
ent = OREF_ENTRIES(invidx);
/* 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, O_RDWR);
if (fd < 0) {
INV_PERROR(ent->ie_filename);
return INV_ERR;
}
stobj = calloc(1, sizeof(invt_oref_t));
OREF_SET_CHILD(invidx, stobj);
stobj->fd = fd;
return INV_OK;
}
/* used to be idx_create */
int
oref_resolve_new_invidx(
invt_oref_t *invidx,
char *fname)
{
int stobjfd, fd;
inv_idbtoken_t tok;
if ((fd = open (fname, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
INV_PERROR (fname);
return INV_ERR;
}
invidx->fd = fd;
OREF_LOCK(invidx, LOCK_EX);
fchmod(fd, INV_PERMS);
#ifdef INVT_DEBUG
mlog(MLOG_NITTY | MLOG_INV, "creating InvIndex %s\n", fname);
#endif
/* create the new stobj as its first entry */
rval = oref_resolve_new_stobj(invidx, IS_EMPTY);
OREF_UNLOCK(invidx);
return rval;
}
/* formerly idx_create_entry() */
int
oref_resolve_new_stobj(
invt_oref_t *invidx,
bool_t firstentry)
{
invt_entry_t ent;
int fd;
off64_t hoff;
invt_oref_t *stobj;
inv_idbtoken_t tok;
assert(OREF_ISLOCKED(invidx));
memset (&ent, 0, sizeof(ent));
stobj = calloc(1, sizeof(invt_oref_t));
OREF_SET_CHILD(invidx, stobj);
/* 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 = malloc(sizeof(invt_counter_t));
cnt->ic_maxnum = INVT_MAX_INVINDICES;
cnt->ic_curnum = 1;
cnt->ic_vernum = INV_VERSION;
fd = stobj_create(ent.ie_filename);
if (fd < 0) {
free(cnt);
return INV_ERR;
}
stobj->fd = fd;
OREF_SET_COUNTERS(invidx, cnt);
OREF_SET_ENTRIES(invidx, &ent);
if ((oref_sync(invidx, INVT_RES_COUNTERS) == INV_ERR)
||
(oref_sync(invidx, INVT_RES_ENTRIES) == INV_ERR))
return INV_ERR;
}
else {
if (oref_resolve_upto(invidx, INVT_RES_COUNTERS) == INV_ERR)
return INV_ERR;
/* create the new storage object */
fd = stobj_create(ent.ie_filename);
if (fd < 0) {
return -1;
}
stobj->fd = fd;
OREF_CNT_CURNUM(invidx)++;
if ((oref_sync(invidx, INVT_RES_COUNTERS) == INV_ERR)
||
(oref_sync_append(invidx, INVT_RES_ENTRIES,
&ent, sizeof(ent)) == INV_ERR))
return INV_ERR;
}
tok = get_token(invfd, fd);
tok->d_invindex_off = IDX_HDR_OFFSET(OREF_CNT_CURNUM(invidx) - 1);
tok->d_update_flag |= NEW_INVINDEX;
OREF_SET_TOKEN(invidx, tok);
return INV_OK;
}