sysfs: kill an extra put in sysfs_create_link() failure path
[linux-2.6] / fs / xfs / xfs_behavior.c
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  */
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;
87  * the position is guaranteed not to be the first position.
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 /*
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 }