@@ -102,56 +102,35 @@ static void mdev_put_parent(struct mdev_parent *parent)
102
102
kref_put (& parent -> ref , mdev_release_parent );
103
103
}
104
104
105
- static int mdev_device_create_ops ( struct kobject * kobj ,
106
- struct mdev_device * mdev )
105
+ /* Caller must hold parent unreg_sem read or write lock */
106
+ static void mdev_device_remove_common ( struct mdev_device * mdev )
107
107
{
108
- struct mdev_parent * parent = mdev -> parent ;
109
- int ret ;
110
-
111
- ret = parent -> ops -> create (kobj , mdev );
112
- if (ret )
113
- return ret ;
114
-
115
- ret = sysfs_create_groups (& mdev -> dev .kobj ,
116
- parent -> ops -> mdev_attr_groups );
117
- if (ret )
118
- parent -> ops -> remove (mdev );
119
-
120
- return ret ;
121
- }
122
-
123
- /*
124
- * mdev_device_remove_ops gets called from sysfs's 'remove' and when parent
125
- * device is being unregistered from mdev device framework.
126
- * - 'force_remove' is set to 'false' when called from sysfs's 'remove' which
127
- * indicates that if the mdev device is active, used by VMM or userspace
128
- * application, vendor driver could return error then don't remove the device.
129
- * - 'force_remove' is set to 'true' when called from mdev_unregister_device()
130
- * which indicate that parent device is being removed from mdev device
131
- * framework so remove mdev device forcefully.
132
- */
133
- static int mdev_device_remove_ops (struct mdev_device * mdev , bool force_remove )
134
- {
135
- struct mdev_parent * parent = mdev -> parent ;
108
+ struct mdev_parent * parent ;
109
+ struct mdev_type * type ;
136
110
int ret ;
137
111
138
- /*
139
- * Vendor driver can return error if VMM or userspace application is
140
- * using this mdev device.
141
- */
112
+ type = to_mdev_type (mdev -> type_kobj );
113
+ mdev_remove_sysfs_files (& mdev -> dev , type );
114
+ device_del (& mdev -> dev );
115
+ parent = mdev -> parent ;
116
+ lockdep_assert_held (& parent -> unreg_sem );
142
117
ret = parent -> ops -> remove (mdev );
143
- if (ret && ! force_remove )
144
- return ret ;
118
+ if (ret )
119
+ dev_err ( & mdev -> dev , "Remove failed: err=%d\n" , ret ) ;
145
120
146
- sysfs_remove_groups (& mdev -> dev .kobj , parent -> ops -> mdev_attr_groups );
147
- return 0 ;
121
+ /* Balances with device_initialize() */
122
+ put_device (& mdev -> dev );
123
+ mdev_put_parent (parent );
148
124
}
149
125
150
126
static int mdev_device_remove_cb (struct device * dev , void * data )
151
127
{
152
- if (dev_is_mdev (dev ))
153
- mdev_device_remove ( dev , true) ;
128
+ if (dev_is_mdev (dev )) {
129
+ struct mdev_device * mdev ;
154
130
131
+ mdev = to_mdev_device (dev );
132
+ mdev_device_remove_common (mdev );
133
+ }
155
134
return 0 ;
156
135
}
157
136
@@ -193,6 +172,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
193
172
}
194
173
195
174
kref_init (& parent -> ref );
175
+ init_rwsem (& parent -> unreg_sem );
196
176
197
177
parent -> dev = dev ;
198
178
parent -> ops = ops ;
@@ -251,21 +231,23 @@ void mdev_unregister_device(struct device *dev)
251
231
dev_info (dev , "MDEV: Unregistering\n" );
252
232
253
233
list_del (& parent -> next );
234
+ mutex_unlock (& parent_list_lock );
235
+
236
+ down_write (& parent -> unreg_sem );
237
+
254
238
class_compat_remove_link (mdev_bus_compat_class , dev , NULL );
255
239
256
240
device_for_each_child (dev , NULL , mdev_device_remove_cb );
257
241
258
242
parent_remove_sysfs_files (parent );
243
+ up_write (& parent -> unreg_sem );
259
244
260
- mutex_unlock (& parent_list_lock );
261
245
mdev_put_parent (parent );
262
246
}
263
247
EXPORT_SYMBOL (mdev_unregister_device );
264
248
265
- static void mdev_device_release (struct device * dev )
249
+ static void mdev_device_free (struct mdev_device * mdev )
266
250
{
267
- struct mdev_device * mdev = to_mdev_device (dev );
268
-
269
251
mutex_lock (& mdev_list_lock );
270
252
list_del (& mdev -> next );
271
253
mutex_unlock (& mdev_list_lock );
@@ -274,6 +256,13 @@ static void mdev_device_release(struct device *dev)
274
256
kfree (mdev );
275
257
}
276
258
259
+ static void mdev_device_release (struct device * dev )
260
+ {
261
+ struct mdev_device * mdev = to_mdev_device (dev );
262
+
263
+ mdev_device_free (mdev );
264
+ }
265
+
277
266
int mdev_device_create (struct kobject * kobj ,
278
267
struct device * dev , const guid_t * uuid )
279
268
{
@@ -310,46 +299,55 @@ int mdev_device_create(struct kobject *kobj,
310
299
311
300
mdev -> parent = parent ;
312
301
302
+ /* Check if parent unregistration has started */
303
+ if (!down_read_trylock (& parent -> unreg_sem )) {
304
+ mdev_device_free (mdev );
305
+ ret = - ENODEV ;
306
+ goto mdev_fail ;
307
+ }
308
+
309
+ device_initialize (& mdev -> dev );
313
310
mdev -> dev .parent = dev ;
314
311
mdev -> dev .bus = & mdev_bus_type ;
315
312
mdev -> dev .release = mdev_device_release ;
316
313
dev_set_name (& mdev -> dev , "%pUl" , uuid );
314
+ mdev -> dev .groups = parent -> ops -> mdev_attr_groups ;
315
+ mdev -> type_kobj = kobj ;
317
316
318
- ret = device_register (& mdev -> dev );
319
- if (ret ) {
320
- put_device (& mdev -> dev );
321
- goto mdev_fail ;
322
- }
317
+ ret = parent -> ops -> create (kobj , mdev );
318
+ if (ret )
319
+ goto ops_create_fail ;
323
320
324
- ret = mdev_device_create_ops ( kobj , mdev );
321
+ ret = device_add ( & mdev -> dev );
325
322
if (ret )
326
- goto create_fail ;
323
+ goto add_fail ;
327
324
328
325
ret = mdev_create_sysfs_files (& mdev -> dev , type );
329
- if (ret ) {
330
- mdev_device_remove_ops (mdev , true);
331
- goto create_fail ;
332
- }
326
+ if (ret )
327
+ goto sysfs_fail ;
333
328
334
- mdev -> type_kobj = kobj ;
335
329
mdev -> active = true;
336
330
dev_dbg (& mdev -> dev , "MDEV: created\n" );
331
+ up_read (& parent -> unreg_sem );
337
332
338
333
return 0 ;
339
334
340
- create_fail :
341
- device_unregister (& mdev -> dev );
335
+ sysfs_fail :
336
+ device_del (& mdev -> dev );
337
+ add_fail :
338
+ parent -> ops -> remove (mdev );
339
+ ops_create_fail :
340
+ up_read (& parent -> unreg_sem );
341
+ put_device (& mdev -> dev );
342
342
mdev_fail :
343
343
mdev_put_parent (parent );
344
344
return ret ;
345
345
}
346
346
347
- int mdev_device_remove (struct device * dev , bool force_remove )
347
+ int mdev_device_remove (struct device * dev )
348
348
{
349
349
struct mdev_device * mdev , * tmp ;
350
350
struct mdev_parent * parent ;
351
- struct mdev_type * type ;
352
- int ret ;
353
351
354
352
mdev = to_mdev_device (dev );
355
353
@@ -372,19 +370,13 @@ int mdev_device_remove(struct device *dev, bool force_remove)
372
370
mdev -> active = false;
373
371
mutex_unlock (& mdev_list_lock );
374
372
375
- type = to_mdev_type (mdev -> type_kobj );
376
373
parent = mdev -> parent ;
374
+ /* Check if parent unregistration has started */
375
+ if (!down_read_trylock (& parent -> unreg_sem ))
376
+ return - ENODEV ;
377
377
378
- ret = mdev_device_remove_ops (mdev , force_remove );
379
- if (ret ) {
380
- mdev -> active = true;
381
- return ret ;
382
- }
383
-
384
- mdev_remove_sysfs_files (dev , type );
385
- device_unregister (dev );
386
- mdev_put_parent (parent );
387
-
378
+ mdev_device_remove_common (mdev );
379
+ up_read (& parent -> unreg_sem );
388
380
return 0 ;
389
381
}
390
382
0 commit comments