| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Nathan Scott | 7b71876 | 2005-11-02 14:58:39 +1100 | [diff] [blame] | 2 |  * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 
 | 3 |  * All Rights Reserved. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 |  * | 
| Nathan Scott | 7b71876 | 2005-11-02 14:58:39 +1100 | [diff] [blame] | 5 |  * This program is free software; you can redistribute it and/or | 
 | 6 |  * modify it under the terms of the GNU General Public License as | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 |  * published by the Free Software Foundation. | 
 | 8 |  * | 
| Nathan Scott | 7b71876 | 2005-11-02 14:58:39 +1100 | [diff] [blame] | 9 |  * This program is distributed in the hope that it would be useful, | 
 | 10 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 11 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 12 |  * GNU General Public License for more details. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 |  * | 
| Nathan Scott | 7b71876 | 2005-11-02 14:58:39 +1100 | [diff] [blame] | 14 |  * You should have received a copy of the GNU General Public License | 
 | 15 |  * along with this program; if not, write the Free Software Foundation, | 
 | 16 |  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 17 |  */ | 
 | 18 | #include "xfs.h" | 
 | 19 |  | 
 | 20 | /* | 
 | 21 |  * Source file used to associate/disassociate behaviors with virtualized | 
 | 22 |  * objects.  See xfs_behavior.h for more information about behaviors, etc. | 
 | 23 |  * | 
 | 24 |  * The implementation is split between functions in this file and macros | 
 | 25 |  * in xfs_behavior.h. | 
 | 26 |  */ | 
 | 27 |  | 
 | 28 | /* | 
 | 29 |  * Insert a new behavior descriptor into a behavior chain. | 
 | 30 |  * | 
 | 31 |  * The behavior chain is ordered based on the 'position' number which | 
 | 32 |  * lives in the first field of the ops vector (higher numbers first). | 
 | 33 |  * | 
| Nathan Scott | c41564b | 2006-03-29 08:55:14 +1000 | [diff] [blame] | 34 |  * Attempts to insert duplicate ops result in an EINVAL return code. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 |  * Otherwise, return 0 to indicate success. | 
 | 36 |  */ | 
 | 37 | int | 
 | 38 | bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp) | 
 | 39 | { | 
 | 40 | 	bhv_desc_t	*curdesc, *prev; | 
 | 41 | 	int		position; | 
 | 42 |  | 
 | 43 | 	/* | 
 | 44 | 	 * Validate the position value of the new behavior. | 
 | 45 | 	 */ | 
 | 46 | 	position = BHV_POSITION(bdp); | 
 | 47 | 	ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP); | 
 | 48 |  | 
 | 49 | 	/* | 
 | 50 | 	 * Find location to insert behavior.  Check for duplicates. | 
 | 51 | 	 */ | 
 | 52 | 	prev = NULL; | 
 | 53 | 	for (curdesc = bhp->bh_first; | 
 | 54 | 	     curdesc != NULL; | 
 | 55 | 	     curdesc = curdesc->bd_next) { | 
 | 56 |  | 
 | 57 | 		/* Check for duplication. */ | 
 | 58 | 		if (curdesc->bd_ops == bdp->bd_ops) { | 
 | 59 | 			ASSERT(0); | 
 | 60 | 			return EINVAL; | 
 | 61 | 		} | 
 | 62 |  | 
 | 63 | 		/* Find correct position */ | 
 | 64 | 		if (position >= BHV_POSITION(curdesc)) { | 
 | 65 | 			ASSERT(position != BHV_POSITION(curdesc)); | 
 | 66 | 			break;		/* found it */ | 
 | 67 | 		} | 
 | 68 |  | 
 | 69 | 		prev = curdesc; | 
 | 70 | 	} | 
 | 71 |  | 
 | 72 | 	if (prev == NULL) { | 
 | 73 | 		/* insert at front of chain */ | 
 | 74 | 		bdp->bd_next = bhp->bh_first; | 
 | 75 | 		bhp->bh_first = bdp; | 
 | 76 | 	} else { | 
 | 77 | 		/* insert after prev */ | 
 | 78 | 		bdp->bd_next = prev->bd_next; | 
 | 79 | 		prev->bd_next = bdp; | 
 | 80 | 	} | 
 | 81 |  | 
 | 82 | 	return 0; | 
 | 83 | } | 
 | 84 |  | 
 | 85 | /* | 
 | 86 |  * Remove a behavior descriptor from a position in a behavior chain; | 
| Nathan Scott | c41564b | 2006-03-29 08:55:14 +1000 | [diff] [blame] | 87 |  * the position is guaranteed not to be the first position. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 |  * Should only be called by the bhv_remove() macro. | 
 | 89 |  */ | 
 | 90 | void | 
 | 91 | bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp) | 
 | 92 | { | 
 | 93 | 	bhv_desc_t	*curdesc, *prev; | 
 | 94 |  | 
 | 95 | 	ASSERT(bhp->bh_first != NULL); | 
 | 96 | 	ASSERT(bhp->bh_first->bd_next != NULL); | 
 | 97 |  | 
 | 98 | 	prev = bhp->bh_first; | 
 | 99 | 	for (curdesc = bhp->bh_first->bd_next; | 
 | 100 | 	     curdesc != NULL; | 
 | 101 | 	     curdesc = curdesc->bd_next) { | 
 | 102 |  | 
 | 103 | 		if (curdesc == bdp) | 
 | 104 | 			break;		/* found it */ | 
 | 105 | 		prev = curdesc; | 
 | 106 | 	} | 
 | 107 |  | 
 | 108 | 	ASSERT(curdesc == bdp); | 
 | 109 | 	prev->bd_next = bdp->bd_next;	/* remove from after prev */ | 
 | 110 | } | 
 | 111 |  | 
 | 112 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 |  * Looks for the first behavior within a specified range of positions. | 
 | 114 |  * Return the associated behavior descriptor.  Or NULL, if none found. | 
 | 115 |  */ | 
 | 116 | bhv_desc_t * | 
 | 117 | bhv_lookup_range(bhv_head_t *bhp, int low, int high) | 
 | 118 | { | 
 | 119 | 	bhv_desc_t	*curdesc; | 
 | 120 |  | 
 | 121 | 	for (curdesc = bhp->bh_first; | 
 | 122 | 	     curdesc != NULL; | 
 | 123 | 	     curdesc = curdesc->bd_next) { | 
 | 124 |  | 
 | 125 | 		int	position = BHV_POSITION(curdesc); | 
 | 126 |  | 
 | 127 | 		if (position <= high) { | 
 | 128 | 			if (position >= low) | 
 | 129 | 				return curdesc; | 
 | 130 | 			return NULL; | 
 | 131 | 		} | 
 | 132 | 	} | 
 | 133 |  | 
 | 134 | 	return NULL; | 
 | 135 | } | 
 | 136 |  | 
 | 137 | /* | 
 | 138 |  * Return the base behavior in the chain, or NULL if the chain | 
 | 139 |  * is empty. | 
 | 140 |  * | 
 | 141 |  * The caller has not read locked the behavior chain, so acquire the | 
 | 142 |  * lock before traversing the chain. | 
 | 143 |  */ | 
 | 144 | bhv_desc_t * | 
 | 145 | bhv_base(bhv_head_t *bhp) | 
 | 146 | { | 
 | 147 | 	bhv_desc_t	*curdesc; | 
 | 148 |  | 
 | 149 | 	for (curdesc = bhp->bh_first; | 
 | 150 | 	     curdesc != NULL; | 
 | 151 | 	     curdesc = curdesc->bd_next) { | 
 | 152 |  | 
 | 153 | 		if (curdesc->bd_next == NULL) { | 
 | 154 | 			return curdesc; | 
 | 155 | 		} | 
 | 156 | 	} | 
 | 157 |  | 
 | 158 | 	return NULL; | 
 | 159 | } | 
 | 160 |  | 
 | 161 | void | 
 | 162 | bhv_head_init( | 
 | 163 | 	bhv_head_t *bhp, | 
 | 164 | 	char *name) | 
 | 165 | { | 
 | 166 | 	bhp->bh_first = NULL; | 
 | 167 | } | 
 | 168 |  | 
 | 169 | void | 
 | 170 | bhv_insert_initial( | 
 | 171 | 	bhv_head_t *bhp, | 
 | 172 | 	bhv_desc_t *bdp) | 
 | 173 | { | 
 | 174 | 	ASSERT(bhp->bh_first == NULL); | 
 | 175 | 	(bhp)->bh_first = bdp; | 
 | 176 | } | 
 | 177 |  | 
 | 178 | void | 
 | 179 | bhv_head_destroy( | 
 | 180 | 	bhv_head_t *bhp) | 
 | 181 | { | 
 | 182 | 	ASSERT(bhp->bh_first == NULL); | 
 | 183 | } |