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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ 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 struct devlink_region {
 10         struct devlink *devlink;
 11         struct devlink_port *port;
 12         struct list_head list;
 13         union {
 14                 const struct devlink_region_ops *ops;
 15                 const struct devlink_port_region_ops *port_ops;
 16         };
 17         struct mutex snapshot_lock; /* protects snapshot_list,
 18                                      * max_snapshots and cur_snapshots
 19                                      * consistency.
 20                                      */
 21         struct list_head snapshot_list;
 22         u32 max_snapshots;
 23         u32 cur_snapshots;
 24         u64 size;
 25 };
 26 
 27 struct devlink_snapshot {
 28         struct list_head list;
 29         struct devlink_region *region;
 30         u8 *data;
 31         u32 id;
 32 };
 33 
 34 static struct devlink_region *
 35 devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
 36 {
 37         struct devlink_region *region;
 38 
 39         list_for_each_entry(region, &devlink->region_list, list)
 40                 if (!strcmp(region->ops->name, region_name))
 41                         return region;
 42 
 43         return NULL;
 44 }
 45 
 46 static struct devlink_region *
 47 devlink_port_region_get_by_name(struct devlink_port *port,
 48                                 const char *region_name)
 49 {
 50         struct devlink_region *region;
 51 
 52         list_for_each_entry(region, &port->region_list, list)
 53                 if (!strcmp(region->ops->name, region_name))
 54                         return region;
 55 
 56         return NULL;
 57 }
 58 
 59 static struct devlink_snapshot *
 60 devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
 61 {
 62         struct devlink_snapshot *snapshot;
 63 
 64         list_for_each_entry(snapshot, &region->snapshot_list, list)
 65                 if (snapshot->id == id)
 66                         return snapshot;
 67 
 68         return NULL;
 69 }
 70 
 71 static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
 72                                              struct devlink *devlink,
 73                                              struct devlink_snapshot *snapshot)
 74 {
 75         struct nlattr *snap_attr;
 76         int err;
 77 
 78         snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
 79         if (!snap_attr)
 80                 return -EINVAL;
 81 
 82         err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
 83         if (err)
 84                 goto nla_put_failure;
 85 
 86         nla_nest_end(msg, snap_attr);
 87         return 0;
 88 
 89 nla_put_failure:
 90         nla_nest_cancel(msg, snap_attr);
 91         return err;
 92 }
 93 
 94 static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
 95                                               struct devlink *devlink,
 96                                               struct devlink_region *region)
 97 {
 98         struct devlink_snapshot *snapshot;
 99         struct nlattr *snapshots_attr;
100         int err;
101 
102         snapshots_attr = nla_nest_start_noflag(msg,
103                                                DEVLINK_ATTR_REGION_SNAPSHOTS);
104         if (!snapshots_attr)
105                 return -EINVAL;
106 
107         list_for_each_entry(snapshot, &region->snapshot_list, list) {
108                 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
109                 if (err)
110                         goto nla_put_failure;
111         }
112 
113         nla_nest_end(msg, snapshots_attr);
114         return 0;
115 
116 nla_put_failure:
117         nla_nest_cancel(msg, snapshots_attr);
118         return err;
119 }
120 
121 static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
122                                   enum devlink_command cmd, u32 portid,
123                                   u32 seq, int flags,
124                                   struct devlink_region *region)
125 {
126         void *hdr;
127         int err;
128 
129         hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
130         if (!hdr)
131                 return -EMSGSIZE;
132 
133         err = devlink_nl_put_handle(msg, devlink);
134         if (err)
135                 goto nla_put_failure;
136 
137         if (region->port) {
138                 err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
139                                   region->port->index);
140                 if (err)
141                         goto nla_put_failure;
142         }
143 
144         err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
145         if (err)
146                 goto nla_put_failure;
147 
148         err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
149                                 region->size,
150                                 DEVLINK_ATTR_PAD);
151         if (err)
152                 goto nla_put_failure;
153 
154         err = nla_put_u32(msg, DEVLINK_ATTR_REGION_MAX_SNAPSHOTS,
155                           region->max_snapshots);
156         if (err)
157                 goto nla_put_failure;
158 
159         err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
160         if (err)
161                 goto nla_put_failure;
162 
163         genlmsg_end(msg, hdr);
164         return 0;
165 
166 nla_put_failure:
167         genlmsg_cancel(msg, hdr);
168         return err;
169 }
170 
171 static struct sk_buff *
172 devlink_nl_region_notify_build(struct devlink_region *region,
173                                struct devlink_snapshot *snapshot,
174                                enum devlink_command cmd, u32 portid, u32 seq)
175 {
176         struct devlink *devlink = region->devlink;
177         struct sk_buff *msg;
178         void *hdr;
179         int err;
180 
181         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
182         if (!msg)
183                 return ERR_PTR(-ENOMEM);
184 
185         hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
186         if (!hdr) {
187                 err = -EMSGSIZE;
188                 goto out_free_msg;
189         }
190 
191         err = devlink_nl_put_handle(msg, devlink);
192         if (err)
193                 goto out_cancel_msg;
194 
195         if (region->port) {
196                 err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
197                                   region->port->index);
198                 if (err)
199                         goto out_cancel_msg;
200         }
201 
202         err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
203                              region->ops->name);
204         if (err)
205                 goto out_cancel_msg;
206 
207         if (snapshot) {
208                 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
209                                   snapshot->id);
210                 if (err)
211                         goto out_cancel_msg;
212         } else {
213                 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
214                                         region->size, DEVLINK_ATTR_PAD);
215                 if (err)
216                         goto out_cancel_msg;
217         }
218         genlmsg_end(msg, hdr);
219 
220         return msg;
221 
222 out_cancel_msg:
223         genlmsg_cancel(msg, hdr);
224 out_free_msg:
225         nlmsg_free(msg);
226         return ERR_PTR(err);
227 }
228 
229 static void devlink_nl_region_notify(struct devlink_region *region,
230                                      struct devlink_snapshot *snapshot,
231                                      enum devlink_command cmd)
232 {
233         struct devlink *devlink = region->devlink;
234         struct sk_buff *msg;
235 
236         WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
237 
238         if (!__devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
239                 return;
240 
241         msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
242         if (IS_ERR(msg))
243                 return;
244 
245         devlink_nl_notify_send(devlink, msg);
246 }
247 
248 void devlink_regions_notify_register(struct devlink *devlink)
249 {
250         struct devlink_region *region;
251 
252         list_for_each_entry(region, &devlink->region_list, list)
253                 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
254 }
255 
256 void devlink_regions_notify_unregister(struct devlink *devlink)
257 {
258         struct devlink_region *region;
259 
260         list_for_each_entry_reverse(region, &devlink->region_list, list)
261                 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
262 }
263 
264 /**
265  * __devlink_snapshot_id_increment - Increment number of snapshots using an id
266  *      @devlink: devlink instance
267  *      @id: the snapshot id
268  *
269  *      Track when a new snapshot begins using an id. Load the count for the
270  *      given id from the snapshot xarray, increment it, and store it back.
271  *
272  *      Called when a new snapshot is created with the given id.
273  *
274  *      The id *must* have been previously allocated by
275  *      devlink_region_snapshot_id_get().
276  *
277  *      Returns 0 on success, or an error on failure.
278  */
279 static int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
280 {
281         unsigned long count;
282         void *p;
283         int err;
284 
285         xa_lock(&devlink->snapshot_ids);
286         p = xa_load(&devlink->snapshot_ids, id);
287         if (WARN_ON(!p)) {
288                 err = -EINVAL;
289                 goto unlock;
290         }
291 
292         if (WARN_ON(!xa_is_value(p))) {
293                 err = -EINVAL;
294                 goto unlock;
295         }
296 
297         count = xa_to_value(p);
298         count++;
299 
300         err = xa_err(__xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
301                                 GFP_ATOMIC));
302 unlock:
303         xa_unlock(&devlink->snapshot_ids);
304         return err;
305 }
306 
307 /**
308  * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
309  *      @devlink: devlink instance
310  *      @id: the snapshot id
311  *
312  *      Track when a snapshot is deleted and stops using an id. Load the count
313  *      for the given id from the snapshot xarray, decrement it, and store it
314  *      back.
315  *
316  *      If the count reaches zero, erase this id from the xarray, freeing it
317  *      up for future re-use by devlink_region_snapshot_id_get().
318  *
319  *      Called when a snapshot using the given id is deleted, and when the
320  *      initial allocator of the id is finished using it.
321  */
322 static void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
323 {
324         unsigned long count;
325         void *p;
326 
327         xa_lock(&devlink->snapshot_ids);
328         p = xa_load(&devlink->snapshot_ids, id);
329         if (WARN_ON(!p))
330                 goto unlock;
331 
332         if (WARN_ON(!xa_is_value(p)))
333                 goto unlock;
334 
335         count = xa_to_value(p);
336 
337         if (count > 1) {
338                 count--;
339                 __xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
340                            GFP_ATOMIC);
341         } else {
342                 /* If this was the last user, we can erase this id */
343                 __xa_erase(&devlink->snapshot_ids, id);
344         }
345 unlock:
346         xa_unlock(&devlink->snapshot_ids);
347 }
348 
349 /**
350  *      __devlink_snapshot_id_insert - Insert a specific snapshot ID
351  *      @devlink: devlink instance
352  *      @id: the snapshot id
353  *
354  *      Mark the given snapshot id as used by inserting a zero value into the
355  *      snapshot xarray.
356  *
357  *      This must be called while holding the devlink instance lock. Unlike
358  *      devlink_snapshot_id_get, the initial reference count is zero, not one.
359  *      It is expected that the id will immediately be used before
360  *      releasing the devlink instance lock.
361  *
362  *      Returns zero on success, or an error code if the snapshot id could not
363  *      be inserted.
364  */
365 static int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
366 {
367         int err;
368 
369         xa_lock(&devlink->snapshot_ids);
370         if (xa_load(&devlink->snapshot_ids, id)) {
371                 xa_unlock(&devlink->snapshot_ids);
372                 return -EEXIST;
373         }
374         err = xa_err(__xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
375                                 GFP_ATOMIC));
376         xa_unlock(&devlink->snapshot_ids);
377         return err;
378 }
379 
380 /**
381  *      __devlink_region_snapshot_id_get - get snapshot ID
382  *      @devlink: devlink instance
383  *      @id: storage to return snapshot id
384  *
385  *      Allocates a new snapshot id. Returns zero on success, or a negative
386  *      error on failure. Must be called while holding the devlink instance
387  *      lock.
388  *
389  *      Snapshot IDs are tracked using an xarray which stores the number of
390  *      users of the snapshot id.
391  *
392  *      Note that the caller of this function counts as a 'user', in order to
393  *      avoid race conditions. The caller must release its hold on the
394  *      snapshot by using devlink_region_snapshot_id_put.
395  */
396 static int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
397 {
398         return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
399                         xa_limit_32b, GFP_KERNEL);
400 }
401 
402 /**
403  *      __devlink_region_snapshot_create - create a new snapshot
404  *      This will add a new snapshot of a region. The snapshot
405  *      will be stored on the region struct and can be accessed
406  *      from devlink. This is useful for future analyses of snapshots.
407  *      Multiple snapshots can be created on a region.
408  *      The @snapshot_id should be obtained using the getter function.
409  *
410  *      Must be called only while holding the region snapshot lock.
411  *
412  *      @region: devlink region of the snapshot
413  *      @data: snapshot data
414  *      @snapshot_id: snapshot id to be created
415  */
416 static int
417 __devlink_region_snapshot_create(struct devlink_region *region,
418                                  u8 *data, u32 snapshot_id)
419 {
420         struct devlink *devlink = region->devlink;
421         struct devlink_snapshot *snapshot;
422         int err;
423 
424         lockdep_assert_held(&region->snapshot_lock);
425 
426         /* check if region can hold one more snapshot */
427         if (region->cur_snapshots == region->max_snapshots)
428                 return -ENOSPC;
429 
430         if (devlink_region_snapshot_get_by_id(region, snapshot_id))
431                 return -EEXIST;
432 
433         snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
434         if (!snapshot)
435                 return -ENOMEM;
436 
437         err = __devlink_snapshot_id_increment(devlink, snapshot_id);
438         if (err)
439                 goto err_snapshot_id_increment;
440 
441         snapshot->id = snapshot_id;
442         snapshot->region = region;
443         snapshot->data = data;
444 
445         list_add_tail(&snapshot->list, &region->snapshot_list);
446 
447         region->cur_snapshots++;
448 
449         devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
450         return 0;
451 
452 err_snapshot_id_increment:
453         kfree(snapshot);
454         return err;
455 }
456 
457 static void devlink_region_snapshot_del(struct devlink_region *region,
458                                         struct devlink_snapshot *snapshot)
459 {
460         struct devlink *devlink = region->devlink;
461 
462         lockdep_assert_held(&region->snapshot_lock);
463 
464         devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
465         region->cur_snapshots--;
466         list_del(&snapshot->list);
467         region->ops->destructor(snapshot->data);
468         __devlink_snapshot_id_decrement(devlink, snapshot->id);
469         kfree(snapshot);
470 }
471 
472 int devlink_nl_region_get_doit(struct sk_buff *skb, struct genl_info *info)
473 {
474         struct devlink *devlink = info->user_ptr[0];
475         struct devlink_port *port = NULL;
476         struct devlink_region *region;
477         const char *region_name;
478         struct sk_buff *msg;
479         unsigned int index;
480         int err;
481 
482         if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME))
483                 return -EINVAL;
484 
485         if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
486                 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
487 
488                 port = devlink_port_get_by_index(devlink, index);
489                 if (!port)
490                         return -ENODEV;
491         }
492 
493         region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
494         if (port)
495                 region = devlink_port_region_get_by_name(port, region_name);
496         else
497                 region = devlink_region_get_by_name(devlink, region_name);
498 
499         if (!region)
500                 return -EINVAL;
501 
502         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
503         if (!msg)
504                 return -ENOMEM;
505 
506         err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
507                                      info->snd_portid, info->snd_seq, 0,
508                                      region);
509         if (err) {
510                 nlmsg_free(msg);
511                 return err;
512         }
513 
514         return genlmsg_reply(msg, info);
515 }
516 
517 static int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
518                                                  struct netlink_callback *cb,
519                                                  struct devlink_port *port,
520                                                  int *idx, int start, int flags)
521 {
522         struct devlink_region *region;
523         int err = 0;
524 
525         list_for_each_entry(region, &port->region_list, list) {
526                 if (*idx < start) {
527                         (*idx)++;
528                         continue;
529                 }
530                 err = devlink_nl_region_fill(msg, port->devlink,
531                                              DEVLINK_CMD_REGION_GET,
532                                              NETLINK_CB(cb->skb).portid,
533                                              cb->nlh->nlmsg_seq,
534                                              flags, region);
535                 if (err)
536                         goto out;
537                 (*idx)++;
538         }
539 
540 out:
541         return err;
542 }
543 
544 static int devlink_nl_region_get_dump_one(struct sk_buff *msg,
545                                           struct devlink *devlink,
546                                           struct netlink_callback *cb,
547                                           int flags)
548 {
549         struct devlink_nl_dump_state *state = devlink_dump_state(cb);
550         struct devlink_region *region;
551         struct devlink_port *port;
552         unsigned long port_index;
553         int idx = 0;
554         int err;
555 
556         list_for_each_entry(region, &devlink->region_list, list) {
557                 if (idx < state->idx) {
558                         idx++;
559                         continue;
560                 }
561                 err = devlink_nl_region_fill(msg, devlink,
562                                              DEVLINK_CMD_REGION_GET,
563                                              NETLINK_CB(cb->skb).portid,
564                                              cb->nlh->nlmsg_seq, flags,
565                                              region);
566                 if (err) {
567                         state->idx = idx;
568                         return err;
569                 }
570                 idx++;
571         }
572 
573         xa_for_each(&devlink->ports, port_index, port) {
574                 err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, &idx,
575                                                             state->idx, flags);
576                 if (err) {
577                         state->idx = idx;
578                         return err;
579                 }
580         }
581 
582         return 0;
583 }
584 
585 int devlink_nl_region_get_dumpit(struct sk_buff *skb,
586                                  struct netlink_callback *cb)
587 {
588         return devlink_nl_dumpit(skb, cb, devlink_nl_region_get_dump_one);
589 }
590 
591 int devlink_nl_region_del_doit(struct sk_buff *skb, struct genl_info *info)
592 {
593         struct devlink *devlink = info->user_ptr[0];
594         struct devlink_snapshot *snapshot;
595         struct devlink_port *port = NULL;
596         struct devlink_region *region;
597         const char *region_name;
598         unsigned int index;
599         u32 snapshot_id;
600 
601         if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME) ||
602             GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_SNAPSHOT_ID))
603                 return -EINVAL;
604 
605         region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
606         snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
607 
608         if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
609                 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
610 
611                 port = devlink_port_get_by_index(devlink, index);
612                 if (!port)
613                         return -ENODEV;
614         }
615 
616         if (port)
617                 region = devlink_port_region_get_by_name(port, region_name);
618         else
619                 region = devlink_region_get_by_name(devlink, region_name);
620 
621         if (!region)
622                 return -EINVAL;
623 
624         mutex_lock(&region->snapshot_lock);
625         snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
626         if (!snapshot) {
627                 mutex_unlock(&region->snapshot_lock);
628                 return -EINVAL;
629         }
630 
631         devlink_region_snapshot_del(region, snapshot);
632         mutex_unlock(&region->snapshot_lock);
633         return 0;
634 }
635 
636 int devlink_nl_region_new_doit(struct sk_buff *skb, struct genl_info *info)
637 {
638         struct devlink *devlink = info->user_ptr[0];
639         struct devlink_snapshot *snapshot;
640         struct devlink_port *port = NULL;
641         struct nlattr *snapshot_id_attr;
642         struct devlink_region *region;
643         const char *region_name;
644         unsigned int index;
645         u32 snapshot_id;
646         u8 *data;
647         int err;
648 
649         if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_REGION_NAME)) {
650                 NL_SET_ERR_MSG(info->extack, "No region name provided");
651                 return -EINVAL;
652         }
653 
654         region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
655 
656         if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
657                 index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
658 
659                 port = devlink_port_get_by_index(devlink, index);
660                 if (!port)
661                         return -ENODEV;
662         }
663 
664         if (port)
665                 region = devlink_port_region_get_by_name(port, region_name);
666         else
667                 region = devlink_region_get_by_name(devlink, region_name);
668 
669         if (!region) {
670                 NL_SET_ERR_MSG(info->extack, "The requested region does not exist");
671                 return -EINVAL;
672         }
673 
674         if (!region->ops->snapshot) {
675                 NL_SET_ERR_MSG(info->extack, "The requested region does not support taking an immediate snapshot");
676                 return -EOPNOTSUPP;
677         }
678 
679         mutex_lock(&region->snapshot_lock);
680 
681         if (region->cur_snapshots == region->max_snapshots) {
682                 NL_SET_ERR_MSG(info->extack, "The region has reached the maximum number of stored snapshots");
683                 err = -ENOSPC;
684                 goto unlock;
685         }
686 
687         snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
688         if (snapshot_id_attr) {
689                 snapshot_id = nla_get_u32(snapshot_id_attr);
690 
691                 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
692                         NL_SET_ERR_MSG(info->extack, "The requested snapshot id is already in use");
693                         err = -EEXIST;
694                         goto unlock;
695                 }
696 
697                 err = __devlink_snapshot_id_insert(devlink, snapshot_id);
698                 if (err)
699                         goto unlock;
700         } else {
701                 err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
702                 if (err) {
703                         NL_SET_ERR_MSG(info->extack, "Failed to allocate a new snapshot id");
704                         goto unlock;
705                 }
706         }
707 
708         if (port)
709                 err = region->port_ops->snapshot(port, region->port_ops,
710                                                  info->extack, &data);
711         else
712                 err = region->ops->snapshot(devlink, region->ops,
713                                             info->extack, &data);
714         if (err)
715                 goto err_snapshot_capture;
716 
717         err = __devlink_region_snapshot_create(region, data, snapshot_id);
718         if (err)
719                 goto err_snapshot_create;
720 
721         if (!snapshot_id_attr) {
722                 struct sk_buff *msg;
723 
724                 snapshot = devlink_region_snapshot_get_by_id(region,
725                                                              snapshot_id);
726                 if (WARN_ON(!snapshot)) {
727                         err = -EINVAL;
728                         goto unlock;
729                 }
730 
731                 msg = devlink_nl_region_notify_build(region, snapshot,
732                                                      DEVLINK_CMD_REGION_NEW,
733                                                      info->snd_portid,
734                                                      info->snd_seq);
735                 err = PTR_ERR_OR_ZERO(msg);
736                 if (err)
737                         goto err_notify;
738 
739                 err = genlmsg_reply(msg, info);
740                 if (err)
741                         goto err_notify;
742         }
743 
744         mutex_unlock(&region->snapshot_lock);
745         return 0;
746 
747 err_snapshot_create:
748         region->ops->destructor(data);
749 err_snapshot_capture:
750         __devlink_snapshot_id_decrement(devlink, snapshot_id);
751         mutex_unlock(&region->snapshot_lock);
752         return err;
753 
754 err_notify:
755         devlink_region_snapshot_del(region, snapshot);
756 unlock:
757         mutex_unlock(&region->snapshot_lock);
758         return err;
759 }
760 
761 static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
762                                                  u8 *chunk, u32 chunk_size,
763                                                  u64 addr)
764 {
765         struct nlattr *chunk_attr;
766         int err;
767 
768         chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
769         if (!chunk_attr)
770                 return -EINVAL;
771 
772         err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
773         if (err)
774                 goto nla_put_failure;
775 
776         err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
777                                 DEVLINK_ATTR_PAD);
778         if (err)
779                 goto nla_put_failure;
780 
781         nla_nest_end(msg, chunk_attr);
782         return 0;
783 
784 nla_put_failure:
785         nla_nest_cancel(msg, chunk_attr);
786         return err;
787 }
788 
789 #define DEVLINK_REGION_READ_CHUNK_SIZE 256
790 
791 typedef int devlink_chunk_fill_t(void *cb_priv, u8 *chunk, u32 chunk_size,
792                                  u64 curr_offset,
793                                  struct netlink_ext_ack *extack);
794 
795 static int
796 devlink_nl_region_read_fill(struct sk_buff *skb, devlink_chunk_fill_t *cb,
797                             void *cb_priv, u64 start_offset, u64 end_offset,
798                             u64 *new_offset, struct netlink_ext_ack *extack)
799 {
800         u64 curr_offset = start_offset;
801         int err = 0;
802         u8 *data;
803 
804         /* Allocate and re-use a single buffer */
805         data = kmalloc(DEVLINK_REGION_READ_CHUNK_SIZE, GFP_KERNEL);
806         if (!data)
807                 return -ENOMEM;
808 
809         *new_offset = start_offset;
810 
811         while (curr_offset < end_offset) {
812                 u32 data_size;
813 
814                 data_size = min_t(u32, end_offset - curr_offset,
815                                   DEVLINK_REGION_READ_CHUNK_SIZE);
816 
817                 err = cb(cb_priv, data, data_size, curr_offset, extack);
818                 if (err)
819                         break;
820 
821                 err = devlink_nl_cmd_region_read_chunk_fill(skb, data, data_size, curr_offset);
822                 if (err)
823                         break;
824 
825                 curr_offset += data_size;
826         }
827         *new_offset = curr_offset;
828 
829         kfree(data);
830 
831         return err;
832 }
833 
834 static int
835 devlink_region_snapshot_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
836                              u64 curr_offset,
837                              struct netlink_ext_ack __always_unused *extack)
838 {
839         struct devlink_snapshot *snapshot = cb_priv;
840 
841         memcpy(chunk, &snapshot->data[curr_offset], chunk_size);
842 
843         return 0;
844 }
845 
846 static int
847 devlink_region_port_direct_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
848                                 u64 curr_offset, struct netlink_ext_ack *extack)
849 {
850         struct devlink_region *region = cb_priv;
851 
852         return region->port_ops->read(region->port, region->port_ops, extack,
853                                       curr_offset, chunk_size, chunk);
854 }
855 
856 static int
857 devlink_region_direct_fill(void *cb_priv, u8 *chunk, u32 chunk_size,
858                            u64 curr_offset, struct netlink_ext_ack *extack)
859 {
860         struct devlink_region *region = cb_priv;
861 
862         return region->ops->read(region->devlink, region->ops, extack,
863                                  curr_offset, chunk_size, chunk);
864 }
865 
866 int devlink_nl_region_read_dumpit(struct sk_buff *skb,
867                                   struct netlink_callback *cb)
868 {
869         const struct genl_dumpit_info *info = genl_dumpit_info(cb);
870         struct devlink_nl_dump_state *state = devlink_dump_state(cb);
871         struct nlattr *chunks_attr, *region_attr, *snapshot_attr;
872         u64 ret_offset, start_offset, end_offset = U64_MAX;
873         struct nlattr **attrs = info->info.attrs;
874         struct devlink_port *port = NULL;
875         devlink_chunk_fill_t *region_cb;
876         struct devlink_region *region;
877         const char *region_name;
878         struct devlink *devlink;
879         unsigned int index;
880         void *region_cb_priv;
881         void *hdr;
882         int err;
883 
884         start_offset = state->start_offset;
885 
886         devlink = devlink_get_from_attrs_lock(sock_net(cb->skb->sk), attrs,
887                                               false);
888         if (IS_ERR(devlink))
889                 return PTR_ERR(devlink);
890 
891         if (!attrs[DEVLINK_ATTR_REGION_NAME]) {
892                 NL_SET_ERR_MSG(cb->extack, "No region name provided");
893                 err = -EINVAL;
894                 goto out_unlock;
895         }
896 
897         if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
898                 index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
899 
900                 port = devlink_port_get_by_index(devlink, index);
901                 if (!port) {
902                         err = -ENODEV;
903                         goto out_unlock;
904                 }
905         }
906 
907         region_attr = attrs[DEVLINK_ATTR_REGION_NAME];
908         region_name = nla_data(region_attr);
909 
910         if (port)
911                 region = devlink_port_region_get_by_name(port, region_name);
912         else
913                 region = devlink_region_get_by_name(devlink, region_name);
914 
915         if (!region) {
916                 NL_SET_ERR_MSG_ATTR(cb->extack, region_attr, "Requested region does not exist");
917                 err = -EINVAL;
918                 goto out_unlock;
919         }
920 
921         snapshot_attr = attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
922         if (!snapshot_attr) {
923                 if (!nla_get_flag(attrs[DEVLINK_ATTR_REGION_DIRECT])) {
924                         NL_SET_ERR_MSG(cb->extack, "No snapshot id provided");
925                         err = -EINVAL;
926                         goto out_unlock;
927                 }
928 
929                 if (!region->ops->read) {
930                         NL_SET_ERR_MSG(cb->extack, "Requested region does not support direct read");
931                         err = -EOPNOTSUPP;
932                         goto out_unlock;
933                 }
934 
935                 if (port)
936                         region_cb = &devlink_region_port_direct_fill;
937                 else
938                         region_cb = &devlink_region_direct_fill;
939                 region_cb_priv = region;
940         } else {
941                 struct devlink_snapshot *snapshot;
942                 u32 snapshot_id;
943 
944                 if (nla_get_flag(attrs[DEVLINK_ATTR_REGION_DIRECT])) {
945                         NL_SET_ERR_MSG_ATTR(cb->extack, snapshot_attr, "Direct region read does not use snapshot");
946                         err = -EINVAL;
947                         goto out_unlock;
948                 }
949 
950                 snapshot_id = nla_get_u32(snapshot_attr);
951                 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
952                 if (!snapshot) {
953                         NL_SET_ERR_MSG_ATTR(cb->extack, snapshot_attr, "Requested snapshot does not exist");
954                         err = -EINVAL;
955                         goto out_unlock;
956                 }
957                 region_cb = &devlink_region_snapshot_fill;
958                 region_cb_priv = snapshot;
959         }
960 
961         if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
962             attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
963                 if (!start_offset)
964                         start_offset =
965                                 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
966 
967                 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
968                 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
969         }
970 
971         if (end_offset > region->size)
972                 end_offset = region->size;
973 
974         /* return 0 if there is no further data to read */
975         if (start_offset == end_offset) {
976                 err = 0;
977                 goto out_unlock;
978         }
979 
980         hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
981                           &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
982                           DEVLINK_CMD_REGION_READ);
983         if (!hdr) {
984                 err = -EMSGSIZE;
985                 goto out_unlock;
986         }
987 
988         err = devlink_nl_put_handle(skb, devlink);
989         if (err)
990                 goto nla_put_failure;
991 
992         if (region->port) {
993                 err = nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
994                                   region->port->index);
995                 if (err)
996                         goto nla_put_failure;
997         }
998 
999         err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
1000         if (err)
1001                 goto nla_put_failure;
1002 
1003         chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
1004         if (!chunks_attr) {
1005                 err = -EMSGSIZE;
1006                 goto nla_put_failure;
1007         }
1008 
1009         err = devlink_nl_region_read_fill(skb, region_cb, region_cb_priv,
1010                                           start_offset, end_offset, &ret_offset,
1011                                           cb->extack);
1012 
1013         if (err && err != -EMSGSIZE)
1014                 goto nla_put_failure;
1015 
1016         /* Check if there was any progress done to prevent infinite loop */
1017         if (ret_offset == start_offset) {
1018                 err = -EINVAL;
1019                 goto nla_put_failure;
1020         }
1021 
1022         state->start_offset = ret_offset;
1023 
1024         nla_nest_end(skb, chunks_attr);
1025         genlmsg_end(skb, hdr);
1026         devl_unlock(devlink);
1027         devlink_put(devlink);
1028         return skb->len;
1029 
1030 nla_put_failure:
1031         genlmsg_cancel(skb, hdr);
1032 out_unlock:
1033         devl_unlock(devlink);
1034         devlink_put(devlink);
1035         return err;
1036 }
1037 
1038 /**
1039  * devl_region_create - create a new address region
1040  *
1041  * @devlink: devlink
1042  * @ops: region operations and name
1043  * @region_max_snapshots: Maximum supported number of snapshots for region
1044  * @region_size: size of region
1045  */
1046 struct devlink_region *devl_region_create(struct devlink *devlink,
1047                                           const struct devlink_region_ops *ops,
1048                                           u32 region_max_snapshots,
1049                                           u64 region_size)
1050 {
1051         struct devlink_region *region;
1052 
1053         devl_assert_locked(devlink);
1054 
1055         if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
1056                 return ERR_PTR(-EINVAL);
1057 
1058         if (devlink_region_get_by_name(devlink, ops->name))
1059                 return ERR_PTR(-EEXIST);
1060 
1061         region = kzalloc(sizeof(*region), GFP_KERNEL);
1062         if (!region)
1063                 return ERR_PTR(-ENOMEM);
1064 
1065         region->devlink = devlink;
1066         region->max_snapshots = region_max_snapshots;
1067         region->ops = ops;
1068         region->size = region_size;
1069         INIT_LIST_HEAD(&region->snapshot_list);
1070         mutex_init(&region->snapshot_lock);
1071         list_add_tail(&region->list, &devlink->region_list);
1072         devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
1073 
1074         return region;
1075 }
1076 EXPORT_SYMBOL_GPL(devl_region_create);
1077 
1078 /**
1079  *      devlink_region_create - create a new address region
1080  *
1081  *      @devlink: devlink
1082  *      @ops: region operations and name
1083  *      @region_max_snapshots: Maximum supported number of snapshots for region
1084  *      @region_size: size of region
1085  *
1086  *      Context: Takes and release devlink->lock <mutex>.
1087  */
1088 struct devlink_region *
1089 devlink_region_create(struct devlink *devlink,
1090                       const struct devlink_region_ops *ops,
1091                       u32 region_max_snapshots, u64 region_size)
1092 {
1093         struct devlink_region *region;
1094 
1095         devl_lock(devlink);
1096         region = devl_region_create(devlink, ops, region_max_snapshots,
1097                                     region_size);
1098         devl_unlock(devlink);
1099         return region;
1100 }
1101 EXPORT_SYMBOL_GPL(devlink_region_create);
1102 
1103 /**
1104  *      devlink_port_region_create - create a new address region for a port
1105  *
1106  *      @port: devlink port
1107  *      @ops: region operations and name
1108  *      @region_max_snapshots: Maximum supported number of snapshots for region
1109  *      @region_size: size of region
1110  *
1111  *      Context: Takes and release devlink->lock <mutex>.
1112  */
1113 struct devlink_region *
1114 devlink_port_region_create(struct devlink_port *port,
1115                            const struct devlink_port_region_ops *ops,
1116                            u32 region_max_snapshots, u64 region_size)
1117 {
1118         struct devlink *devlink = port->devlink;
1119         struct devlink_region *region;
1120         int err = 0;
1121 
1122         ASSERT_DEVLINK_PORT_INITIALIZED(port);
1123 
1124         if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
1125                 return ERR_PTR(-EINVAL);
1126 
1127         devl_lock(devlink);
1128 
1129         if (devlink_port_region_get_by_name(port, ops->name)) {
1130                 err = -EEXIST;
1131                 goto unlock;
1132         }
1133 
1134         region = kzalloc(sizeof(*region), GFP_KERNEL);
1135         if (!region) {
1136                 err = -ENOMEM;
1137                 goto unlock;
1138         }
1139 
1140         region->devlink = devlink;
1141         region->port = port;
1142         region->max_snapshots = region_max_snapshots;
1143         region->port_ops = ops;
1144         region->size = region_size;
1145         INIT_LIST_HEAD(&region->snapshot_list);
1146         mutex_init(&region->snapshot_lock);
1147         list_add_tail(&region->list, &port->region_list);
1148         devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
1149 
1150         devl_unlock(devlink);
1151         return region;
1152 
1153 unlock:
1154         devl_unlock(devlink);
1155         return ERR_PTR(err);
1156 }
1157 EXPORT_SYMBOL_GPL(devlink_port_region_create);
1158 
1159 /**
1160  * devl_region_destroy - destroy address region
1161  *
1162  * @region: devlink region to destroy
1163  */
1164 void devl_region_destroy(struct devlink_region *region)
1165 {
1166         struct devlink *devlink = region->devlink;
1167         struct devlink_snapshot *snapshot, *ts;
1168 
1169         devl_assert_locked(devlink);
1170 
1171         /* Free all snapshots of region */
1172         mutex_lock(&region->snapshot_lock);
1173         list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
1174                 devlink_region_snapshot_del(region, snapshot);
1175         mutex_unlock(&region->snapshot_lock);
1176 
1177         list_del(&region->list);
1178         mutex_destroy(&region->snapshot_lock);
1179 
1180         devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
1181         kfree(region);
1182 }
1183 EXPORT_SYMBOL_GPL(devl_region_destroy);
1184 
1185 /**
1186  *      devlink_region_destroy - destroy address region
1187  *
1188  *      @region: devlink region to destroy
1189  *
1190  *      Context: Takes and release devlink->lock <mutex>.
1191  */
1192 void devlink_region_destroy(struct devlink_region *region)
1193 {
1194         struct devlink *devlink = region->devlink;
1195 
1196         devl_lock(devlink);
1197         devl_region_destroy(region);
1198         devl_unlock(devlink);
1199 }
1200 EXPORT_SYMBOL_GPL(devlink_region_destroy);
1201 
1202 /**
1203  *      devlink_region_snapshot_id_get - get snapshot ID
1204  *
1205  *      This callback should be called when adding a new snapshot,
1206  *      Driver should use the same id for multiple snapshots taken
1207  *      on multiple regions at the same time/by the same trigger.
1208  *
1209  *      The caller of this function must use devlink_region_snapshot_id_put
1210  *      when finished creating regions using this id.
1211  *
1212  *      Returns zero on success, or a negative error code on failure.
1213  *
1214  *      @devlink: devlink
1215  *      @id: storage to return id
1216  */
1217 int devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
1218 {
1219         return __devlink_region_snapshot_id_get(devlink, id);
1220 }
1221 EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
1222 
1223 /**
1224  *      devlink_region_snapshot_id_put - put snapshot ID reference
1225  *
1226  *      This should be called by a driver after finishing creating snapshots
1227  *      with an id. Doing so ensures that the ID can later be released in the
1228  *      event that all snapshots using it have been destroyed.
1229  *
1230  *      @devlink: devlink
1231  *      @id: id to release reference on
1232  */
1233 void devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
1234 {
1235         __devlink_snapshot_id_decrement(devlink, id);
1236 }
1237 EXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
1238 
1239 /**
1240  *      devlink_region_snapshot_create - create a new snapshot
1241  *      This will add a new snapshot of a region. The snapshot
1242  *      will be stored on the region struct and can be accessed
1243  *      from devlink. This is useful for future analyses of snapshots.
1244  *      Multiple snapshots can be created on a region.
1245  *      The @snapshot_id should be obtained using the getter function.
1246  *
1247  *      @region: devlink region of the snapshot
1248  *      @data: snapshot data
1249  *      @snapshot_id: snapshot id to be created
1250  */
1251 int devlink_region_snapshot_create(struct devlink_region *region,
1252                                    u8 *data, u32 snapshot_id)
1253 {
1254         int err;
1255 
1256         mutex_lock(&region->snapshot_lock);
1257         err = __devlink_region_snapshot_create(region, data, snapshot_id);
1258         mutex_unlock(&region->snapshot_lock);
1259         return err;
1260 }
1261 EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
1262 

~ [ 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