drbd: drbd_adm_prepare(): Only set adm_ctx.connection when a connection is requested
[deliverable/linux.git] / drivers / block / drbd / drbd_nl.c
index 924126436a8b8b4c72adcf42fe2f76a927c4ec51..664e913cef437dab6d6e03453565c500c16657d5 100644 (file)
@@ -216,10 +216,6 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
        adm_ctx.device = minor_to_device(d_in->minor);
        if (adm_ctx.resource_name) {
                adm_ctx.resource = drbd_find_resource(adm_ctx.resource_name);
-               if (adm_ctx.resource) {
-                       adm_ctx.connection = first_connection(adm_ctx.resource);
-                       kref_get(&adm_ctx.connection->kref);
-               }
        }
 
        if (!adm_ctx.device && (flags & DRBD_ADM_NEED_MINOR)) {
@@ -234,7 +230,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
        }
 
        if (flags & DRBD_ADM_NEED_CONNECTION) {
-               if (adm_ctx.connection && !(flags & DRBD_ADM_NEED_RESOURCE)) {
+               if (adm_ctx.resource) {
                        drbd_msg_put_info("no resource name expected");
                        return ERR_INVALID_REQUEST;
                }
@@ -560,8 +556,16 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
        int forced = 0;
        union drbd_state mask, val;
 
-       if (new_role == R_PRIMARY)
-               request_ping(first_peer_device(device)->connection); /* Detect a dead peer ASAP */
+       if (new_role == R_PRIMARY) {
+               struct drbd_connection *connection;
+
+               /* Detect dead peers as soon as possible.  */
+
+               rcu_read_lock();
+               for_each_connection(connection, device->resource)
+                       request_ping(connection);
+               rcu_read_unlock();
+       }
 
        mutex_lock(device->state_mutex);
 
@@ -1921,29 +1925,29 @@ static bool conn_ov_running(struct drbd_connection *connection)
 }
 
 static enum drbd_ret_code
-_check_net_options(struct drbd_connection *connection, struct net_conf *old_conf, struct net_conf *new_conf)
+_check_net_options(struct drbd_connection *connection, struct net_conf *old_net_conf, struct net_conf *new_net_conf)
 {
        struct drbd_peer_device *peer_device;
        int i;
 
-       if (old_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) {
-               if (new_conf->wire_protocol != old_conf->wire_protocol)
+       if (old_net_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) {
+               if (new_net_conf->wire_protocol != old_net_conf->wire_protocol)
                        return ERR_NEED_APV_100;
 
-               if (new_conf->two_primaries != old_conf->two_primaries)
+               if (new_net_conf->two_primaries != old_net_conf->two_primaries)
                        return ERR_NEED_APV_100;
 
-               if (strcmp(new_conf->integrity_alg, old_conf->integrity_alg))
+               if (strcmp(new_net_conf->integrity_alg, old_net_conf->integrity_alg))
                        return ERR_NEED_APV_100;
        }
 
-       if (!new_conf->two_primaries &&
+       if (!new_net_conf->two_primaries &&
            conn_highest_role(connection) == R_PRIMARY &&
            conn_highest_peer(connection) == R_PRIMARY)
                return ERR_NEED_ALLOW_TWO_PRI;
 
-       if (new_conf->two_primaries &&
-           (new_conf->wire_protocol != DRBD_PROT_C))
+       if (new_net_conf->two_primaries &&
+           (new_net_conf->wire_protocol != DRBD_PROT_C))
                return ERR_NOT_PROTO_C;
 
        idr_for_each_entry(&connection->peer_devices, peer_device, i) {
@@ -1951,28 +1955,28 @@ _check_net_options(struct drbd_connection *connection, struct net_conf *old_conf
                if (get_ldev(device)) {
                        enum drbd_fencing_p fp = rcu_dereference(device->ldev->disk_conf)->fencing;
                        put_ldev(device);
-                       if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
+                       if (new_net_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH)
                                return ERR_STONITH_AND_PROT_A;
                }
-               if (device->state.role == R_PRIMARY && new_conf->discard_my_data)
+               if (device->state.role == R_PRIMARY && new_net_conf->discard_my_data)
                        return ERR_DISCARD_IMPOSSIBLE;
        }
 
-       if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A)
+       if (new_net_conf->on_congestion != OC_BLOCK && new_net_conf->wire_protocol != DRBD_PROT_A)
                return ERR_CONG_NOT_PROTO_A;
 
        return NO_ERROR;
 }
 
 static enum drbd_ret_code
-check_net_options(struct drbd_connection *connection, struct net_conf *new_conf)
+check_net_options(struct drbd_connection *connection, struct net_conf *new_net_conf)
 {
        static enum drbd_ret_code rv;
        struct drbd_peer_device *peer_device;
        int i;
 
        rcu_read_lock();
-       rv = _check_net_options(connection, rcu_dereference(connection->net_conf), new_conf);
+       rv = _check_net_options(connection, rcu_dereference(connection->net_conf), new_net_conf);
        rcu_read_unlock();
 
        /* connection->volumes protected by genl_lock() here */
@@ -2010,26 +2014,26 @@ alloc_hash(struct crypto_hash **tfm, char *tfm_name, int err_alg)
 }
 
 static enum drbd_ret_code
-alloc_crypto(struct crypto *crypto, struct net_conf *new_conf)
+alloc_crypto(struct crypto *crypto, struct net_conf *new_net_conf)
 {
        char hmac_name[CRYPTO_MAX_ALG_NAME];
        enum drbd_ret_code rv;
 
-       rv = alloc_hash(&crypto->csums_tfm, new_conf->csums_alg,
+       rv = alloc_hash(&crypto->csums_tfm, new_net_conf->csums_alg,
                       ERR_CSUMS_ALG);
        if (rv != NO_ERROR)
                return rv;
-       rv = alloc_hash(&crypto->verify_tfm, new_conf->verify_alg,
+       rv = alloc_hash(&crypto->verify_tfm, new_net_conf->verify_alg,
                       ERR_VERIFY_ALG);
        if (rv != NO_ERROR)
                return rv;
-       rv = alloc_hash(&crypto->integrity_tfm, new_conf->integrity_alg,
+       rv = alloc_hash(&crypto->integrity_tfm, new_net_conf->integrity_alg,
                       ERR_INTEGRITY_ALG);
        if (rv != NO_ERROR)
                return rv;
-       if (new_conf->cram_hmac_alg[0] != 0) {
+       if (new_net_conf->cram_hmac_alg[0] != 0) {
                snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)",
-                        new_conf->cram_hmac_alg);
+                        new_net_conf->cram_hmac_alg);
 
                rv = alloc_hash(&crypto->cram_hmac_tfm, hmac_name,
                               ERR_AUTH_ALG);
@@ -2050,7 +2054,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
 {
        enum drbd_ret_code retcode;
        struct drbd_connection *connection;
-       struct net_conf *old_conf, *new_conf = NULL;
+       struct net_conf *old_net_conf, *new_net_conf = NULL;
        int err;
        int ovr; /* online verify running */
        int rsr; /* re-sync running */
@@ -2064,8 +2068,8 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
 
        connection = adm_ctx.connection;
 
-       new_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
-       if (!new_conf) {
+       new_net_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
+       if (!new_net_conf) {
                retcode = ERR_NOMEM;
                goto out;
        }
@@ -2074,48 +2078,48 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
 
        mutex_lock(&connection->data.mutex);
        mutex_lock(&connection->conf_update);
-       old_conf = connection->net_conf;
+       old_net_conf = connection->net_conf;
 
-       if (!old_conf) {
+       if (!old_net_conf) {
                drbd_msg_put_info("net conf missing, try connect");
                retcode = ERR_INVALID_REQUEST;
                goto fail;
        }
 
-       *new_conf = *old_conf;
+       *new_net_conf = *old_net_conf;
        if (should_set_defaults(info))
-               set_net_conf_defaults(new_conf);
+               set_net_conf_defaults(new_net_conf);
 
-       err = net_conf_from_attrs_for_change(new_conf, info);
+       err = net_conf_from_attrs_for_change(new_net_conf, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
                drbd_msg_put_info(from_attrs_err_to_txt(err));
                goto fail;
        }
 
-       retcode = check_net_options(connection, new_conf);
+       retcode = check_net_options(connection, new_net_conf);
        if (retcode != NO_ERROR)
                goto fail;
 
        /* re-sync running */
        rsr = conn_resync_running(connection);
-       if (rsr && strcmp(new_conf->csums_alg, old_conf->csums_alg)) {
+       if (rsr && strcmp(new_net_conf->csums_alg, old_net_conf->csums_alg)) {
                retcode = ERR_CSUMS_RESYNC_RUNNING;
                goto fail;
        }
 
        /* online verify running */
        ovr = conn_ov_running(connection);
-       if (ovr && strcmp(new_conf->verify_alg, old_conf->verify_alg)) {
+       if (ovr && strcmp(new_net_conf->verify_alg, old_net_conf->verify_alg)) {
                retcode = ERR_VERIFY_RUNNING;
                goto fail;
        }
 
-       retcode = alloc_crypto(&crypto, new_conf);
+       retcode = alloc_crypto(&crypto, new_net_conf);
        if (retcode != NO_ERROR)
                goto fail;
 
-       rcu_assign_pointer(connection->net_conf, new_conf);
+       rcu_assign_pointer(connection->net_conf, new_net_conf);
 
        if (!rsr) {
                crypto_free_hash(connection->csums_tfm);
@@ -2140,7 +2144,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        mutex_unlock(&connection->conf_update);
        mutex_unlock(&connection->data.mutex);
        synchronize_rcu();
-       kfree(old_conf);
+       kfree(old_net_conf);
 
        if (connection->cstate >= C_WF_REPORT_PARAMS)
                drbd_send_sync_param(minor_to_device(conn_lowest_minor(connection)));
@@ -2151,7 +2155,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        mutex_unlock(&connection->conf_update);
        mutex_unlock(&connection->data.mutex);
        free_crypto(&crypto);
-       kfree(new_conf);
+       kfree(new_net_conf);
  done:
        conn_reconfig_done(connection);
  out:
@@ -2162,7 +2166,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
 int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
 {
        struct drbd_peer_device *peer_device;
-       struct net_conf *old_conf, *new_conf = NULL;
+       struct net_conf *old_net_conf, *new_net_conf = NULL;
        struct crypto crypto = { };
        struct drbd_resource *resource;
        struct drbd_connection *connection;
@@ -2203,7 +2207,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       connection = adm_ctx.connection;
+       connection = first_connection(adm_ctx.resource);
        conn_reconfig_start(connection);
 
        if (connection->cstate > C_STANDALONE) {
@@ -2212,41 +2216,41 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* allocation not in the IO path, drbdsetup / netlink process context */
-       new_conf = kzalloc(sizeof(*new_conf), GFP_KERNEL);
-       if (!new_conf) {
+       new_net_conf = kzalloc(sizeof(*new_net_conf), GFP_KERNEL);
+       if (!new_net_conf) {
                retcode = ERR_NOMEM;
                goto fail;
        }
 
-       set_net_conf_defaults(new_conf);
+       set_net_conf_defaults(new_net_conf);
 
-       err = net_conf_from_attrs(new_conf, info);
+       err = net_conf_from_attrs(new_net_conf, info);
        if (err && err != -ENOMSG) {
                retcode = ERR_MANDATORY_TAG;
                drbd_msg_put_info(from_attrs_err_to_txt(err));
                goto fail;
        }
 
-       retcode = check_net_options(connection, new_conf);
+       retcode = check_net_options(connection, new_net_conf);
        if (retcode != NO_ERROR)
                goto fail;
 
-       retcode = alloc_crypto(&crypto, new_conf);
+       retcode = alloc_crypto(&crypto, new_net_conf);
        if (retcode != NO_ERROR)
                goto fail;
 
-       ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
+       ((char *)new_net_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
 
        conn_flush_workqueue(connection);
 
        mutex_lock(&connection->conf_update);
-       old_conf = connection->net_conf;
-       if (old_conf) {
+       old_net_conf = connection->net_conf;
+       if (old_net_conf) {
                retcode = ERR_NET_CONFIGURED;
                mutex_unlock(&connection->conf_update);
                goto fail;
        }
-       rcu_assign_pointer(connection->net_conf, new_conf);
+       rcu_assign_pointer(connection->net_conf, new_net_conf);
 
        conn_free_crypto(connection);
        connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
@@ -2277,7 +2281,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
 
 fail:
        free_crypto(&crypto);
-       kfree(new_conf);
+       kfree(new_net_conf);
 
        conn_reconfig_done(connection);
 out:
@@ -2752,23 +2756,28 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
        return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED));
 }
 
-static int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_connection *connection, unsigned vnr)
+static int nla_put_drbd_cfg_context(struct sk_buff *skb,
+                                   struct drbd_resource *resource,
+                                   struct drbd_connection *connection,
+                                   struct drbd_device *device)
 {
        struct nlattr *nla;
        nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT);
        if (!nla)
                goto nla_put_failure;
-       if (vnr != VOLUME_UNSPECIFIED &&
-           nla_put_u32(skb, T_ctx_volume, vnr))
+       if (device &&
+           nla_put_u32(skb, T_ctx_volume, device->vnr))
                goto nla_put_failure;
        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))
-               goto nla_put_failure;
-       if (connection->peer_addr_len &&
-           nla_put(skb, T_ctx_peer_addr, connection->peer_addr_len, &connection->peer_addr))
-               goto nla_put_failure;
+       if (connection) {
+               if (connection->my_addr_len &&
+                   nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr))
+                       goto nla_put_failure;
+               if (connection->peer_addr_len &&
+                   nla_put(skb, T_ctx_peer_addr, connection->peer_addr_len, &connection->peer_addr))
+                       goto nla_put_failure;
+       }
        nla_nest_end(skb, nla);
        return 0;
 
@@ -2778,9 +2787,22 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
-static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
+/*
+ * Return the connection of @resource if @resource has exactly one connection.
+ */
+static struct drbd_connection *the_only_connection(struct drbd_resource *resource)
+{
+       struct list_head *connections = &resource->connections;
+
+       if (list_empty(connections) || connections->next->next != connections)
+               return NULL;
+       return list_first_entry(&resource->connections, struct drbd_connection, connections);
+}
+
+int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
                const struct sib_info *sib)
 {
+       struct drbd_resource *resource = device->resource;
        struct state_info *si = NULL; /* for sizeof(si->member); */
        struct nlattr *nla;
        int got_ldev;
@@ -2804,7 +2826,7 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
 
        /* We need to add connection name and volume number information still.
         * Minor number is in drbd_genlmsghdr. */
-       if (nla_put_drbd_cfg_context(skb, first_peer_device(device)->connection, device->vnr))
+       if (nla_put_drbd_cfg_context(skb, resource, the_only_connection(resource), device))
                goto nla_put_failure;
 
        if (res_opts_to_skb(skb, &device->resource->res_opts, exclude_sensitive))
@@ -2922,19 +2944,17 @@ out:
 
 static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct drbd_peer_device *peer_device;
        struct drbd_device *device;
        struct drbd_genlmsghdr *dh;
        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:
         * for_each_resource_safe(resource, tmp, &drbd_resources) {
-        *      connection = "first connection of resource";
-        *      idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+        *      connection = "first connection of resource or undefined";
+        *      idr_for_each_entry(&resource->devices, device, i) {
         *        ...
         *      }
         * }
@@ -2969,9 +2989,8 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
        }
        if (resource) {
 next_resource:
-               connection = first_connection(resource);
-               peer_device = idr_get_next(&connection->peer_devices, &volume);
-               if (!peer_device) {
+               device = idr_get_next(&resource->devices, &volume);
+               if (!device) {
                        /* No more volumes to dump on this resource.
                         * Advance resource iterator. */
                        pos = list_entry_rcu(resource->resources.next,
@@ -2995,24 +3014,29 @@ next_resource:
                if (!dh)
                        goto out;
 
-               if (!peer_device) {
+               if (!device) {
                        /* This is a connection without a single volume.
                         * Suprisingly enough, it may have a network
                         * configuration. */
-                       struct net_conf *nc;
+                       struct drbd_connection *connection;
+
                        dh->minor = -1U;
                        dh->ret_code = NO_ERROR;
-                       if (nla_put_drbd_cfg_context(skb, connection, VOLUME_UNSPECIFIED))
-                               goto cancel;
-                       nc = rcu_dereference(connection->net_conf);
-                       if (nc && net_conf_to_skb(skb, nc, 1) != 0)
+                       connection = the_only_connection(resource);
+                       if (nla_put_drbd_cfg_context(skb, resource, connection, NULL))
                                goto cancel;
+                       if (connection) {
+                               struct net_conf *nc;
+
+                               nc = rcu_dereference(connection->net_conf);
+                               if (nc && net_conf_to_skb(skb, nc, 1) != 0)
+                                       goto cancel;
+                       }
                        goto done;
                }
 
-               device = peer_device->device;
                D_ASSERT(device, device->vnr == volume);
-               D_ASSERT(device, first_peer_device(device)->connection == connection);
+               D_ASSERT(device, device->resource == resource);
 
                dh->minor = device_to_minor(device);
                dh->ret_code = NO_ERROR;
@@ -3281,7 +3305,7 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
-       if (adm_ctx.connection) {
+       if (adm_ctx.resource) {
                if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) {
                        retcode = ERR_INVALID_REQUEST;
                        drbd_msg_put_info("resource exists");
@@ -3328,7 +3352,7 @@ int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       retcode = drbd_create_minor(adm_ctx.connection, dh->minor, adm_ctx.volume);
+       retcode = drbd_create_device(adm_ctx.resource, dh->minor, adm_ctx.volume);
 out:
        drbd_adm_finish(info, retcode);
        return 0;
@@ -3343,7 +3367,7 @@ static enum drbd_ret_code adm_del_minor(struct drbd_device *device)
            device->state.role == R_SECONDARY) {
                _drbd_request_state(device, NS(conn, C_WF_REPORT_PARAMS),
                                    CS_VERBOSE + CS_WAIT_COMPLETE);
-               drbd_delete_minor(device);
+               drbd_delete_device(device);
                return NO_ERROR;
        } else
                return ERR_MINOR_CONFIGURED;
@@ -3367,8 +3391,10 @@ out:
 
 int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
 {
+       struct drbd_resource *resource;
+       struct drbd_connection *connection;
+       struct drbd_device *device;
        int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
-       struct drbd_peer_device *peer_device;
        unsigned i;
 
        retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3377,24 +3403,29 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
+       resource = adm_ctx.resource;
        /* demote */
-       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
-               retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
+       for_each_connection(connection, resource) {
+               struct drbd_peer_device *peer_device;
+
+               idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+                       retcode = drbd_set_role(peer_device->device, R_SECONDARY, 0);
+                       if (retcode < SS_SUCCESS) {
+                               drbd_msg_put_info("failed to demote");
+                               goto out;
+                       }
+               }
+
+               retcode = conn_try_disconnect(connection, 0);
                if (retcode < SS_SUCCESS) {
-                       drbd_msg_put_info("failed to demote");
+                       drbd_msg_put_info("failed to disconnect");
                        goto out;
                }
        }
 
-       retcode = conn_try_disconnect(adm_ctx.connection, 0);
-       if (retcode < SS_SUCCESS) {
-               drbd_msg_put_info("failed to disconnect");
-               goto out;
-       }
-
        /* detach */
-       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
-               retcode = adm_detach(peer_device->device, 0);
+       idr_for_each_entry(&resource->devices, device, i) {
+               retcode = adm_detach(device, 0);
                if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
                        drbd_msg_put_info("failed to detach");
                        goto out;
@@ -3404,13 +3435,14 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        /* If we reach this, all volumes (of this connection) are Secondary,
         * Disconnected, Diskless, aka Unconfigured. Make sure all threads have
         * actually stopped, state handling only does drbd_thread_stop_nowait(). */
-       drbd_thread_stop(&adm_ctx.connection->worker);
+       for_each_connection(connection, resource)
+               drbd_thread_stop(&connection->worker);
 
        /* Now, nothing can fail anymore */
 
        /* delete volumes */
-       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
-               retcode = adm_del_minor(peer_device->device);
+       idr_for_each_entry(&resource->devices, device, i) {
+               retcode = adm_del_minor(device);
                if (retcode != NO_ERROR) {
                        /* "can not happen" */
                        drbd_msg_put_info("failed to delete volume");
@@ -3418,21 +3450,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       /* delete connection */
-       if (conn_lowest_minor(adm_ctx.connection) < 0) {
-               struct drbd_resource *resource = adm_ctx.connection->resource;
-
-               list_del_rcu(&resource->resources);
-               synchronize_rcu();
-               drbd_free_resource(resource);
+       list_del_rcu(&resource->resources);
+       synchronize_rcu();
+       drbd_free_resource(resource);
+       retcode = NO_ERROR;
 
-               retcode = NO_ERROR;
-       } else {
-               /* "can not happen" */
-               retcode = ERR_RES_IN_USE;
-               drbd_msg_put_info("failed to delete connection");
-       }
-       goto out;
 out:
        drbd_adm_finish(info, retcode);
        return 0;
This page took 0.033077 seconds and 5 git commands to generate.