~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/devlink/resource.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
  4  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
  5  */
  6 
  7 #include "devl_internal.h"
  8 
  9 /**
 10  * struct devlink_resource - devlink resource
 11  * @name: name of the resource
 12  * @id: id, per devlink instance
 13  * @size: size of the resource
 14  * @size_new: updated size of the resource, reload is needed
 15  * @size_valid: valid in case the total size of the resource is valid
 16  *              including its children
 17  * @parent: parent resource
 18  * @size_params: size parameters
 19  * @list: parent list
 20  * @resource_list: list of child resources
 21  * @occ_get: occupancy getter callback
 22  * @occ_get_priv: occupancy getter callback priv
 23  */
 24 struct devlink_resource {
 25         const char *name;
 26         u64 id;
 27         u64 size;
 28         u64 size_new;
 29         bool size_valid;
 30         struct devlink_resource *parent;
 31         struct devlink_resource_size_params size_params;
 32         struct list_head list;
 33         struct list_head resource_list;
 34         devlink_resource_occ_get_t *occ_get;
 35         void *occ_get_priv;
 36 };
 37 
 38 static struct devlink_resource *
 39 devlink_resource_find(struct devlink *devlink,
 40                       struct devlink_resource *resource, u64 resource_id)
 41 {
 42         struct list_head *resource_list;
 43 
 44         if (resource)
 45                 resource_list = &resource->resource_list;
 46         else
 47                 resource_list = &devlink->resource_list;
 48 
 49         list_for_each_entry(resource, resource_list, list) {
 50                 struct devlink_resource *child_resource;
 51 
 52                 if (resource->id == resource_id)
 53                         return resource;
 54 
 55                 child_resource = devlink_resource_find(devlink, resource,
 56                                                        resource_id);
 57                 if (child_resource)
 58                         return child_resource;
 59         }
 60         return NULL;
 61 }
 62 
 63 static void
 64 devlink_resource_validate_children(struct devlink_resource *resource)
 65 {
 66         struct devlink_resource *child_resource;
 67         bool size_valid = true;
 68         u64 parts_size = 0;
 69 
 70         if (list_empty(&resource->resource_list))
 71                 goto out;
 72 
 73         list_for_each_entry(child_resource, &resource->resource_list, list)
 74                 parts_size += child_resource->size_new;
 75 
 76         if (parts_size > resource->size_new)
 77                 size_valid = false;
 78 out:
 79         resource->size_valid = size_valid;
 80 }
 81 
 82 static int
 83 devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
 84                                struct netlink_ext_ack *extack)
 85 {
 86         u64 reminder;
 87         int err = 0;
 88 
 89         if (size > resource->size_params.size_max) {
 90                 NL_SET_ERR_MSG(extack, "Size larger than maximum");
 91                 err = -EINVAL;
 92         }
 93 
 94         if (size < resource->size_params.size_min) {
 95                 NL_SET_ERR_MSG(extack, "Size smaller than minimum");
 96                 err = -EINVAL;
 97         }
 98 
 99         div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
100         if (reminder) {
101                 NL_SET_ERR_MSG(extack, "Wrong granularity");
102                 err = -EINVAL;
103         }
104 
105         return err;
106 }
107 
108 int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info)
109 {
110         struct devlink *devlink = info->user_ptr[0];
111         struct devlink_resource *resource;
112         u64 resource_id;
113         u64 size;
114         int err;
115 
116         if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_ID) ||
117             GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_SIZE))
118                 return -EINVAL;
119         resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
120 
121         resource = devlink_resource_find(devlink, NULL, resource_id);
122         if (!resource)
123                 return -EINVAL;
124 
125         size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
126         err = devlink_resource_validate_size(resource, size, info->extack);
127         if (err)
128                 return err;
129 
130         resource->size_new = size;
131         devlink_resource_validate_children(resource);
132         if (resource->parent)
133                 devlink_resource_validate_children(resource->parent);
134         return 0;
135 }
136 
137 static int
138 devlink_resource_size_params_put(struct devlink_resource *resource,
139                                  struct sk_buff *skb)
140 {
141         struct devlink_resource_size_params *size_params;
142 
143         size_params = &resource->size_params;
144         if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
145                               size_params->size_granularity, DEVLINK_ATTR_PAD) ||
146             nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
147                               size_params->size_max, DEVLINK_ATTR_PAD) ||
148             nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
149                               size_params->size_min, DEVLINK_ATTR_PAD) ||
150             nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
151                 return -EMSGSIZE;
152         return 0;
153 }
154 
155 static int devlink_resource_occ_put(struct devlink_resource *resource,
156                                     struct sk_buff *skb)
157 {
158         if (!resource->occ_get)
159                 return 0;
160         return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
161                                  resource->occ_get(resource->occ_get_priv),
162                                  DEVLINK_ATTR_PAD);
163 }
164 
165 static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
166                                 struct devlink_resource *resource)
167 {
168         struct devlink_resource *child_resource;
169         struct nlattr *child_resource_attr;
170         struct nlattr *resource_attr;
171 
172         resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
173         if (!resource_attr)
174                 return -EMSGSIZE;
175 
176         if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
177             nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
178                               DEVLINK_ATTR_PAD) ||
179             nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
180                               DEVLINK_ATTR_PAD))
181                 goto nla_put_failure;
182         if (resource->size != resource->size_new &&
183             nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
184                               resource->size_new, DEVLINK_ATTR_PAD))
185                 goto nla_put_failure;
186         if (devlink_resource_occ_put(resource, skb))
187                 goto nla_put_failure;
188         if (devlink_resource_size_params_put(resource, skb))
189                 goto nla_put_failure;
190         if (list_empty(&resource->resource_list))
191                 goto out;
192 
193         if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
194                        resource->size_valid))
195                 goto nla_put_failure;
196 
197         child_resource_attr = nla_nest_start_noflag(skb,
198                                                     DEVLINK_ATTR_RESOURCE_LIST);
199         if (!child_resource_attr)
200                 goto nla_put_failure;
201 
202         list_for_each_entry(child_resource, &resource->resource_list, list) {
203                 if (devlink_resource_put(devlink, skb, child_resource))
204                         goto resource_put_failure;
205         }
206 
207         nla_nest_end(skb, child_resource_attr);
208 out:
209         nla_nest_end(skb, resource_attr);
210         return 0;
211 
212 resource_put_failure:
213         nla_nest_cancel(skb, child_resource_attr);
214 nla_put_failure:
215         nla_nest_cancel(skb, resource_attr);
216         return -EMSGSIZE;
217 }
218 
219 static int devlink_resource_fill(struct genl_info *info,
220                                  enum devlink_command cmd, int flags)
221 {
222         struct devlink *devlink = info->user_ptr[0];
223         struct devlink_resource *resource;
224         struct nlattr *resources_attr;
225         struct sk_buff *skb = NULL;
226         struct nlmsghdr *nlh;
227         bool incomplete;
228         void *hdr;
229         int i;
230         int err;
231 
232         resource = list_first_entry(&devlink->resource_list,
233                                     struct devlink_resource, list);
234 start_again:
235         err = devlink_nl_msg_reply_and_new(&skb, info);
236         if (err)
237                 return err;
238 
239         hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
240                           &devlink_nl_family, NLM_F_MULTI, cmd);
241         if (!hdr) {
242                 nlmsg_free(skb);
243                 return -EMSGSIZE;
244         }
245 
246         if (devlink_nl_put_handle(skb, devlink))
247                 goto nla_put_failure;
248 
249         resources_attr = nla_nest_start_noflag(skb,
250                                                DEVLINK_ATTR_RESOURCE_LIST);
251         if (!resources_attr)
252                 goto nla_put_failure;
253 
254         incomplete = false;
255         i = 0;
256         list_for_each_entry_from(resource, &devlink->resource_list, list) {
257                 err = devlink_resource_put(devlink, skb, resource);
258                 if (err) {
259                         if (!i)
260                                 goto err_resource_put;
261                         incomplete = true;
262                         break;
263                 }
264                 i++;
265         }
266         nla_nest_end(skb, resources_attr);
267         genlmsg_end(skb, hdr);
268         if (incomplete)
269                 goto start_again;
270 send_done:
271         nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
272                         NLMSG_DONE, 0, flags | NLM_F_MULTI);
273         if (!nlh) {
274                 err = devlink_nl_msg_reply_and_new(&skb, info);
275                 if (err)
276                         return err;
277                 goto send_done;
278         }
279         return genlmsg_reply(skb, info);
280 
281 nla_put_failure:
282         err = -EMSGSIZE;
283 err_resource_put:
284         nlmsg_free(skb);
285         return err;
286 }
287 
288 int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
289 {
290         struct devlink *devlink = info->user_ptr[0];
291 
292         if (list_empty(&devlink->resource_list))
293                 return -EOPNOTSUPP;
294 
295         return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
296 }
297 
298 int devlink_resources_validate(struct devlink *devlink,
299                                struct devlink_resource *resource,
300                                struct genl_info *info)
301 {
302         struct list_head *resource_list;
303         int err = 0;
304 
305         if (resource)
306                 resource_list = &resource->resource_list;
307         else
308                 resource_list = &devlink->resource_list;
309 
310         list_for_each_entry(resource, resource_list, list) {
311                 if (!resource->size_valid)
312                         return -EINVAL;
313                 err = devlink_resources_validate(devlink, resource, info);
314                 if (err)
315                         return err;
316         }
317         return err;
318 }
319 
320 /**
321  * devl_resource_register - devlink resource register
322  *
323  * @devlink: devlink
324  * @resource_name: resource's name
325  * @resource_size: resource's size
326  * @resource_id: resource's id
327  * @parent_resource_id: resource's parent id
328  * @size_params: size parameters
329  *
330  * Generic resources should reuse the same names across drivers.
331  * Please see the generic resources list at:
332  * Documentation/networking/devlink/devlink-resource.rst
333  */
334 int devl_resource_register(struct devlink *devlink,
335                            const char *resource_name,
336                            u64 resource_size,
337                            u64 resource_id,
338                            u64 parent_resource_id,
339                            const struct devlink_resource_size_params *size_params)
340 {
341         struct devlink_resource *resource;
342         struct list_head *resource_list;
343         bool top_hierarchy;
344 
345         lockdep_assert_held(&devlink->lock);
346 
347         top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
348 
349         resource = devlink_resource_find(devlink, NULL, resource_id);
350         if (resource)
351                 return -EINVAL;
352 
353         resource = kzalloc(sizeof(*resource), GFP_KERNEL);
354         if (!resource)
355                 return -ENOMEM;
356 
357         if (top_hierarchy) {
358                 resource_list = &devlink->resource_list;
359         } else {
360                 struct devlink_resource *parent_resource;
361 
362                 parent_resource = devlink_resource_find(devlink, NULL,
363                                                         parent_resource_id);
364                 if (parent_resource) {
365                         resource_list = &parent_resource->resource_list;
366                         resource->parent = parent_resource;
367                 } else {
368                         kfree(resource);
369                         return -EINVAL;
370                 }
371         }
372 
373         resource->name = resource_name;
374         resource->size = resource_size;
375         resource->size_new = resource_size;
376         resource->id = resource_id;
377         resource->size_valid = true;
378         memcpy(&resource->size_params, size_params,
379                sizeof(resource->size_params));
380         INIT_LIST_HEAD(&resource->resource_list);
381         list_add_tail(&resource->list, resource_list);
382 
383         return 0;
384 }
385 EXPORT_SYMBOL_GPL(devl_resource_register);
386 
387 /**
388  *      devlink_resource_register - devlink resource register
389  *
390  *      @devlink: devlink
391  *      @resource_name: resource's name
392  *      @resource_size: resource's size
393  *      @resource_id: resource's id
394  *      @parent_resource_id: resource's parent id
395  *      @size_params: size parameters
396  *
397  *      Generic resources should reuse the same names across drivers.
398  *      Please see the generic resources list at:
399  *      Documentation/networking/devlink/devlink-resource.rst
400  *
401  *      Context: Takes and release devlink->lock <mutex>.
402  */
403 int devlink_resource_register(struct devlink *devlink,
404                               const char *resource_name,
405                               u64 resource_size,
406                               u64 resource_id,
407                               u64 parent_resource_id,
408                               const struct devlink_resource_size_params *size_params)
409 {
410         int err;
411 
412         devl_lock(devlink);
413         err = devl_resource_register(devlink, resource_name, resource_size,
414                                      resource_id, parent_resource_id, size_params);
415         devl_unlock(devlink);
416         return err;
417 }
418 EXPORT_SYMBOL_GPL(devlink_resource_register);
419 
420 static void devlink_resource_unregister(struct devlink *devlink,
421                                         struct devlink_resource *resource)
422 {
423         struct devlink_resource *tmp, *child_resource;
424 
425         list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
426                                  list) {
427                 devlink_resource_unregister(devlink, child_resource);
428                 list_del(&child_resource->list);
429                 kfree(child_resource);
430         }
431 }
432 
433 /**
434  * devl_resources_unregister - free all resources
435  *
436  * @devlink: devlink
437  */
438 void devl_resources_unregister(struct devlink *devlink)
439 {
440         struct devlink_resource *tmp, *child_resource;
441 
442         lockdep_assert_held(&devlink->lock);
443 
444         list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list,
445                                  list) {
446                 devlink_resource_unregister(devlink, child_resource);
447                 list_del(&child_resource->list);
448                 kfree(child_resource);
449         }
450 }
451 EXPORT_SYMBOL_GPL(devl_resources_unregister);
452 
453 /**
454  *      devlink_resources_unregister - free all resources
455  *
456  *      @devlink: devlink
457  *
458  *      Context: Takes and release devlink->lock <mutex>.
459  */
460 void devlink_resources_unregister(struct devlink *devlink)
461 {
462         devl_lock(devlink);
463         devl_resources_unregister(devlink);
464         devl_unlock(devlink);
465 }
466 EXPORT_SYMBOL_GPL(devlink_resources_unregister);
467 
468 /**
469  * devl_resource_size_get - get and update size
470  *
471  * @devlink: devlink
472  * @resource_id: the requested resource id
473  * @p_resource_size: ptr to update
474  */
475 int devl_resource_size_get(struct devlink *devlink,
476                            u64 resource_id,
477                            u64 *p_resource_size)
478 {
479         struct devlink_resource *resource;
480 
481         lockdep_assert_held(&devlink->lock);
482 
483         resource = devlink_resource_find(devlink, NULL, resource_id);
484         if (!resource)
485                 return -EINVAL;
486         *p_resource_size = resource->size_new;
487         resource->size = resource->size_new;
488         return 0;
489 }
490 EXPORT_SYMBOL_GPL(devl_resource_size_get);
491 
492 /**
493  * devl_resource_occ_get_register - register occupancy getter
494  *
495  * @devlink: devlink
496  * @resource_id: resource id
497  * @occ_get: occupancy getter callback
498  * @occ_get_priv: occupancy getter callback priv
499  */
500 void devl_resource_occ_get_register(struct devlink *devlink,
501                                     u64 resource_id,
502                                     devlink_resource_occ_get_t *occ_get,
503                                     void *occ_get_priv)
504 {
505         struct devlink_resource *resource;
506 
507         lockdep_assert_held(&devlink->lock);
508 
509         resource = devlink_resource_find(devlink, NULL, resource_id);
510         if (WARN_ON(!resource))
511                 return;
512         WARN_ON(resource->occ_get);
513 
514         resource->occ_get = occ_get;
515         resource->occ_get_priv = occ_get_priv;
516 }
517 EXPORT_SYMBOL_GPL(devl_resource_occ_get_register);
518 
519 /**
520  *      devlink_resource_occ_get_register - register occupancy getter
521  *
522  *      @devlink: devlink
523  *      @resource_id: resource id
524  *      @occ_get: occupancy getter callback
525  *      @occ_get_priv: occupancy getter callback priv
526  *
527  *      Context: Takes and release devlink->lock <mutex>.
528  */
529 void devlink_resource_occ_get_register(struct devlink *devlink,
530                                        u64 resource_id,
531                                        devlink_resource_occ_get_t *occ_get,
532                                        void *occ_get_priv)
533 {
534         devl_lock(devlink);
535         devl_resource_occ_get_register(devlink, resource_id,
536                                        occ_get, occ_get_priv);
537         devl_unlock(devlink);
538 }
539 EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
540 
541 /**
542  * devl_resource_occ_get_unregister - unregister occupancy getter
543  *
544  * @devlink: devlink
545  * @resource_id: resource id
546  */
547 void devl_resource_occ_get_unregister(struct devlink *devlink,
548                                       u64 resource_id)
549 {
550         struct devlink_resource *resource;
551 
552         lockdep_assert_held(&devlink->lock);
553 
554         resource = devlink_resource_find(devlink, NULL, resource_id);
555         if (WARN_ON(!resource))
556                 return;
557         WARN_ON(!resource->occ_get);
558 
559         resource->occ_get = NULL;
560         resource->occ_get_priv = NULL;
561 }
562 EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
563 
564 /**
565  *      devlink_resource_occ_get_unregister - unregister occupancy getter
566  *
567  *      @devlink: devlink
568  *      @resource_id: resource id
569  *
570  *      Context: Takes and release devlink->lock <mutex>.
571  */
572 void devlink_resource_occ_get_unregister(struct devlink *devlink,
573                                          u64 resource_id)
574 {
575         devl_lock(devlink);
576         devl_resource_occ_get_unregister(devlink, resource_id);
577         devl_unlock(devlink);
578 }
579 EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
580 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php