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>
This commit is contained in:
Lars Ellenberg 2011-04-18 09:43:25 +02:00 committed by Philipp Reisner
parent 302bdeae49
commit 71932efc1c
1 changed files with 66 additions and 4 deletions

View File

@ -2598,7 +2598,7 @@ out:
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_genlmsghdr *dh;
@ -2616,6 +2616,9 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
* where tconn is cb->args[0];
* 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,
* 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)
/* synchronize with drbd_new_tconn/drbd_free_tconn */
down_read(&drbd_cfg_rwsem);
next_tconn:
/* revalidate iterator position */
list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
if (pos == NULL) {
@ -2641,16 +2643,22 @@ next_tconn:
}
}
if (tconn) {
next_tconn:
mdev = idr_get_next(&tconn->volumes, &volume);
if (!mdev) {
/* No more volumes to dump on this tconn.
* Advance tconn iterator. */
pos = list_entry(tconn->all_tconn.next,
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) {
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;
tconn = pos;
goto next_tconn;
}
}
@ -2696,6 +2704,60 @@ out:
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)
{
enum drbd_ret_code retcode;