22
22
MODULE_LICENSE ("GPL v2" );
23
23
MODULE_DESCRIPTION ("IRQ bypass manager utility module" );
24
24
25
- static LIST_HEAD (producers );
26
- static LIST_HEAD (consumers );
25
+ static DEFINE_XARRAY (producers );
26
+ static DEFINE_XARRAY (consumers );
27
27
static DEFINE_MUTEX (lock );
28
28
29
29
/* @lock must be held when calling connect */
@@ -86,13 +86,13 @@ static void __disconnect(struct irq_bypass_producer *prod,
86
86
* @producer: pointer to producer structure
87
87
* @eventfd: pointer to the eventfd context associated with the producer
88
88
*
89
- * Add the provided IRQ producer to the list of producers and connect
90
- * with any matching eventfd found on the IRQ consumers list .
89
+ * Add the provided IRQ producer to the set of producers and connect with the
90
+ * consumer with a matching eventfd, if one exists .
91
91
*/
92
92
int irq_bypass_register_producer (struct irq_bypass_producer * producer ,
93
93
struct eventfd_ctx * eventfd )
94
94
{
95
- struct irq_bypass_producer * tmp ;
95
+ unsigned long index = ( unsigned long ) eventfd ;
96
96
struct irq_bypass_consumer * consumer ;
97
97
int ret ;
98
98
@@ -101,22 +101,20 @@ int irq_bypass_register_producer(struct irq_bypass_producer *producer,
101
101
102
102
guard (mutex )(& lock );
103
103
104
- list_for_each_entry (tmp , & producers , node ) {
105
- if (tmp -> eventfd == eventfd )
106
- return - EBUSY ;
107
- }
104
+ ret = xa_insert (& producers , index , producer , GFP_KERNEL );
105
+ if (ret )
106
+ return ret ;
108
107
109
- list_for_each_entry ( consumer , & consumers , node ) {
110
- if (consumer -> eventfd == eventfd ) {
111
- ret = __connect (producer , consumer );
112
- if (ret )
113
- return ret ;
114
- break ;
108
+ consumer = xa_load ( & consumers , index );
109
+ if (consumer ) {
110
+ ret = __connect (producer , consumer );
111
+ if (ret ) {
112
+ WARN_ON_ONCE ( xa_erase ( & producers , index ) != producer ) ;
113
+ return ret ;
115
114
}
116
115
}
117
116
118
117
producer -> eventfd = eventfd ;
119
- list_add (& producer -> node , & producers );
120
118
return 0 ;
121
119
}
122
120
EXPORT_SYMBOL_GPL (irq_bypass_register_producer );
@@ -125,11 +123,14 @@ EXPORT_SYMBOL_GPL(irq_bypass_register_producer);
125
123
* irq_bypass_unregister_producer - unregister IRQ bypass producer
126
124
* @producer: pointer to producer structure
127
125
*
128
- * Remove a previously registered IRQ producer from the list of producers
129
- * and disconnect it from any connected IRQ consumer.
126
+ * Remove a previously registered IRQ producer (note, it's safe to call this
127
+ * even if registration was unsuccessful). Disconnect from the associated
128
+ * consumer, if one exists.
130
129
*/
131
130
void irq_bypass_unregister_producer (struct irq_bypass_producer * producer )
132
131
{
132
+ unsigned long index = (unsigned long )producer -> eventfd ;
133
+
133
134
if (!producer -> eventfd )
134
135
return ;
135
136
@@ -138,8 +139,8 @@ void irq_bypass_unregister_producer(struct irq_bypass_producer *producer)
138
139
if (producer -> consumer )
139
140
__disconnect (producer , producer -> consumer );
140
141
142
+ WARN_ON_ONCE (xa_erase (& producers , index ) != producer );
141
143
producer -> eventfd = NULL ;
142
- list_del (& producer -> node );
143
144
}
144
145
EXPORT_SYMBOL_GPL (irq_bypass_unregister_producer );
145
146
@@ -148,13 +149,13 @@ EXPORT_SYMBOL_GPL(irq_bypass_unregister_producer);
148
149
* @consumer: pointer to consumer structure
149
150
* @eventfd: pointer to the eventfd context associated with the consumer
150
151
*
151
- * Add the provided IRQ consumer to the list of consumers and connect
152
- * with any matching eventfd found on the IRQ producer list .
152
+ * Add the provided IRQ consumer to the set of consumers and connect with the
153
+ * producer with a matching eventfd, if one exists .
153
154
*/
154
155
int irq_bypass_register_consumer (struct irq_bypass_consumer * consumer ,
155
156
struct eventfd_ctx * eventfd )
156
157
{
157
- struct irq_bypass_consumer * tmp ;
158
+ unsigned long index = ( unsigned long ) eventfd ;
158
159
struct irq_bypass_producer * producer ;
159
160
int ret ;
160
161
@@ -166,22 +167,20 @@ int irq_bypass_register_consumer(struct irq_bypass_consumer *consumer,
166
167
167
168
guard (mutex )(& lock );
168
169
169
- list_for_each_entry (tmp , & consumers , node ) {
170
- if (tmp -> eventfd == eventfd )
171
- return - EBUSY ;
172
- }
170
+ ret = xa_insert (& consumers , index , consumer , GFP_KERNEL );
171
+ if (ret )
172
+ return ret ;
173
173
174
- list_for_each_entry ( producer , & producers , node ) {
175
- if (producer -> eventfd == eventfd ) {
176
- ret = __connect (producer , consumer );
177
- if (ret )
178
- return ret ;
179
- break ;
174
+ producer = xa_load ( & producers , index );
175
+ if (producer ) {
176
+ ret = __connect (producer , consumer );
177
+ if (ret ) {
178
+ WARN_ON_ONCE ( xa_erase ( & consumers , index ) != consumer ) ;
179
+ return ret ;
180
180
}
181
181
}
182
182
183
183
consumer -> eventfd = eventfd ;
184
- list_add (& consumer -> node , & consumers );
185
184
return 0 ;
186
185
}
187
186
EXPORT_SYMBOL_GPL (irq_bypass_register_consumer );
@@ -190,11 +189,14 @@ EXPORT_SYMBOL_GPL(irq_bypass_register_consumer);
190
189
* irq_bypass_unregister_consumer - unregister IRQ bypass consumer
191
190
* @consumer: pointer to consumer structure
192
191
*
193
- * Remove a previously registered IRQ consumer from the list of consumers
194
- * and disconnect it from any connected IRQ producer.
192
+ * Remove a previously registered IRQ consumer (note, it's safe to call this
193
+ * even if registration was unsuccessful). Disconnect from the associated
194
+ * producer, if one exists.
195
195
*/
196
196
void irq_bypass_unregister_consumer (struct irq_bypass_consumer * consumer )
197
197
{
198
+ unsigned long index = (unsigned long )consumer -> eventfd ;
199
+
198
200
if (!consumer -> eventfd )
199
201
return ;
200
202
@@ -203,7 +205,7 @@ void irq_bypass_unregister_consumer(struct irq_bypass_consumer *consumer)
203
205
if (consumer -> producer )
204
206
__disconnect (consumer -> producer , consumer );
205
207
208
+ WARN_ON_ONCE (xa_erase (& consumers , index ) != consumer );
206
209
consumer -> eventfd = NULL ;
207
- list_del (& consumer -> node );
208
210
}
209
211
EXPORT_SYMBOL_GPL (irq_bypass_unregister_consumer );
0 commit comments