1/* 2 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 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 7 * published by the Free Software Foundation. 8 * 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. 13 * 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 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 * 34 * Attempts to insert duplicate ops result in an EINVAL return code. 35 * Otherwise, return 0 to indicate success. 36 */ 37int 38bhv_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; 87 * the position is guaranteed not to be the first position. 88 * Should only be called by the bhv_remove() macro. 89 */ 90void 91bhv_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/* 113 * Looks for the first behavior within a specified range of positions. 114 * Return the associated behavior descriptor. Or NULL, if none found. 115 */ 116bhv_desc_t * 117bhv_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 */ 144bhv_desc_t * 145bhv_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 161void 162bhv_head_init( 163 bhv_head_t *bhp, 164 char *name) 165{ 166 bhp->bh_first = NULL; 167} 168 169void 170bhv_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 178void 179bhv_head_destroy( 180 bhv_head_t *bhp) 181{ 182 ASSERT(bhp->bh_first == NULL); 183} 184