Blame view

drivers/base/attribute_container.c 12 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   * attribute_container.c - implementation of a simple container for classes
   *
   * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
   *
   * This file is licensed under GPLv2
   *
   * The basic idea here is to enable a device to be attached to an
   * aritrary numer of classes without having to allocate storage for them.
   * Instead, the contained classes select the devices they need to attach
   * to via a matching function.
   */
  
  #include <linux/attribute_container.h>
  #include <linux/init.h>
  #include <linux/device.h>
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/module.h>
f8916c11a   Michael S. Tsirkin   Driver core: incl...
21
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

a1bdc7aad   Ben Dooks   [PATCH] drivers/b...
23
  #include "base.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  /* This is a private structure used to tie the classdev and the
   * container .. it should never be visible outside this file */
  struct internal_container {
53c165e0a   James Bottomley   [SCSI] correct at...
27
  	struct klist_node node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  	struct attribute_container *cont;
ee959b00c   Tony Jones   SCSI: convert str...
29
  	struct device classdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  };
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
31
32
33
34
  static void internal_container_klist_get(struct klist_node *n)
  {
  	struct internal_container *ic =
  		container_of(n, struct internal_container, node);
ee959b00c   Tony Jones   SCSI: convert str...
35
  	get_device(&ic->classdev);
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
36
37
38
39
40
41
  }
  
  static void internal_container_klist_put(struct klist_node *n)
  {
  	struct internal_container *ic =
  		container_of(n, struct internal_container, node);
ee959b00c   Tony Jones   SCSI: convert str...
42
  	put_device(&ic->classdev);
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
43
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
  /**
   * attribute_container_classdev_to_container - given a classdev, return the container
   *
   * @classdev: the class device created by attribute_container_add_device.
   *
   * Returns the container associated with this classdev.
   */
  struct attribute_container *
ee959b00c   Tony Jones   SCSI: convert str...
52
  attribute_container_classdev_to_container(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
58
  {
  	struct internal_container *ic =
  		container_of(classdev, struct internal_container, classdev);
  	return ic->cont;
  }
  EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
db1118a46   Denis Cheng   Driver core: use ...
59
  static LIST_HEAD(attribute_container_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

61a2f59af   Matthias Kaehlcke   drivers/base/attr...
61
  static DEFINE_MUTEX(attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
  
  /**
   * attribute_container_register - register an attribute container
   *
   * @cont: The container to register.  This must be allocated by the
   *        callee and should also be zeroed by it.
   */
  int
  attribute_container_register(struct attribute_container *cont)
  {
  	INIT_LIST_HEAD(&cont->node);
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
73
74
  	klist_init(&cont->containers,internal_container_klist_get,
  		   internal_container_klist_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  		
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
76
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	list_add_tail(&cont->node, &attribute_container_list);
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
78
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(attribute_container_register);
  
  /**
   * attribute_container_unregister - remove a container registration
   *
   * @cont: previously registered container to remove
   */
  int
  attribute_container_unregister(struct attribute_container *cont)
  {
  	int retval = -EBUSY;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
93
  	mutex_lock(&attribute_container_mutex);
53c165e0a   James Bottomley   [SCSI] correct at...
94
95
  	spin_lock(&cont->containers.k_lock);
  	if (!list_empty(&cont->containers.k_list))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
  		goto out;
  	retval = 0;
  	list_del(&cont->node);
   out:
53c165e0a   James Bottomley   [SCSI] correct at...
100
  	spin_unlock(&cont->containers.k_lock);
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
101
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
  	return retval;
  		
  }
  EXPORT_SYMBOL_GPL(attribute_container_unregister);
  
  /* private function used as class release */
ee959b00c   Tony Jones   SCSI: convert str...
108
  static void attribute_container_release(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
  {
  	struct internal_container *ic 
  		= container_of(classdev, struct internal_container, classdev);
ee959b00c   Tony Jones   SCSI: convert str...
112
  	struct device *dev = classdev->parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  
  	kfree(ic);
  	put_device(dev);
  }
  
  /**
   * attribute_container_add_device - see if any container is interested in dev
   *
   * @dev: device to add attributes to
   * @fn:	 function to trigger addition of class device.
   *
   * This function allocates storage for the class device(s) to be
   * attached to dev (one for each matching attribute_container).  If no
   * fn is provided, the code will simply register the class device via
ee959b00c   Tony Jones   SCSI: convert str...
127
   * device_add.  If a function is provided, it is expected to add
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
   * the class device at the appropriate time.  One of the things that
   * might be necessary is to allocate and initialise the classdev and
   * then add it a later time.  To do this, call this routine for
   * allocation and initialisation and then use
ee959b00c   Tony Jones   SCSI: convert str...
132
   * attribute_container_device_trigger() to call device_add() on
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
   * it.  Note: after this, the class device contains a reference to dev
   * which is not relinquished until the release of the classdev.
   */
  void
  attribute_container_add_device(struct device *dev,
  			       int (*fn)(struct attribute_container *,
  					 struct device *,
ee959b00c   Tony Jones   SCSI: convert str...
140
  					 struct device *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
143
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
  	list_for_each_entry(cont, &attribute_container_list, node) {
  		struct internal_container *ic;
  
  		if (attribute_container_no_classdevs(cont))
  			continue;
  
  		if (!cont->match(cont, dev))
  			continue;
4aed0644d   Jiri Slaby   [PATCH] drivers/b...
152
153
  
  		ic = kzalloc(sizeof(*ic), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
  		if (!ic) {
  			dev_printk(KERN_ERR, dev, "failed to allocate class container
  ");
  			continue;
  		}
4aed0644d   Jiri Slaby   [PATCH] drivers/b...
159

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  		ic->cont = cont;
ee959b00c   Tony Jones   SCSI: convert str...
161
162
  		device_initialize(&ic->classdev);
  		ic->classdev.parent = get_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  		ic->classdev.class = cont->class;
ee959b00c   Tony Jones   SCSI: convert str...
164
  		cont->class->dev_release = attribute_container_release;
1e0b2cf93   Kay Sievers   driver core: stru...
165
  		dev_set_name(&ic->classdev, dev_name(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
  		if (fn)
  			fn(cont, dev, &ic->classdev);
  		else
  			attribute_container_add_class_device(&ic->classdev);
53c165e0a   James Bottomley   [SCSI] correct at...
170
  		klist_add_tail(&ic->node, &cont->containers);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
172
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  }
53c165e0a   James Bottomley   [SCSI] correct at...
174
175
176
177
178
179
  /* FIXME: can't break out of this unless klist_iter_exit is also
   * called before doing the break
   */
  #define klist_for_each_entry(pos, head, member, iter) \
  	for (klist_iter_init(head, iter); (pos = ({ \
  		struct klist_node *n = klist_next(iter); \
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
180
181
  		n ? container_of(n, typeof(*pos), member) : \
  			({ klist_iter_exit(iter) ; NULL; }); \
53c165e0a   James Bottomley   [SCSI] correct at...
182
183
  	}) ) != NULL; )
  			
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
  /**
   * attribute_container_remove_device - make device eligible for removal.
   *
   * @dev:  The generic device
   * @fn:	  A function to call to remove the device
   *
   * This routine triggers device removal.  If fn is NULL, then it is
ee959b00c   Tony Jones   SCSI: convert str...
191
   * simply done via device_unregister (note that if something
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
   * still has a reference to the classdev, then the memory occupied
   * will not be freed until the classdev is released).  If you want a
   * two phase release: remove from visibility and then delete the
   * device, then you should use this routine with a fn that calls
ee959b00c   Tony Jones   SCSI: convert str...
196
197
   * device_del() and then use attribute_container_device_trigger()
   * to do the final put on the classdev.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
   */
  void
  attribute_container_remove_device(struct device *dev,
  				  void (*fn)(struct attribute_container *,
  					     struct device *,
ee959b00c   Tony Jones   SCSI: convert str...
203
  					     struct device *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
206
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	list_for_each_entry(cont, &attribute_container_list, node) {
53c165e0a   James Bottomley   [SCSI] correct at...
208
209
  		struct internal_container *ic;
  		struct klist_iter iter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
215
  
  		if (attribute_container_no_classdevs(cont))
  			continue;
  
  		if (!cont->match(cont, dev))
  			continue;
53c165e0a   James Bottomley   [SCSI] correct at...
216
217
  
  		klist_for_each_entry(ic, &cont->containers, node, &iter) {
ee959b00c   Tony Jones   SCSI: convert str...
218
  			if (dev != ic->classdev.parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  				continue;
caf39e87c   Linus Torvalds   [SCSI] Re-do "fin...
220
  			klist_del(&ic->node);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
  			if (fn)
  				fn(cont, dev, &ic->classdev);
  			else {
  				attribute_container_remove_attrs(&ic->classdev);
ee959b00c   Tony Jones   SCSI: convert str...
225
  				device_unregister(&ic->classdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
  			}
  		}
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
229
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  
  /**
   * attribute_container_device_trigger - execute a trigger for each matching classdev
   *
   * @dev:  The generic device to run the trigger for
   * @fn	  the function to execute for each classdev.
   *
   * This funcion is for executing a trigger when you need to know both
   * the container and the classdev.  If you only care about the
   * container, then use attribute_container_trigger() instead.
   */
  void
  attribute_container_device_trigger(struct device *dev, 
  				   int (*fn)(struct attribute_container *,
  					     struct device *,
ee959b00c   Tony Jones   SCSI: convert str...
246
  					     struct device *))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
249
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  	list_for_each_entry(cont, &attribute_container_list, node) {
53c165e0a   James Bottomley   [SCSI] correct at...
251
252
  		struct internal_container *ic;
  		struct klist_iter iter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
  
  		if (!cont->match(cont, dev))
  			continue;
ebd8bb764   James Bottomley   [SCSI] fix transp...
256
257
258
259
  		if (attribute_container_no_classdevs(cont)) {
  			fn(cont, dev, NULL);
  			continue;
  		}
53c165e0a   James Bottomley   [SCSI] correct at...
260
  		klist_for_each_entry(ic, &cont->containers, node, &iter) {
ee959b00c   Tony Jones   SCSI: convert str...
261
  			if (dev == ic->classdev.parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
  				fn(cont, dev, &ic->classdev);
  		}
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
265
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  
  /**
   * attribute_container_trigger - trigger a function for each matching container
   *
   * @dev:  The generic device to activate the trigger for
   * @fn:	  the function to trigger
   *
   * This routine triggers a function that only needs to know the
   * matching containers (not the classdev) associated with a device.
   * It is more lightweight than attribute_container_device_trigger, so
   * should be used in preference unless the triggering function
   * actually needs to know the classdev.
   */
  void
  attribute_container_trigger(struct device *dev,
  			    int (*fn)(struct attribute_container *,
  				      struct device *))
  {
  	struct attribute_container *cont;
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
286
  	mutex_lock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
  	list_for_each_entry(cont, &attribute_container_list, node) {
  		if (cont->match(cont, dev))
  			fn(cont, dev);
  	}
61a2f59af   Matthias Kaehlcke   drivers/base/attr...
291
  	mutex_unlock(&attribute_container_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
298
299
300
301
302
  
  /**
   * attribute_container_add_attrs - add attributes
   *
   * @classdev: The class device
   *
   * This simply creates all the class device sysfs files from the
   * attributes listed in the container
   */
  int
ee959b00c   Tony Jones   SCSI: convert str...
303
  attribute_container_add_attrs(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
306
  {
  	struct attribute_container *cont =
  		attribute_container_classdev_to_container(classdev);
ee959b00c   Tony Jones   SCSI: convert str...
307
  	struct device_attribute **attrs = cont->attrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	int i, error;
fd1109711   James Bottomley   [SCSI] attribute_...
309
310
311
  	BUG_ON(attrs && cont->grp);
  
  	if (!attrs && !cont->grp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  		return 0;
fd1109711   James Bottomley   [SCSI] attribute_...
313
314
  	if (cont->grp)
  		return sysfs_create_group(&classdev->kobj, cont->grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  	for (i = 0; attrs[i]; i++) {
ebd09ec93   James Bottomley   [SCSI] attirbute_...
316
  		sysfs_attr_init(&attrs[i]->attr);
ee959b00c   Tony Jones   SCSI: convert str...
317
  		error = device_create_file(classdev, attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
  		if (error)
  			return error;
  	}
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
  
  /**
ee959b00c   Tony Jones   SCSI: convert str...
326
   * attribute_container_add_class_device - same function as device_add
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
   *
   * @classdev:	the class device to add
   *
ee959b00c   Tony Jones   SCSI: convert str...
330
   * This performs essentially the same function as device_add except for
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
   * attribute containers, namely add the classdev to the system and then
   * create the attribute files
   */
  int
ee959b00c   Tony Jones   SCSI: convert str...
335
  attribute_container_add_class_device(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  {
ee959b00c   Tony Jones   SCSI: convert str...
337
  	int error = device_add(classdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
  	if (error)
  		return error;
  	return attribute_container_add_attrs(classdev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
346
347
348
349
350
351
  
  /**
   * attribute_container_add_class_device_adapter - simple adapter for triggers
   *
   * This function is identical to attribute_container_add_class_device except
   * that it is designed to be called from the triggers
   */
  int
  attribute_container_add_class_device_adapter(struct attribute_container *cont,
  					     struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
352
  					     struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  {
  	return attribute_container_add_class_device(classdev);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
360
361
362
363
  
  /**
   * attribute_container_remove_attrs - remove any attribute files
   *
   * @classdev: The class device to remove the files from
   *
   */
  void
ee959b00c   Tony Jones   SCSI: convert str...
364
  attribute_container_remove_attrs(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
  {
  	struct attribute_container *cont =
  		attribute_container_classdev_to_container(classdev);
ee959b00c   Tony Jones   SCSI: convert str...
368
  	struct device_attribute **attrs = cont->attrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	int i;
fd1109711   James Bottomley   [SCSI] attribute_...
370
  	if (!attrs && !cont->grp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  		return;
fd1109711   James Bottomley   [SCSI] attribute_...
372
373
374
375
  	if (cont->grp) {
  		sysfs_remove_group(&classdev->kobj, cont->grp);
  		return ;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	for (i = 0; attrs[i]; i++)
ee959b00c   Tony Jones   SCSI: convert str...
377
  		device_remove_file(classdev, attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
383
384
385
  
  /**
   * attribute_container_class_device_del - equivalent of class_device_del
   *
   * @classdev: the class device
   *
   * This function simply removes all the attribute files and then calls
ee959b00c   Tony Jones   SCSI: convert str...
386
   * device_del.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
   */
  void
ee959b00c   Tony Jones   SCSI: convert str...
389
  attribute_container_class_device_del(struct device *classdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  {
  	attribute_container_remove_attrs(classdev);
ee959b00c   Tony Jones   SCSI: convert str...
392
  	device_del(classdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394

d0a7e5740   James Bottomley   [SCSI] correct tr...
395
396
397
398
399
400
401
402
403
  /**
   * attribute_container_find_class_device - find the corresponding class_device
   *
   * @cont:	the container
   * @dev:	the generic device
   *
   * Looks up the device in the container's list of class devices and returns
   * the corresponding class_device.
   */
ee959b00c   Tony Jones   SCSI: convert str...
404
  struct device *
d0a7e5740   James Bottomley   [SCSI] correct tr...
405
406
407
  attribute_container_find_class_device(struct attribute_container *cont,
  				      struct device *dev)
  {
ee959b00c   Tony Jones   SCSI: convert str...
408
  	struct device *cdev = NULL;
d0a7e5740   James Bottomley   [SCSI] correct tr...
409
  	struct internal_container *ic;
53c165e0a   James Bottomley   [SCSI] correct at...
410
  	struct klist_iter iter;
d0a7e5740   James Bottomley   [SCSI] correct tr...
411

53c165e0a   James Bottomley   [SCSI] correct at...
412
  	klist_for_each_entry(ic, &cont->containers, node, &iter) {
ee959b00c   Tony Jones   SCSI: convert str...
413
  		if (ic->classdev.parent == dev) {
d0a7e5740   James Bottomley   [SCSI] correct tr...
414
  			cdev = &ic->classdev;
53c165e0a   James Bottomley   [SCSI] correct at...
415
416
  			/* FIXME: must exit iterator then break */
  			klist_iter_exit(&iter);
d0a7e5740   James Bottomley   [SCSI] correct tr...
417
418
419
  			break;
  		}
  	}
d0a7e5740   James Bottomley   [SCSI] correct tr...
420
421
422
423
  
  	return cdev;
  }
  EXPORT_SYMBOL_GPL(attribute_container_find_class_device);