aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2011-04-18 03:43:25 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:49:04 -0500
commit71932efc1cfccfe1cc8e48b21f8cea5fbbc80e24 (patch)
treed73462e187f7469493d2cacfbddfce14c876c25a /drivers/block/drbd/drbd_nl.c
parent302bdeae49842cbd2faec8203f49b1c4ef20294d (diff)
drbd: allow status dump request all volumes of a specific resource
We had drbd_adm_get_status (one single volume), and drbd_adm_get_status_all (dump of all volumes of all resources). This enhances the latter to be able to dump all volumes of just one specific resource. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r--drivers/block/drbd/drbd_nl.c70
1 files changed, 66 insertions, 4 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index f86e882efcac..fff11ae79f15 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -2598,7 +2598,7 @@ out:
2598 return 0; 2598 return 0;
2599} 2599}
2600 2600
2601int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) 2601int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
2602{ 2602{
2603 struct drbd_conf *mdev; 2603 struct drbd_conf *mdev;
2604 struct drbd_genlmsghdr *dh; 2604 struct drbd_genlmsghdr *dh;
@@ -2616,6 +2616,9 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
2616 * where tconn is cb->args[0]; 2616 * where tconn is cb->args[0];
2617 * and i is cb->args[1]; 2617 * and i is cb->args[1];
2618 * 2618 *
2619 * cb->args[2] indicates if we shall loop over all resources,
2620 * or just dump all volumes of a single resource.
2621 *
2619 * This may miss entries inserted after this dump started, 2622 * This may miss entries inserted after this dump started,
2620 * or entries deleted before they are reached. 2623 * or entries deleted before they are reached.
2621 * 2624 *
@@ -2626,7 +2629,6 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
2626 2629
2627 /* synchronize with drbd_new_tconn/drbd_free_tconn */ 2630 /* synchronize with drbd_new_tconn/drbd_free_tconn */
2628 down_read(&drbd_cfg_rwsem); 2631 down_read(&drbd_cfg_rwsem);
2629next_tconn:
2630 /* revalidate iterator position */ 2632 /* revalidate iterator position */
2631 list_for_each_entry(tmp, &drbd_tconns, all_tconn) { 2633 list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
2632 if (pos == NULL) { 2634 if (pos == NULL) {
@@ -2641,16 +2643,22 @@ next_tconn:
2641 } 2643 }
2642 } 2644 }
2643 if (tconn) { 2645 if (tconn) {
2646next_tconn:
2644 mdev = idr_get_next(&tconn->volumes, &volume); 2647 mdev = idr_get_next(&tconn->volumes, &volume);
2645 if (!mdev) { 2648 if (!mdev) {
2646 /* No more volumes to dump on this tconn. 2649 /* No more volumes to dump on this tconn.
2647 * Advance tconn iterator. */ 2650 * Advance tconn iterator. */
2648 pos = list_entry(tconn->all_tconn.next, 2651 pos = list_entry(tconn->all_tconn.next,
2649 struct drbd_tconn, all_tconn); 2652 struct drbd_tconn, all_tconn);
2650 /* But, did we dump any volume on this tconn yet? */ 2653 /* Did we dump any volume on this tconn yet? */
2651 if (volume != 0) { 2654 if (volume != 0) {
2652 tconn = NULL; 2655 /* If we reached the end of the list,
2656 * or only a single resource dump was requested,
2657 * we are done. */
2658 if (&pos->all_tconn == &drbd_tconns || cb->args[2])
2659 goto out;
2653 volume = 0; 2660 volume = 0;
2661 tconn = pos;
2654 goto next_tconn; 2662 goto next_tconn;
2655 } 2663 }
2656 } 2664 }
@@ -2696,6 +2704,60 @@ out:
2696 return skb->len; 2704 return skb->len;
2697} 2705}
2698 2706
2707/*
2708 * Request status of all resources, or of all volumes within a single resource.
2709 *
2710 * This is a dump, as the answer may not fit in a single reply skb otherwise.
2711 * Which means we cannot use the family->attrbuf or other such members, because
2712 * dump is NOT protected by the genl_lock(). During dump, we only have access
2713 * to the incoming skb, and need to opencode "parsing" of the nlattr payload.
2714 *
2715 * Once things are setup properly, we call into get_one_status().
2716 */
2717int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
2718{
2719 const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ;
2720 struct nlattr *nla;
2721 const char *conn_name;
2722 struct drbd_tconn *tconn;
2723
2724 /* Is this a followup call? */
2725 if (cb->args[0]) {
2726 /* ... of a single resource dump,
2727 * and the resource iterator has been advanced already? */
2728 if (cb->args[2] && cb->args[2] != cb->args[0])
2729 return 0; /* DONE. */
2730 goto dump;
2731 }
2732
2733 /* First call (from netlink_dump_start). We need to figure out
2734 * which resource(s) the user wants us to dump. */
2735 nla = nla_find(nlmsg_attrdata(cb->nlh, hdrlen),
2736 nlmsg_attrlen(cb->nlh, hdrlen),
2737 DRBD_NLA_CFG_CONTEXT);
2738
2739 /* No explicit context given. Dump all. */
2740 if (!nla)
2741 goto dump;
2742 nla = nla_find_nested(nla, __nla_type(T_ctx_conn_name));
2743 /* context given, but no name present? */
2744 if (!nla)
2745 return -EINVAL;
2746 conn_name = nla_data(nla);
2747 tconn = conn_by_name(conn_name);
2748 if (!tconn)
2749 return -ENODEV;
2750
2751 /* prime iterators, and set "filter" mode mark:
2752 * only dump this tconn. */
2753 cb->args[0] = (long)tconn;
2754 /* cb->args[1] = 0; passed in this way. */
2755 cb->args[2] = (long)tconn;
2756
2757dump:
2758 return get_one_status(skb, cb);
2759}
2760
2699int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) 2761int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
2700{ 2762{
2701 enum drbd_ret_code retcode; 2763 enum drbd_ret_code retcode;