Commit 71932efc authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Philipp Reisner

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: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 302bdeae
...@@ -2598,7 +2598,7 @@ int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info) ...@@ -2598,7 +2598,7 @@ int drbd_adm_get_status(struct sk_buff *skb, struct genl_info *info)
return 0; return 0;
} }
int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
{ {
struct drbd_conf *mdev; struct drbd_conf *mdev;
struct drbd_genlmsghdr *dh; struct drbd_genlmsghdr *dh;
...@@ -2616,6 +2616,9 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2616,6 +2616,9 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
* where tconn is cb->args[0]; * where tconn is cb->args[0];
* and i is cb->args[1]; * and i is cb->args[1];
* *
* cb->args[2] indicates if we shall loop over all resources,
* or just dump all volumes of a single resource.
*
* This may miss entries inserted after this dump started, * This may miss entries inserted after this dump started,
* or entries deleted before they are reached. * or entries deleted before they are reached.
* *
...@@ -2626,7 +2629,6 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2626,7 +2629,6 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
/* synchronize with drbd_new_tconn/drbd_free_tconn */ /* synchronize with drbd_new_tconn/drbd_free_tconn */
down_read(&drbd_cfg_rwsem); down_read(&drbd_cfg_rwsem);
next_tconn:
/* revalidate iterator position */ /* revalidate iterator position */
list_for_each_entry(tmp, &drbd_tconns, all_tconn) { list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
if (pos == NULL) { if (pos == NULL) {
...@@ -2641,16 +2643,22 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2641,16 +2643,22 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
} }
} }
if (tconn) { if (tconn) {
next_tconn:
mdev = idr_get_next(&tconn->volumes, &volume); mdev = idr_get_next(&tconn->volumes, &volume);
if (!mdev) { if (!mdev) {
/* No more volumes to dump on this tconn. /* No more volumes to dump on this tconn.
* Advance tconn iterator. */ * Advance tconn iterator. */
pos = list_entry(tconn->all_tconn.next, pos = list_entry(tconn->all_tconn.next,
struct drbd_tconn, all_tconn); struct drbd_tconn, all_tconn);
/* But, did we dump any volume on this tconn yet? */ /* Did we dump any volume on this tconn yet? */
if (volume != 0) { if (volume != 0) {
tconn = NULL; /* If we reached the end of the list,
* or only a single resource dump was requested,
* we are done. */
if (&pos->all_tconn == &drbd_tconns || cb->args[2])
goto out;
volume = 0; volume = 0;
tconn = pos;
goto next_tconn; goto next_tconn;
} }
} }
...@@ -2696,6 +2704,60 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2696,6 +2704,60 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
/*
* Request status of all resources, or of all volumes within a single resource.
*
* This is a dump, as the answer may not fit in a single reply skb otherwise.
* Which means we cannot use the family->attrbuf or other such members, because
* dump is NOT protected by the genl_lock(). During dump, we only have access
* to the incoming skb, and need to opencode "parsing" of the nlattr payload.
*
* Once things are setup properly, we call into get_one_status().
*/
int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
{
const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ;
struct nlattr *nla;
const char *conn_name;
struct drbd_tconn *tconn;
/* Is this a followup call? */
if (cb->args[0]) {
/* ... of a single resource dump,
* and the resource iterator has been advanced already? */
if (cb->args[2] && cb->args[2] != cb->args[0])
return 0; /* DONE. */
goto dump;
}
/* First call (from netlink_dump_start). We need to figure out
* which resource(s) the user wants us to dump. */
nla = nla_find(nlmsg_attrdata(cb->nlh, hdrlen),
nlmsg_attrlen(cb->nlh, hdrlen),
DRBD_NLA_CFG_CONTEXT);
/* No explicit context given. Dump all. */
if (!nla)
goto dump;
nla = nla_find_nested(nla, __nla_type(T_ctx_conn_name));
/* context given, but no name present? */
if (!nla)
return -EINVAL;
conn_name = nla_data(nla);
tconn = conn_by_name(conn_name);
if (!tconn)
return -ENODEV;
/* prime iterators, and set "filter" mode mark:
* only dump this tconn. */
cb->args[0] = (long)tconn;
/* cb->args[1] = 0; passed in this way. */
cb->args[2] = (long)tconn;
dump:
return get_one_status(skb, cb);
}
int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info) int drbd_adm_get_timeout_type(struct sk_buff *skb, struct genl_info *info)
{ {
enum drbd_ret_code retcode; enum drbd_ret_code retcode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment