.. | .. |
---|
33 | 33 | unsigned int last_master; |
---|
34 | 34 | unsigned int first_channel; |
---|
35 | 35 | unsigned int last_channel; |
---|
| 36 | + /* this is the one that's exposed to the attributes */ |
---|
| 37 | + unsigned char priv[]; |
---|
36 | 38 | }; |
---|
| 39 | + |
---|
| 40 | +void *stp_policy_node_priv(struct stp_policy_node *pn) |
---|
| 41 | +{ |
---|
| 42 | + if (!pn) |
---|
| 43 | + return NULL; |
---|
| 44 | + |
---|
| 45 | + return pn->priv; |
---|
| 46 | +} |
---|
37 | 47 | |
---|
38 | 48 | static struct configfs_subsystem stp_policy_subsys; |
---|
39 | 49 | |
---|
.. | .. |
---|
67 | 77 | group) : |
---|
68 | 78 | NULL; |
---|
69 | 79 | } |
---|
| 80 | + |
---|
| 81 | +void *to_pdrv_policy_node(struct config_item *item) |
---|
| 82 | +{ |
---|
| 83 | + struct stp_policy_node *node = to_stp_policy_node(item); |
---|
| 84 | + |
---|
| 85 | + return stp_policy_node_priv(node); |
---|
| 86 | +} |
---|
| 87 | +EXPORT_SYMBOL_GPL(to_pdrv_policy_node); |
---|
70 | 88 | |
---|
71 | 89 | static ssize_t |
---|
72 | 90 | stp_policy_node_masters_show(struct config_item *item, char *page) |
---|
.. | .. |
---|
163 | 181 | |
---|
164 | 182 | static void stp_policy_node_release(struct config_item *item) |
---|
165 | 183 | { |
---|
166 | | - kfree(to_stp_policy_node(item)); |
---|
| 184 | + struct stp_policy_node *node = to_stp_policy_node(item); |
---|
| 185 | + |
---|
| 186 | + kfree(node); |
---|
167 | 187 | } |
---|
168 | 188 | |
---|
169 | 189 | static struct configfs_item_operations stp_policy_node_item_ops = { |
---|
.. | .. |
---|
182 | 202 | static const struct config_item_type stp_policy_type; |
---|
183 | 203 | static const struct config_item_type stp_policy_node_type; |
---|
184 | 204 | |
---|
| 205 | +const struct config_item_type * |
---|
| 206 | +get_policy_node_type(struct configfs_attribute **attrs) |
---|
| 207 | +{ |
---|
| 208 | + struct config_item_type *type; |
---|
| 209 | + struct configfs_attribute **merged; |
---|
| 210 | + |
---|
| 211 | + type = kmemdup(&stp_policy_node_type, sizeof(stp_policy_node_type), |
---|
| 212 | + GFP_KERNEL); |
---|
| 213 | + if (!type) |
---|
| 214 | + return NULL; |
---|
| 215 | + |
---|
| 216 | + merged = memcat_p(stp_policy_node_attrs, attrs); |
---|
| 217 | + if (!merged) { |
---|
| 218 | + kfree(type); |
---|
| 219 | + return NULL; |
---|
| 220 | + } |
---|
| 221 | + |
---|
| 222 | + type->ct_attrs = merged; |
---|
| 223 | + |
---|
| 224 | + return type; |
---|
| 225 | +} |
---|
| 226 | + |
---|
185 | 227 | static struct config_group * |
---|
186 | 228 | stp_policy_node_make(struct config_group *group, const char *name) |
---|
187 | 229 | { |
---|
| 230 | + const struct config_item_type *type = &stp_policy_node_type; |
---|
188 | 231 | struct stp_policy_node *policy_node, *parent_node; |
---|
| 232 | + const struct stm_protocol_driver *pdrv; |
---|
189 | 233 | struct stp_policy *policy; |
---|
190 | 234 | |
---|
191 | 235 | if (group->cg_item.ci_type == &stp_policy_type) { |
---|
.. | .. |
---|
199 | 243 | if (!policy->stm) |
---|
200 | 244 | return ERR_PTR(-ENODEV); |
---|
201 | 245 | |
---|
202 | | - policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL); |
---|
| 246 | + pdrv = policy->stm->pdrv; |
---|
| 247 | + policy_node = |
---|
| 248 | + kzalloc(offsetof(struct stp_policy_node, priv[pdrv->priv_sz]), |
---|
| 249 | + GFP_KERNEL); |
---|
203 | 250 | if (!policy_node) |
---|
204 | 251 | return ERR_PTR(-ENOMEM); |
---|
205 | 252 | |
---|
206 | | - config_group_init_type_name(&policy_node->group, name, |
---|
207 | | - &stp_policy_node_type); |
---|
| 253 | + if (pdrv->policy_node_init) |
---|
| 254 | + pdrv->policy_node_init((void *)policy_node->priv); |
---|
| 255 | + |
---|
| 256 | + if (policy->stm->pdrv_node_type) |
---|
| 257 | + type = policy->stm->pdrv_node_type; |
---|
| 258 | + |
---|
| 259 | + config_group_init_type_name(&policy_node->group, name, type); |
---|
208 | 260 | |
---|
209 | 261 | policy_node->policy = policy; |
---|
210 | 262 | |
---|
.. | .. |
---|
254 | 306 | |
---|
255 | 307 | CONFIGFS_ATTR_RO(stp_policy_, device); |
---|
256 | 308 | |
---|
| 309 | +static ssize_t stp_policy_protocol_show(struct config_item *item, |
---|
| 310 | + char *page) |
---|
| 311 | +{ |
---|
| 312 | + struct stp_policy *policy = to_stp_policy(item); |
---|
| 313 | + ssize_t count; |
---|
| 314 | + |
---|
| 315 | + count = sprintf(page, "%s\n", |
---|
| 316 | + (policy && policy->stm) ? |
---|
| 317 | + policy->stm->pdrv->name : |
---|
| 318 | + "<none>"); |
---|
| 319 | + |
---|
| 320 | + return count; |
---|
| 321 | +} |
---|
| 322 | + |
---|
| 323 | +CONFIGFS_ATTR_RO(stp_policy_, protocol); |
---|
| 324 | + |
---|
257 | 325 | static struct configfs_attribute *stp_policy_attrs[] = { |
---|
258 | 326 | &stp_policy_attr_device, |
---|
| 327 | + &stp_policy_attr_protocol, |
---|
259 | 328 | NULL, |
---|
260 | 329 | }; |
---|
261 | 330 | |
---|
.. | .. |
---|
276 | 345 | stm->policy = NULL; |
---|
277 | 346 | policy->stm = NULL; |
---|
278 | 347 | |
---|
| 348 | + /* |
---|
| 349 | + * Drop the reference on the protocol driver and lose the link. |
---|
| 350 | + */ |
---|
| 351 | + stm_put_protocol(stm->pdrv); |
---|
| 352 | + stm->pdrv = NULL; |
---|
279 | 353 | stm_put_device(stm); |
---|
280 | 354 | } |
---|
281 | 355 | |
---|
.. | .. |
---|
311 | 385 | }; |
---|
312 | 386 | |
---|
313 | 387 | static struct config_group * |
---|
314 | | -stp_policies_make(struct config_group *group, const char *name) |
---|
| 388 | +stp_policy_make(struct config_group *group, const char *name) |
---|
315 | 389 | { |
---|
| 390 | + const struct config_item_type *pdrv_node_type; |
---|
| 391 | + const struct stm_protocol_driver *pdrv; |
---|
| 392 | + char *devname, *proto, *p; |
---|
316 | 393 | struct config_group *ret; |
---|
317 | 394 | struct stm_device *stm; |
---|
318 | | - char *devname, *p; |
---|
| 395 | + int err; |
---|
319 | 396 | |
---|
320 | 397 | devname = kasprintf(GFP_KERNEL, "%s", name); |
---|
321 | 398 | if (!devname) |
---|
.. | .. |
---|
326 | 403 | * <device_name> is the name of an existing stm device; may |
---|
327 | 404 | * contain dots; |
---|
328 | 405 | * <policy_name> is an arbitrary string; may not contain dots |
---|
| 406 | + * <device_name>:<protocol_name>.<policy_name> |
---|
329 | 407 | */ |
---|
330 | 408 | p = strrchr(devname, '.'); |
---|
331 | 409 | if (!p) { |
---|
.. | .. |
---|
335 | 413 | |
---|
336 | 414 | *p = '\0'; |
---|
337 | 415 | |
---|
| 416 | + /* |
---|
| 417 | + * look for ":<protocol_name>": |
---|
| 418 | + * + no protocol suffix: fall back to whatever is available; |
---|
| 419 | + * + unknown protocol: fail the whole thing |
---|
| 420 | + */ |
---|
| 421 | + proto = strrchr(devname, ':'); |
---|
| 422 | + if (proto) |
---|
| 423 | + *proto++ = '\0'; |
---|
| 424 | + |
---|
338 | 425 | stm = stm_find_device(devname); |
---|
| 426 | + if (!stm) { |
---|
| 427 | + kfree(devname); |
---|
| 428 | + return ERR_PTR(-ENODEV); |
---|
| 429 | + } |
---|
| 430 | + |
---|
| 431 | + err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type); |
---|
339 | 432 | kfree(devname); |
---|
340 | 433 | |
---|
341 | | - if (!stm) |
---|
| 434 | + if (err) { |
---|
| 435 | + stm_put_device(stm); |
---|
342 | 436 | return ERR_PTR(-ENODEV); |
---|
| 437 | + } |
---|
343 | 438 | |
---|
344 | 439 | mutex_lock(&stm->policy_mutex); |
---|
345 | 440 | if (stm->policy) { |
---|
.. | .. |
---|
355 | 450 | |
---|
356 | 451 | config_group_init_type_name(&stm->policy->group, name, |
---|
357 | 452 | &stp_policy_type); |
---|
358 | | - stm->policy->stm = stm; |
---|
359 | 453 | |
---|
| 454 | + stm->pdrv = pdrv; |
---|
| 455 | + stm->pdrv_node_type = pdrv_node_type; |
---|
| 456 | + stm->policy->stm = stm; |
---|
360 | 457 | ret = &stm->policy->group; |
---|
361 | 458 | |
---|
362 | 459 | unlock_policy: |
---|
363 | 460 | mutex_unlock(&stm->policy_mutex); |
---|
364 | 461 | |
---|
365 | | - if (IS_ERR(ret)) |
---|
| 462 | + if (IS_ERR(ret)) { |
---|
| 463 | + /* |
---|
| 464 | + * pdrv and stm->pdrv at this point can be quite different, |
---|
| 465 | + * and only one of them needs to be 'put' |
---|
| 466 | + */ |
---|
| 467 | + stm_put_protocol(pdrv); |
---|
366 | 468 | stm_put_device(stm); |
---|
| 469 | + } |
---|
367 | 470 | |
---|
368 | 471 | return ret; |
---|
369 | 472 | } |
---|
370 | 473 | |
---|
371 | | -static struct configfs_group_operations stp_policies_group_ops = { |
---|
372 | | - .make_group = stp_policies_make, |
---|
| 474 | +static struct configfs_group_operations stp_policy_root_group_ops = { |
---|
| 475 | + .make_group = stp_policy_make, |
---|
373 | 476 | }; |
---|
374 | 477 | |
---|
375 | | -static const struct config_item_type stp_policies_type = { |
---|
376 | | - .ct_group_ops = &stp_policies_group_ops, |
---|
| 478 | +static const struct config_item_type stp_policy_root_type = { |
---|
| 479 | + .ct_group_ops = &stp_policy_root_group_ops, |
---|
377 | 480 | .ct_owner = THIS_MODULE, |
---|
378 | 481 | }; |
---|
379 | 482 | |
---|
.. | .. |
---|
381 | 484 | .su_group = { |
---|
382 | 485 | .cg_item = { |
---|
383 | 486 | .ci_namebuf = "stp-policy", |
---|
384 | | - .ci_type = &stp_policies_type, |
---|
| 487 | + .ci_type = &stp_policy_root_type, |
---|
385 | 488 | }, |
---|
386 | 489 | }, |
---|
387 | 490 | }; |
---|
.. | .. |
---|
392 | 495 | static struct stp_policy_node * |
---|
393 | 496 | __stp_policy_node_lookup(struct stp_policy *policy, char *s) |
---|
394 | 497 | { |
---|
395 | | - struct stp_policy_node *policy_node, *ret; |
---|
| 498 | + struct stp_policy_node *policy_node, *ret = NULL; |
---|
396 | 499 | struct list_head *head = &policy->group.cg_children; |
---|
397 | 500 | struct config_item *item; |
---|
398 | 501 | char *start, *end = s; |
---|
399 | 502 | |
---|
400 | 503 | if (list_empty(head)) |
---|
401 | 504 | return NULL; |
---|
402 | | - |
---|
403 | | - /* return the first entry if everything else fails */ |
---|
404 | | - item = list_entry(head->next, struct config_item, ci_entry); |
---|
405 | | - ret = to_stp_policy_node(item); |
---|
406 | 505 | |
---|
407 | 506 | next: |
---|
408 | 507 | for (;;) { |
---|
.. | .. |
---|
449 | 548 | |
---|
450 | 549 | if (policy_node) |
---|
451 | 550 | config_item_get(&policy_node->group.cg_item); |
---|
452 | | - mutex_unlock(&stp_policy_subsys.su_mutex); |
---|
| 551 | + else |
---|
| 552 | + mutex_unlock(&stp_policy_subsys.su_mutex); |
---|
453 | 553 | |
---|
454 | 554 | return policy_node; |
---|
455 | 555 | } |
---|
456 | 556 | |
---|
457 | 557 | void stp_policy_node_put(struct stp_policy_node *policy_node) |
---|
458 | 558 | { |
---|
| 559 | + lockdep_assert_held(&stp_policy_subsys.su_mutex); |
---|
| 560 | + |
---|
| 561 | + mutex_unlock(&stp_policy_subsys.su_mutex); |
---|
459 | 562 | config_item_put(&policy_node->group.cg_item); |
---|
460 | 563 | } |
---|
461 | 564 | |
---|
462 | 565 | int __init stp_configfs_init(void) |
---|
463 | 566 | { |
---|
464 | | - int err; |
---|
465 | | - |
---|
466 | 567 | config_group_init(&stp_policy_subsys.su_group); |
---|
467 | 568 | mutex_init(&stp_policy_subsys.su_mutex); |
---|
468 | | - err = configfs_register_subsystem(&stp_policy_subsys); |
---|
469 | | - |
---|
470 | | - return err; |
---|
| 569 | + return configfs_register_subsystem(&stp_policy_subsys); |
---|
471 | 570 | } |
---|
472 | 571 | |
---|
473 | 572 | void __exit stp_configfs_exit(void) |
---|