summaryrefslogtreecommitdiff
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-06-08 22:17:38 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-02-17 16:44:53 +0100
commit77c556f663b7ac066268c94c18670ce93dec60c0 (patch)
treec05d7b93806b46528e4007ca2bf83ecfb2ec0671 /drivers/block/drbd/drbd_nl.c
parent05a10ec7900dbdba008a24bf56b3490c4b568d2c (diff)
drbd: Add struct drbd_resource
In a first step, each resource has exactly one connection, and both objects are allocated at the same time. The final result will be one resource and zero or more connections. Only allow to delete a resource if all its connections are C_STANDALONE. Stop the worker threads of all connections early enough. Signed-off-by: Andreas Gruenbacher <agruen@linbit.com> Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r--drivers/block/drbd/drbd_nl.c116
1 files changed, 68 insertions, 48 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 83d8c18fb84c..b8eacccbdc5c 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -249,7 +249,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
first_peer_device(adm_ctx.device)->connection != adm_ctx.connection) {
pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n",
adm_ctx.minor, adm_ctx.resource_name,
- first_peer_device(adm_ctx.device)->connection->name);
+ first_peer_device(adm_ctx.device)->connection->resource->name);
drbd_msg_put_info("minor exists in different resource");
return ERR_INVALID_REQUEST;
}
@@ -258,7 +258,8 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
adm_ctx.volume != adm_ctx.device->vnr) {
pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n",
adm_ctx.minor, adm_ctx.volume,
- adm_ctx.device->vnr, first_peer_device(adm_ctx.device)->connection->name);
+ adm_ctx.device->vnr,
+ first_peer_device(adm_ctx.device)->connection->resource->name);
drbd_msg_put_info("minor exists as different volume");
return ERR_INVALID_REQUEST;
}
@@ -371,23 +372,24 @@ static int conn_khelper(struct drbd_connection *connection, char *cmd)
(char[20]) { }, /* address family */
(char[60]) { }, /* address */
NULL };
- char *argv[] = {usermode_helper, cmd, connection->name, NULL };
+ char *resource_name = connection->resource->name;
+ char *argv[] = {usermode_helper, cmd, resource_name, NULL };
int ret;
setup_khelper_env(connection, envp);
conn_md_sync(connection);
- conn_info(connection, "helper command: %s %s %s\n", usermode_helper, cmd, connection->name);
+ conn_info(connection, "helper command: %s %s %s\n", usermode_helper, cmd, resource_name);
/* TODO: conn_bcast_event() ?? */
ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
if (ret)
conn_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
- usermode_helper, cmd, connection->name,
+ usermode_helper, cmd, resource_name,
(ret >> 8) & 0xff, ret);
else
conn_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
- usermode_helper, cmd, connection->name,
+ usermode_helper, cmd, resource_name,
(ret >> 8) & 0xff, ret);
/* TODO: conn_bcast_event() ?? */
@@ -2143,6 +2145,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
struct drbd_device *device;
struct net_conf *old_conf, *new_conf = NULL;
struct crypto crypto = { };
+ struct drbd_resource *resource;
struct drbd_connection *connection;
enum drbd_ret_code retcode;
int i;
@@ -2163,17 +2166,21 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
/* No need for _rcu here. All reconfiguration is
* strictly serialized on genl_lock(). We are protected against
* concurrent reconfiguration/addition/deletion */
- list_for_each_entry(connection, &drbd_connections, connections) {
- if (nla_len(adm_ctx.my_addr) == connection->my_addr_len &&
- !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr, connection->my_addr_len)) {
- retcode = ERR_LOCAL_ADDR;
- goto out;
- }
+ for_each_resource(resource, &drbd_resources) {
+ for_each_connection(connection, resource) {
+ if (nla_len(adm_ctx.my_addr) == connection->my_addr_len &&
+ !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr,
+ connection->my_addr_len)) {
+ retcode = ERR_LOCAL_ADDR;
+ goto out;
+ }
- if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len &&
- !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr, connection->peer_addr_len)) {
- retcode = ERR_PEER_ADDR;
- goto out;
+ if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len &&
+ !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr,
+ connection->peer_addr_len)) {
+ retcode = ERR_PEER_ADDR;
+ goto out;
+ }
}
}
@@ -2736,7 +2743,7 @@ static int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_connection
if (vnr != VOLUME_UNSPECIFIED &&
nla_put_u32(skb, T_ctx_volume, vnr))
goto nla_put_failure;
- if (nla_put_string(skb, T_ctx_resource_name, connection->name))
+ if (nla_put_string(skb, T_ctx_resource_name, connection->resource->name))
goto nla_put_failure;
if (connection->my_addr_len &&
nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr))
@@ -2899,18 +2906,20 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
{
struct drbd_device *device;
struct drbd_genlmsghdr *dh;
- struct drbd_connection *pos = (struct drbd_connection *)cb->args[0];
- struct drbd_connection *connection = NULL;
- struct drbd_connection *tmp;
+ struct drbd_resource *pos = (struct drbd_resource *)cb->args[0];
+ struct drbd_resource *resource = NULL;
+ struct drbd_connection *connection;
+ struct drbd_resource *tmp;
unsigned volume = cb->args[1];
/* Open coded, deferred, iteration:
- * list_for_each_entry_safe(connection, tmp, &drbd_connections, connections) {
+ * for_each_resource_safe(resource, tmp, &drbd_resources) {
+ * connection = "first connection of resource";
* idr_for_each_entry(&connection->volumes, device, i) {
* ...
* }
* }
- * where connection is cb->args[0];
+ * where resource is cb->args[0];
* and i is cb->args[1];
*
* cb->args[2] indicates if we shall loop over all resources,
@@ -2927,36 +2936,37 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
/* synchronize with conn_create()/drbd_destroy_connection() */
rcu_read_lock();
/* revalidate iterator position */
- list_for_each_entry_rcu(tmp, &drbd_connections, connections) {
+ for_each_resource_rcu(tmp, &drbd_resources) {
if (pos == NULL) {
/* first iteration */
pos = tmp;
- connection = pos;
+ resource = pos;
break;
}
if (tmp == pos) {
- connection = pos;
+ resource = pos;
break;
}
}
- if (connection) {
-next_connection:
+ if (resource) {
+next_resource:
+ connection = first_connection(resource);
device = idr_get_next(&connection->volumes, &volume);
if (!device) {
- /* No more volumes to dump on this connection.
- * Advance connection iterator. */
- pos = list_entry_rcu(connection->connections.next,
- struct drbd_connection, connections);
- /* Did we dump any volume on this connection yet? */
+ /* No more volumes to dump on this resource.
+ * Advance resource iterator. */
+ pos = list_entry_rcu(resource->resources.next,
+ struct drbd_resource, resources);
+ /* Did we dump any volume of this resource yet? */
if (volume != 0) {
/* If we reached the end of the list,
* or only a single resource dump was requested,
* we are done. */
- if (&pos->connections == &drbd_connections || cb->args[2])
+ if (&pos->resources == &drbd_resources || cb->args[2])
goto out;
volume = 0;
- connection = pos;
- goto next_connection;
+ resource = pos;
+ goto next_resource;
}
}
@@ -3000,9 +3010,9 @@ out:
rcu_read_unlock();
/* where to start the next iteration */
cb->args[0] = (long)pos;
- cb->args[1] = (pos == connection) ? volume + 1 : 0;
+ cb->args[1] = (pos == resource) ? volume + 1 : 0;
- /* No more connections/volumes/minors found results in an empty skb.
+ /* No more resources/volumes/minors found results in an empty skb.
* Which will terminate the dump. */
return skb->len;
}
@@ -3399,9 +3409,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
/* delete connection */
if (conn_lowest_minor(adm_ctx.connection) < 0) {
- list_del_rcu(&adm_ctx.connection->connections);
+ struct drbd_resource *resource = adm_ctx.connection->resource;
+
+ list_del_rcu(&resource->resources);
synchronize_rcu();
- kref_put(&adm_ctx.connection->kref, drbd_destroy_connection);
+ drbd_free_resource(resource);
retcode = NO_ERROR;
} else {
@@ -3417,6 +3429,8 @@ out:
int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
{
+ struct drbd_resource *resource;
+ struct drbd_connection *connection;
enum drbd_ret_code retcode;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3425,18 +3439,24 @@ int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- if (conn_lowest_minor(adm_ctx.connection) < 0) {
- list_del_rcu(&adm_ctx.connection->connections);
- synchronize_rcu();
- kref_put(&adm_ctx.connection->kref, drbd_destroy_connection);
-
- retcode = NO_ERROR;
- } else {
+ resource = adm_ctx.resource;
+ for_each_connection(connection, resource) {
+ if (connection->cstate > C_STANDALONE) {
+ retcode = ERR_NET_CONFIGURED;
+ goto out;
+ }
+ }
+ if (!idr_is_empty(&resource->devices)) {
retcode = ERR_RES_IN_USE;
+ goto out;
}
- if (retcode == NO_ERROR)
- drbd_thread_stop(&adm_ctx.connection->worker);
+ list_del_rcu(&resource->resources);
+ for_each_connection(connection, resource)
+ drbd_thread_stop(&connection->worker);
+ synchronize_rcu();
+ drbd_free_resource(resource);
+ retcode = NO_ERROR;
out:
drbd_adm_finish(info, retcode);
return 0;