1153323Srodrigc/*
2159451Srodrigc * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3159451Srodrigc * All Rights Reserved.
4153323Srodrigc *
5159451Srodrigc * This program is free software; you can redistribute it and/or
6159451Srodrigc * modify it under the terms of the GNU General Public License as
7153323Srodrigc * published by the Free Software Foundation.
8153323Srodrigc *
9159451Srodrigc * This program is distributed in the hope that it would be useful,
10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of
11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12159451Srodrigc * GNU General Public License for more details.
13153323Srodrigc *
14159451Srodrigc * You should have received a copy of the GNU General Public License
15159451Srodrigc * along with this program; if not, write the Free Software Foundation,
16159451Srodrigc * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17153323Srodrigc */
18153323Srodrigc#include "xfs.h"
19153323Srodrigc
20153323Srodrigc/*
21153323Srodrigc * Source file used to associate/disassociate behaviors with virtualized
22153323Srodrigc * objects.  See xfs_behavior.h for more information about behaviors, etc.
23153323Srodrigc *
24153323Srodrigc * The implementation is split between functions in this file and macros
25153323Srodrigc * in xfs_behavior.h.
26153323Srodrigc */
27153323Srodrigc
28153323Srodrigc/*
29153323Srodrigc * Insert a new behavior descriptor into a behavior chain.
30153323Srodrigc *
31153323Srodrigc * The behavior chain is ordered based on the 'position' number which
32153323Srodrigc * lives in the first field of the ops vector (higher numbers first).
33153323Srodrigc *
34159451Srodrigc * Attempts to insert duplicate ops result in an EINVAL return code.
35153323Srodrigc * Otherwise, return 0 to indicate success.
36153323Srodrigc */
37153323Srodrigcint
38153323Srodrigcbhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp)
39153323Srodrigc{
40153323Srodrigc	bhv_desc_t	*curdesc, *prev;
41153323Srodrigc	int		position;
42153323Srodrigc
43153323Srodrigc	/*
44153323Srodrigc	 * Validate the position value of the new behavior.
45153323Srodrigc	 */
46153323Srodrigc	position = BHV_POSITION(bdp);
47153323Srodrigc	ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP);
48153323Srodrigc
49153323Srodrigc	/*
50153323Srodrigc	 * Find location to insert behavior.  Check for duplicates.
51153323Srodrigc	 */
52153323Srodrigc	prev = NULL;
53153323Srodrigc	for (curdesc = bhp->bh_first;
54153323Srodrigc	     curdesc != NULL;
55153323Srodrigc	     curdesc = curdesc->bd_next) {
56153323Srodrigc
57153323Srodrigc		/* Check for duplication. */
58153323Srodrigc		if (curdesc->bd_ops == bdp->bd_ops) {
59153323Srodrigc			ASSERT(0);
60153323Srodrigc			return EINVAL;
61153323Srodrigc		}
62153323Srodrigc
63153323Srodrigc		/* Find correct position */
64153323Srodrigc		if (position >= BHV_POSITION(curdesc)) {
65153323Srodrigc			ASSERT(position != BHV_POSITION(curdesc));
66153323Srodrigc			break;		/* found it */
67153323Srodrigc		}
68153323Srodrigc
69153323Srodrigc		prev = curdesc;
70153323Srodrigc	}
71153323Srodrigc
72153323Srodrigc	if (prev == NULL) {
73153323Srodrigc		/* insert at front of chain */
74153323Srodrigc		bdp->bd_next = bhp->bh_first;
75153323Srodrigc		bhp->bh_first = bdp;
76153323Srodrigc	} else {
77153323Srodrigc		/* insert after prev */
78153323Srodrigc		bdp->bd_next = prev->bd_next;
79153323Srodrigc		prev->bd_next = bdp;
80153323Srodrigc	}
81153323Srodrigc
82153323Srodrigc	return 0;
83153323Srodrigc}
84153323Srodrigc
85153323Srodrigc/*
86153323Srodrigc * Remove a behavior descriptor from a position in a behavior chain;
87159451Srodrigc * the position is guaranteed not to be the first position.
88153323Srodrigc * Should only be called by the bhv_remove() macro.
89153323Srodrigc */
90153323Srodrigcvoid
91153323Srodrigcbhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
92153323Srodrigc{
93153323Srodrigc	bhv_desc_t	*curdesc, *prev;
94153323Srodrigc
95153323Srodrigc	ASSERT(bhp->bh_first != NULL);
96153323Srodrigc	ASSERT(bhp->bh_first->bd_next != NULL);
97153323Srodrigc
98153323Srodrigc	prev = bhp->bh_first;
99153323Srodrigc	for (curdesc = bhp->bh_first->bd_next;
100153323Srodrigc	     curdesc != NULL;
101153323Srodrigc	     curdesc = curdesc->bd_next) {
102153323Srodrigc
103153323Srodrigc		if (curdesc == bdp)
104153323Srodrigc			break;		/* found it */
105153323Srodrigc		prev = curdesc;
106153323Srodrigc	}
107153323Srodrigc
108153323Srodrigc	ASSERT(curdesc == bdp);
109153323Srodrigc	prev->bd_next = bdp->bd_next;	/* remove from after prev */
110153323Srodrigc}
111153323Srodrigc
112153323Srodrigc/*
113153323Srodrigc * Look for a specific ops vector on the specified behavior chain.
114153323Srodrigc * Return the associated behavior descriptor.  Or NULL, if not found.
115153323Srodrigc */
116153323Srodrigcbhv_desc_t *
117153323Srodrigcbhv_lookup(bhv_head_t *bhp, void *ops)
118153323Srodrigc{
119153323Srodrigc	bhv_desc_t	*curdesc;
120153323Srodrigc
121153323Srodrigc	for (curdesc = bhp->bh_first;
122153323Srodrigc	     curdesc != NULL;
123153323Srodrigc	     curdesc = curdesc->bd_next) {
124153323Srodrigc
125153323Srodrigc		if (curdesc->bd_ops == ops)
126153323Srodrigc			return curdesc;
127153323Srodrigc	}
128153323Srodrigc
129153323Srodrigc	return NULL;
130153323Srodrigc}
131153323Srodrigc
132153323Srodrigc/*
133153323Srodrigc * Looks for the first behavior within a specified range of positions.
134153323Srodrigc * Return the associated behavior descriptor.  Or NULL, if none found.
135153323Srodrigc */
136153323Srodrigcbhv_desc_t *
137153323Srodrigcbhv_lookup_range(bhv_head_t *bhp, int low, int high)
138153323Srodrigc{
139153323Srodrigc	bhv_desc_t	*curdesc;
140153323Srodrigc
141153323Srodrigc	for (curdesc = bhp->bh_first;
142153323Srodrigc	     curdesc != NULL;
143153323Srodrigc	     curdesc = curdesc->bd_next) {
144153323Srodrigc
145153323Srodrigc		int	position = BHV_POSITION(curdesc);
146153323Srodrigc
147153323Srodrigc		if (position <= high) {
148153323Srodrigc			if (position >= low)
149153323Srodrigc				return curdesc;
150153323Srodrigc			return NULL;
151153323Srodrigc		}
152153323Srodrigc	}
153153323Srodrigc
154153323Srodrigc	return NULL;
155153323Srodrigc}
156153323Srodrigc
157153323Srodrigc/*
158153323Srodrigc * Return the base behavior in the chain, or NULL if the chain
159153323Srodrigc * is empty.
160153323Srodrigc *
161153323Srodrigc * The caller has not read locked the behavior chain, so acquire the
162153323Srodrigc * lock before traversing the chain.
163153323Srodrigc */
164153323Srodrigcbhv_desc_t *
165153323Srodrigcbhv_base(bhv_head_t *bhp)
166153323Srodrigc{
167153323Srodrigc	bhv_desc_t	*curdesc;
168153323Srodrigc
169153323Srodrigc	for (curdesc = bhp->bh_first;
170153323Srodrigc	     curdesc != NULL;
171153323Srodrigc	     curdesc = curdesc->bd_next) {
172153323Srodrigc
173153323Srodrigc		if (curdesc->bd_next == NULL) {
174153323Srodrigc			return curdesc;
175153323Srodrigc		}
176153323Srodrigc	}
177153323Srodrigc
178153323Srodrigc	return NULL;
179153323Srodrigc}
180153323Srodrigc
181153323Srodrigcvoid
182153323Srodrigcbhv_head_init(
183153323Srodrigc	bhv_head_t *bhp,
184153323Srodrigc	char *name)
185153323Srodrigc{
186153323Srodrigc	bhp->bh_first = NULL;
187153323Srodrigc}
188153323Srodrigc
189153323Srodrigcvoid
190153323Srodrigcbhv_insert_initial(
191153323Srodrigc	bhv_head_t *bhp,
192153323Srodrigc	bhv_desc_t *bdp)
193153323Srodrigc{
194153323Srodrigc	ASSERT(bhp->bh_first == NULL);
195153323Srodrigc	(bhp)->bh_first = bdp;
196153323Srodrigc}
197153323Srodrigc
198153323Srodrigcvoid
199153323Srodrigcbhv_head_destroy(
200153323Srodrigc	bhv_head_t *bhp)
201153323Srodrigc{
202153323Srodrigc	ASSERT(bhp->bh_first == NULL);
203153323Srodrigc}
204