diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2011-04-18 03:43:25 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:49:04 -0500 |
commit | 71932efc1cfccfe1cc8e48b21f8cea5fbbc80e24 (patch) | |
tree | d73462e187f7469493d2cacfbddfce14c876c25a /drivers/block/drbd/drbd_nl.c | |
parent | 302bdeae49842cbd2faec8203f49b1c4ef20294d (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.c | 70 |
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 | ||
2601 | int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) | 2601 | int 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); |
2629 | next_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) { |
2646 | next_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 | */ | ||
2717 | int 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 | |||
2757 | dump: | ||
2758 | return get_one_status(skb, cb); | ||
2759 | } | ||
2760 | |||
2699 | int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) | 2761 | int 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; |