[BACK]Return to xfs_behavior.c CVS log [TXT][DIR] Up to [Development] / xfs-linux

File: [Development] / xfs-linux / Attic / xfs_behavior.c (download)

Revision 1.6, Thu Jun 8 23:59:59 2000 UTC (17 years, 4 months ago) by lord
Branch: MAIN
Changes since 1.5: +1 -2 lines

Bring XFS upto 2.3.42
Merge of 2.3.99pre2-xfs:slinx:43458a by ananth.

  Merge of 2.3.42-xfs:slinx:43458a by ananth.

/**************************************************************************
 *									  *
 * Copyright (C) 1999 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; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will 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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 *									  *
 **************************************************************************/
#ident "$Id$"

/*
 * Source file used to associate/disassociate behaviors with virtualized 
 * objects.  See ksys/behavior.h for more information about behaviors, etc.
 *
 * The implementation is split between functions in this file and macros
 * in behavior.h.
 */
#if defined(__linux__)
#include <xfs_linux.h>
#endif

#define	_KERNEL	1

#include <sys/types.h>
#include <ksys/behavior.h>
#include <sys/errno.h>
#include <sys/kmem.h>
#include <ksys/kern_heap.h>
#include <sys/debug.h>

#include "xfs_sim.h"

zone_t	*bhv_global_zone;

/*
 * Global initialization function called out of main.
 */
void
bhv_global_init(void)
{
	/*
	 * Initialize a behavior zone used by subsystems using behaviors 
         * but without any private data.  In the UNIKERNEL case, this zone 
         * is used only for behaviors that are not yet isolated to a single 
         * cell.  The only such user is in pshm.c in which a dummy vnode is 
         * obtained in support of vce avoidance logic.
	 */
	bhv_global_zone = kmem_zone_init(sizeof(bhv_desc_t), "bhv_global_zone");
}

/*
 * Insert a new behavior descriptor into a behavior chain.  The act of
 * modifying the chain is done atomically w.r.t. ops-in-progress
 * (see comment at top of behavior.h for more info on synchronization).
 *
 * If BHV_SYNCH is defined, then must be called with the behavior chain 
 * write locked.  This both synchronizes with ops-in-progress as well
 * as multiple concurrent threads inserting.
 *
 * If BHV_SYNCH is not defined, then it's the callers' responsibility
 * to synchronize appropriately.  Imon, for instance, relies on the
 * atomic nature of insertion to synchronize with ops-in-progress, and
 * implements its own lock to synchronize multiple concurrent threads
 * inserting.
 *
 * The behavior chain is ordered based on the 'position' number which
 * lives in the first field of the ops vector (higher numbers first).
 *
 * Attemps to insert duplicate ops result in an EINVAL return code.
 * Otherwise, return 0 to indicate success.
 */
int 
bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp)
{
	bhv_desc_t 	*curdesc, *prev;
	int		position;

	ASSERT(bdp->bd_next == NULL);
	ASSERT(BHV_IS_WRITE_LOCKED(bhp));

	/*
	 * Validate the position value of the new behavior.
	 */
	position = BHV_POSITION(bdp);
	ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP);

	/* 
	 * Find location to insert behavior.  Check for duplicates.
	 */
	prev = NULL;
	for (curdesc = bhp->bh_first;  
	     curdesc != NULL;
	     curdesc = curdesc->bd_next) {

		/* Check for duplication. */
		if (curdesc->bd_ops == bdp->bd_ops)
			return EINVAL;

		/* Find correct position */
		if (position >= BHV_POSITION(curdesc)) {
			ASSERT(position != BHV_POSITION(curdesc));
			break;		/* found it */
		}

		prev = curdesc;
	} 

	if (prev == NULL) {
		/* insert at front of chain */
		bdp->bd_next = bhp->bh_first;
		bhp->bh_first = bdp;		/* atomic wrt oip's */
	} else {
		/* insert after prev */
		bdp->bd_next = prev->bd_next;
		prev->bd_next = bdp;		/* atomic wrt oip's */
	}

	return 0;
}

/*
 * Remove a behavior descriptor from a position in a behavior chain;
 * the postition is guaranteed not to be the first position.  
 * Should only be called by the bhv_remove() macro.
 *
 * The act of modifying the chain is done atomically w.r.t. ops-in-progress
 * (see comment at top of behavior.h for more info on synchronization).
 */
void 
bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
{
	bhv_desc_t 	*curdesc, *prev;

	ASSERT(bhp->bh_first != NULL);
	ASSERT(bhp->bh_first->bd_next != NULL);

	prev = bhp->bh_first;
	for (curdesc = bhp->bh_first->bd_next;  
	     curdesc != NULL;
	     curdesc = curdesc->bd_next) {

		if (curdesc == bdp)
			break;		/* found it */
		prev = curdesc;
	}

	ASSERT(curdesc == bdp);
	prev->bd_next = bdp->bd_next;	/* remove from after prev */
	                                /* atomic wrt oip's */
}

/* 
 * Look for a specific ops vector on the specified behavior chain.
 * Return the associated behavior descriptor.  Or NULL, if not found.
 */
bhv_desc_t *
bhv_lookup(bhv_head_t *bhp, void *ops)
{
	bhv_desc_t	*curdesc;

	for (curdesc = bhp->bh_first;  
	     curdesc != NULL;
	     curdesc = curdesc->bd_next) {

		if (curdesc->bd_ops == ops)
			return curdesc;
	}

	return NULL;
}

/* 
 * Look for a specific ops vector on the specified behavior chain.
 * Return the associated behavior descriptor.  Or NULL, if not found.
 * 
 * The caller has not read locked the behavior chain, so acquire the 
 * lock before traversing the chain.
 */
bhv_desc_t *
bhv_lookup_unlocked(bhv_head_t *bhp, void *ops)
{
	bhv_desc_t	*bdp;

	BHV_READ_LOCK(bhp);
	bdp = bhv_lookup(bhp, ops);
	BHV_READ_UNLOCK(bhp);

	return bdp;
}

/* 
 * Return the base behavior in the chain, or NULL if the chain
 * is empty.  
 * 
 * The caller has not read locked the behavior chain, so acquire the 
 * lock before traversing the chain.
 */
bhv_desc_t *
bhv_base_unlocked(bhv_head_t *bhp)
{
	bhv_desc_t	*curdesc;

	BHV_READ_LOCK(bhp);
	for (curdesc = bhp->bh_first;  
	     curdesc != NULL;
	     curdesc = curdesc->bd_next) {

		if (curdesc->bd_next == NULL) {
			BHV_READ_UNLOCK(bhp);
			return curdesc;
		}
	}

	BHV_READ_UNLOCK(bhp);
	return NULL;
}

#define BHVMAGIC 0xf00d

/* ARGSUSED */
void
bhv_head_init(
        bhv_head_t *bhp,
        char *name)
{
        bhp->bh_first = NULL;
#if defined(CELL_ENABLED)
        bhp->bh_lockp = BHVMAGIC;
#endif
}


/* ARGSUSED */
void
bhv_head_reinit(
        bhv_head_t *bhp)
{
        ASSERT(bhp->bh_first == NULL);
#if defined(CELL_ENABLED)
        ASSERT(bhp->bh_lockp == BHVMAGIC);
#endif
}


void
bhv_insert_initial(
        bhv_head_t *bhp,
        bhv_desc_t *bdp)
{
        ASSERT(bhp->bh_first == NULL);
#if defined(CELL_ENABLED)
        ASSERT(bhp->bh_lockp == BHVMAGIC);
#endif
        (bhp)->bh_first = bdp;
}

void
bhv_head_destroy(
	bhv_head_t *bhp)
{
	ASSERT(bhp->bh_first == NULL);
#if defined(CELL_CAPABLE)
	ASSERT(bhp->bh_lockp == BHVMAGIC);
	bhp->bh_lockp = NULL;
#endif
}