drbd: drbd_adm_new_resource(): Check if resource exists, not if it has any connections
[deliverable/linux.git] / drivers / block / drbd / drbd_nl.c
index bc160ae807986c0908572c0f113cb5a7f04a9aab..fde2d257eb86fd49bdd7b651b56a10c22315d5c4 100644 (file)
@@ -45,8 +45,8 @@
 // int drbd_adm_create_resource(struct sk_buff *skb, struct genl_info *info);
 // int drbd_adm_delete_resource(struct sk_buff *skb, struct genl_info *info);
 
-int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info);
-int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info);
 
 int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info);
 int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info);
@@ -104,7 +104,8 @@ static struct drbd_config_context {
        struct drbd_genlmsghdr *reply_dh;
        /* resolved from attributes, if possible */
        struct drbd_device *device;
-       struct drbd_tconn *tconn;
+       struct drbd_resource *resource;
+       struct drbd_connection *connection;
 } adm_ctx;
 
 static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
@@ -203,9 +204,9 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
                adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
                adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
                if ((adm_ctx.my_addr &&
-                    nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) ||
+                    nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.connection->my_addr)) ||
                    (adm_ctx.peer_addr &&
-                    nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) {
+                    nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.connection->peer_addr))) {
                        err = -EINVAL;
                        goto fail;
                }
@@ -213,19 +214,27 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
 
        adm_ctx.minor = d_in->minor;
        adm_ctx.device = minor_to_device(d_in->minor);
-       adm_ctx.tconn = conn_get_by_name(adm_ctx.resource_name);
+       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)) {
                drbd_msg_put_info("unknown minor");
                return ERR_MINOR_INVALID;
        }
-       if (!adm_ctx.tconn && (flags & DRBD_ADM_NEED_RESOURCE)) {
+       if (!adm_ctx.resource && (flags & DRBD_ADM_NEED_RESOURCE)) {
                drbd_msg_put_info("unknown resource");
+               if (adm_ctx.resource_name)
+                       return ERR_RES_NOT_KNOWN;
                return ERR_INVALID_REQUEST;
        }
 
        if (flags & DRBD_ADM_NEED_CONNECTION) {
-               if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) {
+               if (adm_ctx.connection && !(flags & DRBD_ADM_NEED_RESOURCE)) {
                        drbd_msg_put_info("no resource name expected");
                        return ERR_INVALID_REQUEST;
                }
@@ -234,22 +243,22 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
                        return ERR_INVALID_REQUEST;
                }
                if (adm_ctx.my_addr && adm_ctx.peer_addr)
-                       adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
+                       adm_ctx.connection = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
                                                          nla_len(adm_ctx.my_addr),
                                                          nla_data(adm_ctx.peer_addr),
                                                          nla_len(adm_ctx.peer_addr));
-               if (!adm_ctx.tconn) {
+               if (!adm_ctx.connection) {
                        drbd_msg_put_info("unknown connection");
                        return ERR_INVALID_REQUEST;
                }
        }
 
        /* some more paranoia, if the request was over-determined */
-       if (adm_ctx.device && adm_ctx.tconn &&
-           adm_ctx.device->tconn != adm_ctx.tconn) {
-               pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n",
-                               adm_ctx.minor, adm_ctx.resource_name,
-                               adm_ctx.device->tconn->name);
+       if (adm_ctx.device && adm_ctx.resource &&
+           adm_ctx.device->resource != adm_ctx.resource) {
+               pr_warning("request: minor=%u, resource=%s; but that minor belongs to resource %s\n",
+                               adm_ctx.minor, adm_ctx.resource->name,
+                               adm_ctx.device->resource->name);
                drbd_msg_put_info("minor exists in different resource");
                return ERR_INVALID_REQUEST;
        }
@@ -258,7 +267,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, adm_ctx.device->tconn->name);
+                               adm_ctx.device->vnr,
+                               adm_ctx.device->resource->name);
                drbd_msg_put_info("minor exists as different volume");
                return ERR_INVALID_REQUEST;
        }
@@ -273,9 +283,13 @@ fail:
 
 static int drbd_adm_finish(struct genl_info *info, int retcode)
 {
-       if (adm_ctx.tconn) {
-               kref_put(&adm_ctx.tconn->kref, &conn_destroy);
-               adm_ctx.tconn = NULL;
+       if (adm_ctx.connection) {
+               kref_put(&adm_ctx.connection->kref, drbd_destroy_connection);
+               adm_ctx.connection = NULL;
+       }
+       if (adm_ctx.resource) {
+               kref_put(&adm_ctx.resource->kref, drbd_destroy_resource);
+               adm_ctx.resource = NULL;
        }
 
        if (!adm_ctx.reply_skb)
@@ -286,29 +300,29 @@ static int drbd_adm_finish(struct genl_info *info, int retcode)
        return 0;
 }
 
-static void setup_khelper_env(struct drbd_tconn *tconn, char **envp)
+static void setup_khelper_env(struct drbd_connection *connection, char **envp)
 {
        char *afs;
 
        /* FIXME: A future version will not allow this case. */
-       if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0)
+       if (connection->my_addr_len == 0 || connection->peer_addr_len == 0)
                return;
 
-       switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) {
+       switch (((struct sockaddr *)&connection->peer_addr)->sa_family) {
        case AF_INET6:
                afs = "ipv6";
                snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6",
-                        &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr);
+                        &((struct sockaddr_in6 *)&connection->peer_addr)->sin6_addr);
                break;
        case AF_INET:
                afs = "ipv4";
                snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
-                        &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
+                        &((struct sockaddr_in *)&connection->peer_addr)->sin_addr);
                break;
        default:
                afs = "ssocks";
                snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
-                        &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
+                        &((struct sockaddr_in *)&connection->peer_addr)->sin_addr);
        }
        snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs);
 }
@@ -323,39 +337,39 @@ int drbd_khelper(struct drbd_device *device, char *cmd)
                        NULL };
        char mb[12];
        char *argv[] = {usermode_helper, cmd, mb, NULL };
-       struct drbd_tconn *tconn = device->tconn;
+       struct drbd_connection *connection = first_peer_device(device)->connection;
        struct sib_info sib;
        int ret;
 
-       if (current == tconn->worker.task)
-               set_bit(CALLBACK_PENDING, &tconn->flags);
+       if (current == connection->worker.task)
+               set_bit(CALLBACK_PENDING, &connection->flags);
 
        snprintf(mb, 12, "minor-%d", device_to_minor(device));
-       setup_khelper_env(tconn, envp);
+       setup_khelper_env(connection, envp);
 
        /* The helper may take some time.
         * write out any unsynced meta data changes now */
        drbd_md_sync(device);
 
-       dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
+       drbd_info(device, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
        sib.sib_reason = SIB_HELPER_PRE;
        sib.helper_name = cmd;
        drbd_bcast_event(device, &sib);
        ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
        if (ret)
-               dev_warn(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+               drbd_warn(device, "helper command: %s %s %s exit code %u (0x%x)\n",
                                usermode_helper, cmd, mb,
                                (ret >> 8) & 0xff, ret);
        else
-               dev_info(DEV, "helper command: %s %s %s exit code %u (0x%x)\n",
+               drbd_info(device, "helper command: %s %s %s exit code %u (0x%x)\n",
                                usermode_helper, cmd, mb,
                                (ret >> 8) & 0xff, ret);
        sib.sib_reason = SIB_HELPER_POST;
        sib.helper_exit_code = ret;
        drbd_bcast_event(device, &sib);
 
-       if (current == tconn->worker.task)
-               clear_bit(CALLBACK_PENDING, &tconn->flags);
+       if (current == connection->worker.task)
+               clear_bit(CALLBACK_PENDING, &connection->flags);
 
        if (ret < 0) /* Ignore any ERRNOs we got. */
                ret = 0;
@@ -363,7 +377,7 @@ int drbd_khelper(struct drbd_device *device, char *cmd)
        return ret;
 }
 
-static int conn_khelper(struct drbd_tconn *tconn, char *cmd)
+static int conn_khelper(struct drbd_connection *connection, char *cmd)
 {
        char *envp[] = { "HOME=/",
                        "TERM=linux",
@@ -371,23 +385,24 @@ static int conn_khelper(struct drbd_tconn *tconn, char *cmd)
                         (char[20]) { }, /* address family */
                         (char[60]) { }, /* address */
                        NULL };
-       char *argv[] = {usermode_helper, cmd, tconn->name, NULL };
+       char *resource_name = connection->resource->name;
+       char *argv[] = {usermode_helper, cmd, resource_name, NULL };
        int ret;
 
-       setup_khelper_env(tconn, envp);
-       conn_md_sync(tconn);
+       setup_khelper_env(connection, envp);
+       conn_md_sync(connection);
 
-       conn_info(tconn, "helper command: %s %s %s\n", usermode_helper, cmd, tconn->name);
+       drbd_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(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
-                         usermode_helper, cmd, tconn->name,
+               drbd_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
+                         usermode_helper, cmd, resource_name,
                          (ret >> 8) & 0xff, ret);
        else
-               conn_info(tconn, "helper command: %s %s %s exit code %u (0x%x)\n",
-                         usermode_helper, cmd, tconn->name,
+               drbd_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
+                         usermode_helper, cmd, resource_name,
                          (ret >> 8) & 0xff, ret);
        /* TODO: conn_bcast_event() ?? */
 
@@ -397,17 +412,19 @@ static int conn_khelper(struct drbd_tconn *tconn, char *cmd)
        return ret;
 }
 
-static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
+static enum drbd_fencing_p highest_fencing_policy(struct drbd_connection *connection)
 {
        enum drbd_fencing_p fp = FP_NOT_AVAIL;
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        int vnr;
 
        rcu_read_lock();
-       idr_for_each_entry(&tconn->volumes, device, vnr) {
+       idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+               struct drbd_device *device = peer_device->device;
                if (get_ldev_if_state(device, D_CONSISTENT)) {
-                       fp = max_t(enum drbd_fencing_p, fp,
-                                  rcu_dereference(device->ldev->disk_conf)->fencing);
+                       struct disk_conf *disk_conf =
+                               rcu_dereference(peer_device->device->ldev->disk_conf);
+                       fp = max_t(enum drbd_fencing_p, fp, disk_conf->fencing);
                        put_ldev(device);
                }
        }
@@ -416,7 +433,7 @@ static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn)
        return fp;
 }
 
-bool conn_try_outdate_peer(struct drbd_tconn *tconn)
+bool conn_try_outdate_peer(struct drbd_connection *connection)
 {
        unsigned int connect_cnt;
        union drbd_state mask = { };
@@ -425,26 +442,26 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
        char *ex_to_string;
        int r;
 
-       if (tconn->cstate >= C_WF_REPORT_PARAMS) {
-               conn_err(tconn, "Expected cstate < C_WF_REPORT_PARAMS\n");
+       if (connection->cstate >= C_WF_REPORT_PARAMS) {
+               drbd_err(connection, "Expected cstate < C_WF_REPORT_PARAMS\n");
                return false;
        }
 
-       spin_lock_irq(&tconn->req_lock);
-       connect_cnt = tconn->connect_cnt;
-       spin_unlock_irq(&tconn->req_lock);
+       spin_lock_irq(&connection->req_lock);
+       connect_cnt = connection->connect_cnt;
+       spin_unlock_irq(&connection->req_lock);
 
-       fp = highest_fencing_policy(tconn);
+       fp = highest_fencing_policy(connection);
        switch (fp) {
        case FP_NOT_AVAIL:
-               conn_warn(tconn, "Not fencing peer, I'm not even Consistent myself.\n");
+               drbd_warn(connection, "Not fencing peer, I'm not even Consistent myself.\n");
                goto out;
        case FP_DONT_CARE:
                return true;
        default: ;
        }
 
-       r = conn_khelper(tconn, "fence-peer");
+       r = conn_khelper(connection, "fence-peer");
 
        switch ((r>>8) & 0xff) {
        case 3: /* peer is inconsistent */
@@ -458,7 +475,7 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
                val.pdsk = D_OUTDATED;
                break;
        case 5: /* peer was down */
-               if (conn_highest_disk(tconn) == D_UP_TO_DATE) {
+               if (conn_highest_disk(connection) == D_UP_TO_DATE) {
                        /* we will(have) create(d) a new UUID anyways... */
                        ex_to_string = "peer is unreachable, assumed to be dead";
                        mask.pdsk = D_MASK;
@@ -471,65 +488,65 @@ bool conn_try_outdate_peer(struct drbd_tconn *tconn)
                 * This is useful when an unconnected R_SECONDARY is asked to
                 * become R_PRIMARY, but finds the other peer being active. */
                ex_to_string = "peer is active";
-               conn_warn(tconn, "Peer is primary, outdating myself.\n");
+               drbd_warn(connection, "Peer is primary, outdating myself.\n");
                mask.disk = D_MASK;
                val.disk = D_OUTDATED;
                break;
        case 7:
                if (fp != FP_STONITH)
-                       conn_err(tconn, "fence-peer() = 7 && fencing != Stonith !!!\n");
+                       drbd_err(connection, "fence-peer() = 7 && fencing != Stonith !!!\n");
                ex_to_string = "peer was stonithed";
                mask.pdsk = D_MASK;
                val.pdsk = D_OUTDATED;
                break;
        default:
                /* The script is broken ... */
-               conn_err(tconn, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
+               drbd_err(connection, "fence-peer helper broken, returned %d\n", (r>>8)&0xff);
                return false; /* Eventually leave IO frozen */
        }
 
-       conn_info(tconn, "fence-peer helper returned %d (%s)\n",
+       drbd_info(connection, "fence-peer helper returned %d (%s)\n",
                  (r>>8) & 0xff, ex_to_string);
 
  out:
 
        /* Not using
-          conn_request_state(tconn, mask, val, CS_VERBOSE);
+          conn_request_state(connection, mask, val, CS_VERBOSE);
           here, because we might were able to re-establish the connection in the
           meantime. */
-       spin_lock_irq(&tconn->req_lock);
-       if (tconn->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &tconn->flags)) {
-               if (tconn->connect_cnt != connect_cnt)
+       spin_lock_irq(&connection->req_lock);
+       if (connection->cstate < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &connection->flags)) {
+               if (connection->connect_cnt != connect_cnt)
                        /* In case the connection was established and droped
                           while the fence-peer handler was running, ignore it */
-                       conn_info(tconn, "Ignoring fence-peer exit code\n");
+                       drbd_info(connection, "Ignoring fence-peer exit code\n");
                else
-                       _conn_request_state(tconn, mask, val, CS_VERBOSE);
+                       _conn_request_state(connection, mask, val, CS_VERBOSE);
        }
-       spin_unlock_irq(&tconn->req_lock);
+       spin_unlock_irq(&connection->req_lock);
 
-       return conn_highest_pdsk(tconn) <= D_OUTDATED;
+       return conn_highest_pdsk(connection) <= D_OUTDATED;
 }
 
 static int _try_outdate_peer_async(void *data)
 {
-       struct drbd_tconn *tconn = (struct drbd_tconn *)data;
+       struct drbd_connection *connection = (struct drbd_connection *)data;
 
-       conn_try_outdate_peer(tconn);
+       conn_try_outdate_peer(connection);
 
-       kref_put(&tconn->kref, &conn_destroy);
+       kref_put(&connection->kref, drbd_destroy_connection);
        return 0;
 }
 
-void conn_try_outdate_peer_async(struct drbd_tconn *tconn)
+void conn_try_outdate_peer_async(struct drbd_connection *connection)
 {
        struct task_struct *opa;
 
-       kref_get(&tconn->kref);
-       opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h");
+       kref_get(&connection->kref);
+       opa = kthread_run(_try_outdate_peer_async, connection, "drbd_async_h");
        if (IS_ERR(opa)) {
-               conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n");
-               kref_put(&tconn->kref, &conn_destroy);
+               drbd_err(connection, "out of mem, failed to invoke fence-peer helper\n");
+               kref_put(&connection->kref, drbd_destroy_connection);
        }
 }
 
@@ -544,7 +561,7 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
        union drbd_state mask, val;
 
        if (new_role == R_PRIMARY)
-               request_ping(device->tconn); /* Detect a dead peer ASAP */
+               request_ping(first_peer_device(device)->connection); /* Detect a dead peer ASAP */
 
        mutex_lock(device->state_mutex);
 
@@ -573,9 +590,9 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
 
                if (rv == SS_NO_UP_TO_DATE_DISK &&
                    device->state.disk == D_CONSISTENT && mask.pdsk == 0) {
-                       D_ASSERT(device->state.pdsk == D_UNKNOWN);
+                       D_ASSERT(device, device->state.pdsk == D_UNKNOWN);
 
-                       if (conn_try_outdate_peer(device->tconn)) {
+                       if (conn_try_outdate_peer(first_peer_device(device)->connection)) {
                                val.disk = D_UP_TO_DATE;
                                mask.disk = D_MASK;
                        }
@@ -585,8 +602,8 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
                if (rv == SS_NOTHING_TO_DO)
                        goto out;
                if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) {
-                       if (!conn_try_outdate_peer(device->tconn) && force) {
-                               dev_warn(DEV, "Forced into split brain situation!\n");
+                       if (!conn_try_outdate_peer(first_peer_device(device)->connection) && force) {
+                               drbd_warn(device, "Forced into split brain situation!\n");
                                mask.pdsk = D_MASK;
                                val.pdsk  = D_OUTDATED;
 
@@ -598,7 +615,7 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
                           retry at most once more in this case. */
                        int timeo;
                        rcu_read_lock();
-                       nc = rcu_dereference(device->tconn->net_conf);
+                       nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
                        timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
                        rcu_read_unlock();
                        schedule_timeout_interruptible(timeo);
@@ -619,7 +636,7 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
                goto out;
 
        if (forced)
-               dev_warn(DEV, "Forced to consider local data as UpToDate!\n");
+               drbd_warn(device, "Forced to consider local data as UpToDate!\n");
 
        /* Wait until nothing is on the fly :) */
        wait_event(device->misc_wait, atomic_read(&device->ap_pending_cnt) == 0);
@@ -633,11 +650,11 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
                        put_ldev(device);
                }
        } else {
-               mutex_lock(&device->tconn->conf_update);
-               nc = device->tconn->net_conf;
+               mutex_lock(&first_peer_device(device)->connection->conf_update);
+               nc = first_peer_device(device)->connection->net_conf;
                if (nc)
                        nc->discard_my_data = 0; /* without copy; single bit op is atomic */
-               mutex_unlock(&device->tconn->conf_update);
+               mutex_unlock(&first_peer_device(device)->connection->conf_update);
 
                set_disk_ro(device->vdisk, false);
                if (get_ldev(device)) {
@@ -888,7 +905,7 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
                if (rs && u_size == 0) {
                        /* Remove "rs &&" later. This check should always be active, but
                           right now the receiver expects the permissive behavior */
-                       dev_warn(DEV, "Implicit shrink not allowed. "
+                       drbd_warn(device, "Implicit shrink not allowed. "
                                 "Use --size=%llus for explicit shrink.\n",
                                 (unsigned long long)size);
                        rv = DS_ERROR_SHRINK;
@@ -907,10 +924,10 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
                        /* currently there is only one error: ENOMEM! */
                        size = drbd_bm_capacity(device)>>1;
                        if (size == 0) {
-                               dev_err(DEV, "OUT OF MEMORY! "
+                               drbd_err(device, "OUT OF MEMORY! "
                                    "Could not allocate bitmap!\n");
                        } else {
-                               dev_err(DEV, "BM resizing failed. "
+                               drbd_err(device, "BM resizing failed. "
                                    "Leaving size unchanged at size = %lu KB\n",
                                    (unsigned long)size);
                        }
@@ -919,7 +936,7 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
                /* racy, see comments above. */
                drbd_set_my_capacity(device, size);
                device->ldev->md.la_size_sect = size;
-               dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
+               drbd_info(device, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
                     (unsigned long long)size>>1);
        }
        if (rv <= DS_ERROR)
@@ -939,7 +956,7 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
                md->flags &= ~MDF_PRIMARY_IND;
                drbd_md_write(device, buffer);
 
-               dev_info(DEV, "Writing the whole bitmap, %s\n",
+               drbd_info(device, "Writing the whole bitmap, %s\n",
                         la_size_changed && md_moved ? "size changed and md moved" :
                         la_size_changed ? "size changed" : "md moved");
                /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */
@@ -951,8 +968,8 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
                drbd_md_write(device, buffer);
 
                if (rs)
-                       dev_info(DEV, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
-                                md->al_stripes, md->al_stripe_size_4k * 4);
+                       drbd_info(device, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n",
+                                 md->al_stripes, md->al_stripe_size_4k * 4);
        }
 
        if (size > la_size_sect)
@@ -990,7 +1007,7 @@ drbd_new_dev_size(struct drbd_device *device, struct drbd_backing_dev *bdev,
        m_size = drbd_get_max_capacity(bdev);
 
        if (device->state.conn < C_CONNECTED && assume_peer_has_space) {
-               dev_warn(DEV, "Resize while not connected was forced by the user!\n");
+               drbd_warn(device, "Resize while not connected was forced by the user!\n");
                p_size = m_size;
        }
 
@@ -1012,11 +1029,11 @@ drbd_new_dev_size(struct drbd_device *device, struct drbd_backing_dev *bdev,
        }
 
        if (size == 0)
-               dev_err(DEV, "Both nodes diskless!\n");
+               drbd_err(device, "Both nodes diskless!\n");
 
        if (u_size) {
                if (u_size > size)
-                       dev_err(DEV, "Requested disk size is too big (%lu > %lu)\n",
+                       drbd_err(device, "Requested disk size is too big (%lu > %lu)\n",
                            (unsigned long)u_size>>1, (unsigned long)size>>1);
                else
                        size = u_size;
@@ -1050,7 +1067,7 @@ static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
                dc->al_extents, sizeof(struct lc_element), 0);
 
        if (n == NULL) {
-               dev_err(DEV, "Cannot allocate act_log lru!\n");
+               drbd_err(device, "Cannot allocate act_log lru!\n");
                return -ENOMEM;
        }
        spin_lock_irq(&device->al_lock);
@@ -1058,7 +1075,7 @@ static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
                for (i = 0; i < t->nr_elements; i++) {
                        e = lc_element_by_index(t, i);
                        if (e->refcnt)
-                               dev_err(DEV, "refcnt(%d)==%d\n",
+                               drbd_err(device, "refcnt(%d)==%d\n",
                                    e->lc_number, e->refcnt);
                        in_use += e->refcnt;
                }
@@ -1067,7 +1084,7 @@ static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
                device->act_log = n;
        spin_unlock_irq(&device->al_lock);
        if (in_use) {
-               dev_err(DEV, "Activity log still in use!\n");
+               drbd_err(device, "Activity log still in use!\n");
                lc_destroy(n);
                return -EBUSY;
        } else {
@@ -1106,7 +1123,7 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_
                blk_queue_stack_limits(q, b);
 
                if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
-                       dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+                       drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
                                 q->backing_dev_info.ra_pages,
                                 b->backing_dev_info.ra_pages);
                        q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
@@ -1134,12 +1151,12 @@ void drbd_reconsider_max_bio_size(struct drbd_device *device)
           Because new from 8.3.8 onwards the peer can use multiple
           BIOs for a single peer_request */
        if (device->state.conn >= C_WF_REPORT_PARAMS) {
-               if (device->tconn->agreed_pro_version < 94)
+               if (first_peer_device(device)->connection->agreed_pro_version < 94)
                        peer = min(device->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
                        /* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
-               else if (device->tconn->agreed_pro_version == 94)
+               else if (first_peer_device(device)->connection->agreed_pro_version == 94)
                        peer = DRBD_MAX_SIZE_H80_PACKET;
-               else if (device->tconn->agreed_pro_version < 100)
+               else if (first_peer_device(device)->connection->agreed_pro_version < 100)
                        peer = DRBD_MAX_BIO_SIZE_P95;  /* drbd 8.3.8 onwards, before 8.4.0 */
                else
                        peer = DRBD_MAX_BIO_SIZE;
@@ -1148,34 +1165,34 @@ void drbd_reconsider_max_bio_size(struct drbd_device *device)
        new = min(local, peer);
 
        if (device->state.role == R_PRIMARY && new < now)
-               dev_err(DEV, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
+               drbd_err(device, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
 
        if (new != now)
-               dev_info(DEV, "max BIO size = %u\n", new);
+               drbd_info(device, "max BIO size = %u\n", new);
 
        drbd_setup_queue_param(device, new);
 }
 
 /* Starts the worker thread */
-static void conn_reconfig_start(struct drbd_tconn *tconn)
+static void conn_reconfig_start(struct drbd_connection *connection)
 {
-       drbd_thread_start(&tconn->worker);
-       conn_flush_workqueue(tconn);
+       drbd_thread_start(&connection->worker);
+       conn_flush_workqueue(connection);
 }
 
 /* if still unconfigured, stops worker again. */
-static void conn_reconfig_done(struct drbd_tconn *tconn)
+static void conn_reconfig_done(struct drbd_connection *connection)
 {
        bool stop_threads;
-       spin_lock_irq(&tconn->req_lock);
-       stop_threads = conn_all_vols_unconf(tconn) &&
-               tconn->cstate == C_STANDALONE;
-       spin_unlock_irq(&tconn->req_lock);
+       spin_lock_irq(&connection->req_lock);
+       stop_threads = conn_all_vols_unconf(connection) &&
+               connection->cstate == C_STANDALONE;
+       spin_unlock_irq(&connection->req_lock);
        if (stop_threads) {
                /* asender is implicitly stopped by receiver
                 * in conn_disconnect() */
-               drbd_thread_stop(&tconn->receiver);
-               drbd_thread_stop(&tconn->worker);
+               drbd_thread_stop(&connection->receiver);
+               drbd_thread_stop(&connection->worker);
        }
 }
 
@@ -1185,19 +1202,19 @@ static void drbd_suspend_al(struct drbd_device *device)
        int s = 0;
 
        if (!lc_try_lock(device->act_log)) {
-               dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n");
+               drbd_warn(device, "Failed to lock al in drbd_suspend_al()\n");
                return;
        }
 
        drbd_al_shrink(device);
-       spin_lock_irq(&device->tconn->req_lock);
+       spin_lock_irq(&first_peer_device(device)->connection->req_lock);
        if (device->state.conn < C_CONNECTED)
                s = !test_and_set_bit(AL_SUSPENDED, &device->flags);
-       spin_unlock_irq(&device->tconn->req_lock);
+       spin_unlock_irq(&first_peer_device(device)->connection->req_lock);
        lc_unlock(device->act_log);
 
        if (s)
-               dev_info(DEV, "Suspended AL updates\n");
+               drbd_info(device, "Suspended AL updates\n");
 }
 
 
@@ -1264,7 +1281,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
                goto fail;
        }
 
-       mutex_lock(&device->tconn->conf_update);
+       mutex_lock(&first_peer_device(device)->connection->conf_update);
        old_disk_conf = device->ldev->disk_conf;
        *new_disk_conf = *old_disk_conf;
        if (should_set_defaults(info))
@@ -1292,7 +1309,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
        if (fifo_size != device->rs_plan_s->size) {
                new_plan = fifo_alloc(fifo_size);
                if (!new_plan) {
-                       dev_err(DEV, "kmalloc of fifo_buffer failed");
+                       drbd_err(device, "kmalloc of fifo_buffer failed");
                        retcode = ERR_NOMEM;
                        goto fail_unlock;
                }
@@ -1327,7 +1344,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
                rcu_assign_pointer(device->rs_plan_s, new_plan);
        }
 
-       mutex_unlock(&device->tconn->conf_update);
+       mutex_unlock(&first_peer_device(device)->connection->conf_update);
 
        if (new_disk_conf->al_updates)
                device->ldev->md.flags &= ~MDF_AL_DISABLED;
@@ -1339,7 +1356,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
        else
                set_bit(MD_NO_FUA, &device->flags);
 
-       drbd_bump_write_ordering(device->tconn, WO_bdev_flush);
+       drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
 
        drbd_md_sync(device);
 
@@ -1353,7 +1370,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
        goto success;
 
 fail_unlock:
-       mutex_unlock(&device->tconn->conf_update);
+       mutex_unlock(&first_peer_device(device)->connection->conf_update);
  fail:
        kfree(new_disk_conf);
        kfree(new_plan);
@@ -1388,7 +1405,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
                goto finish;
 
        device = adm_ctx.device;
-       conn_reconfig_start(device->tconn);
+       conn_reconfig_start(first_peer_device(device)->connection);
 
        /* if you want to reconfigure, please tear down first */
        if (device->state.disk > D_DISKLESS) {
@@ -1455,7 +1472,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
                goto fail;
 
        rcu_read_lock();
-       nc = rcu_dereference(device->tconn->net_conf);
+       nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
        if (nc) {
                if (new_disk_conf->fencing == FP_STONITH && nc->wire_protocol == DRBD_PROT_A) {
                        rcu_read_unlock();
@@ -1468,7 +1485,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        bdev = blkdev_get_by_path(new_disk_conf->backing_dev,
                                  FMODE_READ | FMODE_WRITE | FMODE_EXCL, device);
        if (IS_ERR(bdev)) {
-               dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
+               drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
                        PTR_ERR(bdev));
                retcode = ERR_OPEN_DISK;
                goto fail;
@@ -1488,7 +1505,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
                                  (new_disk_conf->meta_dev_idx < 0) ?
                                  (void *)device : (void *)drbd_m_holder);
        if (IS_ERR(bdev)) {
-               dev_err(DEV, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
+               drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
                        PTR_ERR(bdev));
                retcode = ERR_OPEN_MD_DISK;
                goto fail;
@@ -1522,7 +1539,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
                new_disk_conf->al_extents = drbd_al_extents_max(nbc);
 
        if (drbd_get_max_capacity(nbc) < new_disk_conf->disk_size) {
-               dev_err(DEV, "max capacity %llu smaller than disk size %llu\n",
+               drbd_err(device, "max capacity %llu smaller than disk size %llu\n",
                        (unsigned long long) drbd_get_max_capacity(nbc),
                        (unsigned long long) new_disk_conf->disk_size);
                retcode = ERR_DISK_TOO_SMALL;
@@ -1540,7 +1557,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
 
        if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) {
                retcode = ERR_MD_DISK_TOO_SMALL;
-               dev_warn(DEV, "refusing attach: md-device too small, "
+               drbd_warn(device, "refusing attach: md-device too small, "
                     "at least %llu sectors needed for this meta-disk type\n",
                     (unsigned long long) min_md_device_sectors);
                goto fail;
@@ -1557,11 +1574,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
 
        if (nbc->known_size > max_possible_sectors) {
-               dev_warn(DEV, "==> truncating very big lower level device "
+               drbd_warn(device, "==> truncating very big lower level device "
                        "to currently maximum possible %llu sectors <==\n",
                        (unsigned long long) max_possible_sectors);
                if (new_disk_conf->meta_dev_idx >= 0)
-                       dev_warn(DEV, "==>> using internal or flexible "
+                       drbd_warn(device, "==>> using internal or flexible "
                                      "meta data may help <<==\n");
        }
 
@@ -1596,7 +1613,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        if (device->state.conn < C_CONNECTED &&
            device->state.role == R_PRIMARY &&
            (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) {
-               dev_err(DEV, "Can only attach to data with current UUID=%016llX\n",
+               drbd_err(device, "Can only attach to data with current UUID=%016llX\n",
                    (unsigned long long)device->ed_uuid);
                retcode = ERR_DATA_NOT_CURRENT;
                goto force_diskless_dec;
@@ -1611,7 +1628,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        /* Prevent shrinking of consistent devices ! */
        if (drbd_md_test_flag(nbc, MDF_CONSISTENT) &&
            drbd_new_dev_size(device, nbc, nbc->disk_conf->disk_size, 0) < nbc->md.la_size_sect) {
-               dev_warn(DEV, "refusing to truncate a consistent device\n");
+               drbd_warn(device, "refusing to truncate a consistent device\n");
                retcode = ERR_DISK_TOO_SMALL;
                goto force_diskless_dec;
        }
@@ -1627,7 +1644,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
         * Devices and memory are no longer released by error cleanup below.
         * now device takes over responsibility, and the state engine should
         * clean it up somewhere.  */
-       D_ASSERT(device->ldev == NULL);
+       D_ASSERT(device, device->ldev == NULL);
        device->ldev = nbc;
        device->resync = resync_lru;
        device->rs_plan_s = new_plan;
@@ -1636,7 +1653,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        new_disk_conf = NULL;
        new_plan = NULL;
 
-       drbd_bump_write_ordering(device->tconn, WO_bdev_flush);
+       drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
 
        if (drbd_md_test_flag(device->ldev, MDF_CRASHED_PRIMARY))
                set_bit(CRASHED_PRIMARY, &device->flags);
@@ -1644,7 +1661,8 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
                clear_bit(CRASHED_PRIMARY, &device->flags);
 
        if (drbd_md_test_flag(device->ldev, MDF_PRIMARY_IND) &&
-           !(device->state.role == R_PRIMARY && device->tconn->susp_nod))
+           !(device->state.role == R_PRIMARY &&
+             first_peer_device(device)->connection->susp_nod))
                set_bit(CRASHED_PRIMARY, &device->flags);
 
        device->send_cnt = 0;
@@ -1684,7 +1702,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC) ||
            (test_bit(CRASHED_PRIMARY, &device->flags) &&
             drbd_md_test_flag(device->ldev, MDF_AL_DISABLED))) {
-               dev_info(DEV, "Assuming that all blocks are out of sync "
+               drbd_info(device, "Assuming that all blocks are out of sync "
                     "(aka FullSync)\n");
                if (drbd_bitmap_io(device, &drbd_bmio_set_n_write,
                        "set_n_write from attaching", BM_LOCKED_MASK)) {
@@ -1702,7 +1720,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        if (_drbd_bm_total_weight(device) == drbd_bm_bits(device))
                drbd_suspend_al(device); /* IO is still suspended here... */
 
-       spin_lock_irq(&device->tconn->req_lock);
+       spin_lock_irq(&first_peer_device(device)->connection->req_lock);
        os = drbd_read_state(device);
        ns = os;
        /* If MDF_CONSISTENT is not set go into inconsistent state,
@@ -1754,7 +1772,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        }
 
        rv = _drbd_set_state(device, ns, CS_VERBOSE, NULL);
-       spin_unlock_irq(&device->tconn->req_lock);
+       spin_unlock_irq(&first_peer_device(device)->connection->req_lock);
 
        if (rv < SS_SUCCESS)
                goto force_diskless_dec;
@@ -1771,7 +1789,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
 
        kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
        put_ldev(device);
-       conn_reconfig_done(device->tconn);
+       conn_reconfig_done(first_peer_device(device)->connection);
        drbd_adm_finish(info, retcode);
        return 0;
 
@@ -1781,7 +1799,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
        drbd_force_state(device, NS(disk, D_DISKLESS));
        drbd_md_sync(device);
  fail:
-       conn_reconfig_done(device->tconn);
+       conn_reconfig_done(first_peer_device(device)->connection);
        if (nbc) {
                if (nbc->backing_bdev)
                        blkdev_put(nbc->backing_bdev,
@@ -1860,14 +1878,15 @@ out:
        return 0;
 }
 
-static bool conn_resync_running(struct drbd_tconn *tconn)
+static bool conn_resync_running(struct drbd_connection *connection)
 {
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        bool rv = false;
        int vnr;
 
        rcu_read_lock();
-       idr_for_each_entry(&tconn->volumes, device, vnr) {
+       idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+               struct drbd_device *device = peer_device->device;
                if (device->state.conn == C_SYNC_SOURCE ||
                    device->state.conn == C_SYNC_TARGET ||
                    device->state.conn == C_PAUSED_SYNC_S ||
@@ -1881,14 +1900,15 @@ static bool conn_resync_running(struct drbd_tconn *tconn)
        return rv;
 }
 
-static bool conn_ov_running(struct drbd_tconn *tconn)
+static bool conn_ov_running(struct drbd_connection *connection)
 {
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        bool rv = false;
        int vnr;
 
        rcu_read_lock();
-       idr_for_each_entry(&tconn->volumes, device, vnr) {
+       idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+               struct drbd_device *device = peer_device->device;
                if (device->state.conn == C_VERIFY_S ||
                    device->state.conn == C_VERIFY_T) {
                        rv = true;
@@ -1901,12 +1921,12 @@ static bool conn_ov_running(struct drbd_tconn *tconn)
 }
 
 static enum drbd_ret_code
-_check_net_options(struct drbd_tconn *tconn, struct net_conf *old_conf, struct net_conf *new_conf)
+_check_net_options(struct drbd_connection *connection, struct net_conf *old_conf, struct net_conf *new_conf)
 {
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        int i;
 
-       if (old_conf && tconn->cstate == C_WF_REPORT_PARAMS && tconn->agreed_pro_version < 100) {
+       if (old_conf && connection->cstate == C_WF_REPORT_PARAMS && connection->agreed_pro_version < 100) {
                if (new_conf->wire_protocol != old_conf->wire_protocol)
                        return ERR_NEED_APV_100;
 
@@ -1918,15 +1938,16 @@ _check_net_options(struct drbd_tconn *tconn, struct net_conf *old_conf, struct n
        }
 
        if (!new_conf->two_primaries &&
-           conn_highest_role(tconn) == R_PRIMARY &&
-           conn_highest_peer(tconn) == R_PRIMARY)
+           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))
                return ERR_NOT_PROTO_C;
 
-       idr_for_each_entry(&tconn->volumes, device, i) {
+       idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+               struct drbd_device *device = peer_device->device;
                if (get_ldev(device)) {
                        enum drbd_fencing_p fp = rcu_dereference(device->ldev->disk_conf)->fencing;
                        put_ldev(device);
@@ -1944,18 +1965,19 @@ _check_net_options(struct drbd_tconn *tconn, struct net_conf *old_conf, struct n
 }
 
 static enum drbd_ret_code
-check_net_options(struct drbd_tconn *tconn, struct net_conf *new_conf)
+check_net_options(struct drbd_connection *connection, struct net_conf *new_conf)
 {
        static enum drbd_ret_code rv;
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        int i;
 
        rcu_read_lock();
-       rv = _check_net_options(tconn, rcu_dereference(tconn->net_conf), new_conf);
+       rv = _check_net_options(connection, rcu_dereference(connection->net_conf), new_conf);
        rcu_read_unlock();
 
-       /* tconn->volumes protected by genl_lock() here */
-       idr_for_each_entry(&tconn->volumes, device, i) {
+       /* connection->volumes protected by genl_lock() here */
+       idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+               struct drbd_device *device = peer_device->device;
                if (!device->bitmap) {
                        if (drbd_bm_init(device))
                                return ERR_NOMEM;
@@ -2027,7 +2049,7 @@ static void free_crypto(struct crypto *crypto)
 int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
 {
        enum drbd_ret_code retcode;
-       struct drbd_tconn *tconn;
+       struct drbd_connection *connection;
        struct net_conf *old_conf, *new_conf = NULL;
        int err;
        int ovr; /* online verify running */
@@ -2040,7 +2062,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
-       tconn = adm_ctx.tconn;
+       connection = adm_ctx.connection;
 
        new_conf = kzalloc(sizeof(struct net_conf), GFP_KERNEL);
        if (!new_conf) {
@@ -2048,11 +2070,11 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       conn_reconfig_start(tconn);
+       conn_reconfig_start(connection);
 
-       mutex_lock(&tconn->data.mutex);
-       mutex_lock(&tconn->conf_update);
-       old_conf = tconn->net_conf;
+       mutex_lock(&connection->data.mutex);
+       mutex_lock(&connection->conf_update);
+       old_conf = connection->net_conf;
 
        if (!old_conf) {
                drbd_msg_put_info("net conf missing, try connect");
@@ -2071,19 +2093,19 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
                goto fail;
        }
 
-       retcode = check_net_options(tconn, new_conf);
+       retcode = check_net_options(connection, new_conf);
        if (retcode != NO_ERROR)
                goto fail;
 
        /* re-sync running */
-       rsr = conn_resync_running(tconn);
+       rsr = conn_resync_running(connection);
        if (rsr && strcmp(new_conf->csums_alg, old_conf->csums_alg)) {
                retcode = ERR_CSUMS_RESYNC_RUNNING;
                goto fail;
        }
 
        /* online verify running */
-       ovr = conn_ov_running(tconn);
+       ovr = conn_ov_running(connection);
        if (ovr && strcmp(new_conf->verify_alg, old_conf->verify_alg)) {
                retcode = ERR_VERIFY_RUNNING;
                goto fail;
@@ -2093,45 +2115,45 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto fail;
 
-       rcu_assign_pointer(tconn->net_conf, new_conf);
+       rcu_assign_pointer(connection->net_conf, new_conf);
 
        if (!rsr) {
-               crypto_free_hash(tconn->csums_tfm);
-               tconn->csums_tfm = crypto.csums_tfm;
+               crypto_free_hash(connection->csums_tfm);
+               connection->csums_tfm = crypto.csums_tfm;
                crypto.csums_tfm = NULL;
        }
        if (!ovr) {
-               crypto_free_hash(tconn->verify_tfm);
-               tconn->verify_tfm = crypto.verify_tfm;
+               crypto_free_hash(connection->verify_tfm);
+               connection->verify_tfm = crypto.verify_tfm;
                crypto.verify_tfm = NULL;
        }
 
-       crypto_free_hash(tconn->integrity_tfm);
-       tconn->integrity_tfm = crypto.integrity_tfm;
-       if (tconn->cstate >= C_WF_REPORT_PARAMS && tconn->agreed_pro_version >= 100)
-               /* Do this without trying to take tconn->data.mutex again.  */
-               __drbd_send_protocol(tconn, P_PROTOCOL_UPDATE);
+       crypto_free_hash(connection->integrity_tfm);
+       connection->integrity_tfm = crypto.integrity_tfm;
+       if (connection->cstate >= C_WF_REPORT_PARAMS && connection->agreed_pro_version >= 100)
+               /* Do this without trying to take connection->data.mutex again.  */
+               __drbd_send_protocol(connection, P_PROTOCOL_UPDATE);
 
-       crypto_free_hash(tconn->cram_hmac_tfm);
-       tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
+       crypto_free_hash(connection->cram_hmac_tfm);
+       connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
 
-       mutex_unlock(&tconn->conf_update);
-       mutex_unlock(&tconn->data.mutex);
+       mutex_unlock(&connection->conf_update);
+       mutex_unlock(&connection->data.mutex);
        synchronize_rcu();
        kfree(old_conf);
 
-       if (tconn->cstate >= C_WF_REPORT_PARAMS)
-               drbd_send_sync_param(minor_to_device(conn_lowest_minor(tconn)));
+       if (connection->cstate >= C_WF_REPORT_PARAMS)
+               drbd_send_sync_param(minor_to_device(conn_lowest_minor(connection)));
 
        goto done;
 
  fail:
-       mutex_unlock(&tconn->conf_update);
-       mutex_unlock(&tconn->data.mutex);
+       mutex_unlock(&connection->conf_update);
+       mutex_unlock(&connection->data.mutex);
        free_crypto(&crypto);
        kfree(new_conf);
  done:
-       conn_reconfig_done(tconn);
+       conn_reconfig_done(connection);
  out:
        drbd_adm_finish(info, retcode);
        return 0;
@@ -2139,10 +2161,11 @@ 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_device *device;
+       struct drbd_peer_device *peer_device;
        struct net_conf *old_conf, *new_conf = NULL;
        struct crypto crypto = { };
-       struct drbd_tconn *tconn;
+       struct drbd_resource *resource;
+       struct drbd_connection *connection;
        enum drbd_ret_code retcode;
        int i;
        int err;
@@ -2162,24 +2185,28 @@ 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(tconn, &drbd_tconns, all_tconn) {
-               if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len &&
-                   !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->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) == tconn->peer_addr_len &&
-                   !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->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;
+                       }
                }
        }
 
-       tconn = adm_ctx.tconn;
-       conn_reconfig_start(tconn);
+       connection = adm_ctx.connection;
+       conn_reconfig_start(connection);
 
-       if (tconn->cstate > C_STANDALONE) {
+       if (connection->cstate > C_STANDALONE) {
                retcode = ERR_NET_CONFIGURED;
                goto fail;
        }
@@ -2200,7 +2227,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
                goto fail;
        }
 
-       retcode = check_net_options(tconn, new_conf);
+       retcode = check_net_options(connection, new_conf);
        if (retcode != NO_ERROR)
                goto fail;
 
@@ -2210,40 +2237,41 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
 
        ((char *)new_conf->shared_secret)[SHARED_SECRET_MAX-1] = 0;
 
-       conn_flush_workqueue(tconn);
+       conn_flush_workqueue(connection);
 
-       mutex_lock(&tconn->conf_update);
-       old_conf = tconn->net_conf;
+       mutex_lock(&connection->conf_update);
+       old_conf = connection->net_conf;
        if (old_conf) {
                retcode = ERR_NET_CONFIGURED;
-               mutex_unlock(&tconn->conf_update);
+               mutex_unlock(&connection->conf_update);
                goto fail;
        }
-       rcu_assign_pointer(tconn->net_conf, new_conf);
+       rcu_assign_pointer(connection->net_conf, new_conf);
 
-       conn_free_crypto(tconn);
-       tconn->cram_hmac_tfm = crypto.cram_hmac_tfm;
-       tconn->integrity_tfm = crypto.integrity_tfm;
-       tconn->csums_tfm = crypto.csums_tfm;
-       tconn->verify_tfm = crypto.verify_tfm;
+       conn_free_crypto(connection);
+       connection->cram_hmac_tfm = crypto.cram_hmac_tfm;
+       connection->integrity_tfm = crypto.integrity_tfm;
+       connection->csums_tfm = crypto.csums_tfm;
+       connection->verify_tfm = crypto.verify_tfm;
 
-       tconn->my_addr_len = nla_len(adm_ctx.my_addr);
-       memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len);
-       tconn->peer_addr_len = nla_len(adm_ctx.peer_addr);
-       memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len);
+       connection->my_addr_len = nla_len(adm_ctx.my_addr);
+       memcpy(&connection->my_addr, nla_data(adm_ctx.my_addr), connection->my_addr_len);
+       connection->peer_addr_len = nla_len(adm_ctx.peer_addr);
+       memcpy(&connection->peer_addr, nla_data(adm_ctx.peer_addr), connection->peer_addr_len);
 
-       mutex_unlock(&tconn->conf_update);
+       mutex_unlock(&connection->conf_update);
 
        rcu_read_lock();
-       idr_for_each_entry(&tconn->volumes, device, i) {
+       idr_for_each_entry(&connection->peer_devices, peer_device, i) {
+               struct drbd_device *device = peer_device->device;
                device->send_cnt = 0;
                device->recv_cnt = 0;
        }
        rcu_read_unlock();
 
-       retcode = conn_request_state(tconn, NS(conn, C_UNCONNECTED), CS_VERBOSE);
+       retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE);
 
-       conn_reconfig_done(tconn);
+       conn_reconfig_done(connection);
        drbd_adm_finish(info, retcode);
        return 0;
 
@@ -2251,17 +2279,17 @@ fail:
        free_crypto(&crypto);
        kfree(new_conf);
 
-       conn_reconfig_done(tconn);
+       conn_reconfig_done(connection);
 out:
        drbd_adm_finish(info, retcode);
        return 0;
 }
 
-static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool force)
+static enum drbd_state_rv conn_try_disconnect(struct drbd_connection *connection, bool force)
 {
        enum drbd_state_rv rv;
 
-       rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
+       rv = conn_request_state(connection, NS(conn, C_DISCONNECTING),
                        force ? CS_HARD : 0);
 
        switch (rv) {
@@ -2271,18 +2299,18 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
                return SS_SUCCESS;
        case SS_PRIMARY_NOP:
                /* Our state checking code wants to see the peer outdated. */
-               rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
+               rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING, pdsk, D_OUTDATED), 0);
 
                if (rv == SS_OUTDATE_WO_CONN) /* lost connection before graceful disconnect succeeded */
-                       rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_VERBOSE);
+                       rv = conn_request_state(connection, NS(conn, C_DISCONNECTING), CS_VERBOSE);
 
                break;
        case SS_CW_FAILED_BY_PEER:
                /* The peer probably wants to see us outdated. */
-               rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+               rv = conn_request_state(connection, NS2(conn, C_DISCONNECTING,
                                                        disk, D_OUTDATED), 0);
                if (rv == SS_IS_DISKLESS || rv == SS_LOWER_THAN_OUTDATED) {
-                       rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING),
+                       rv = conn_request_state(connection, NS(conn, C_DISCONNECTING),
                                        CS_HARD);
                }
                break;
@@ -2296,7 +2324,7 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
                 * The state handling only uses drbd_thread_stop_nowait(),
                 * we want to really wait here until the receiver is no more.
                 */
-               drbd_thread_stop(&adm_ctx.tconn->receiver);
+               drbd_thread_stop(&connection->receiver);
 
                /* Race breaker.  This additional state change request may be
                 * necessary, if this was a forced disconnect during a receiver
@@ -2304,10 +2332,10 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
                 * after drbdd_init() returned.  Typically, we should be
                 * C_STANDALONE already, now, and this becomes a no-op.
                 */
-               rv2 = conn_request_state(tconn, NS(conn, C_STANDALONE),
+               rv2 = conn_request_state(connection, NS(conn, C_STANDALONE),
                                CS_VERBOSE | CS_HARD);
                if (rv2 < SS_SUCCESS)
-                       conn_err(tconn,
+                       drbd_err(connection,
                                "unexpected rv2=%d in conn_try_disconnect()\n",
                                rv2);
        }
@@ -2317,7 +2345,7 @@ static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool for
 int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
 {
        struct disconnect_parms parms;
-       struct drbd_tconn *tconn;
+       struct drbd_connection *connection;
        enum drbd_state_rv rv;
        enum drbd_ret_code retcode;
        int err;
@@ -2328,7 +2356,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto fail;
 
-       tconn = adm_ctx.tconn;
+       connection = adm_ctx.connection;
        memset(&parms, 0, sizeof(parms));
        if (info->attrs[DRBD_NLA_DISCONNECT_PARMS]) {
                err = disconnect_parms_from_attrs(&parms, info);
@@ -2339,7 +2367,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       rv = conn_try_disconnect(tconn, parms.force_disconnect);
+       rv = conn_try_disconnect(connection, parms.force_disconnect);
        if (rv < SS_SUCCESS)
                retcode = rv;  /* FIXME: Type mismatch. */
        else
@@ -2353,11 +2381,11 @@ void resync_after_online_grow(struct drbd_device *device)
 {
        int iass; /* I am sync source */
 
-       dev_info(DEV, "Resync of new storage after online grow\n");
+       drbd_info(device, "Resync of new storage after online grow\n");
        if (device->state.role != device->state.peer)
                iass = (device->state.role == R_PRIMARY);
        else
-               iass = test_bit(RESOLVE_CONFLICTS, &device->tconn->flags);
+               iass = test_bit(RESOLVE_CONFLICTS, &first_peer_device(device)->connection->flags);
 
        if (iass)
                drbd_start_resync(device, C_SYNC_SOURCE);
@@ -2412,7 +2440,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
                goto fail_ldev;
        }
 
-       if (rs.no_resync && device->tconn->agreed_pro_version < 93) {
+       if (rs.no_resync && first_peer_device(device)->connection->agreed_pro_version < 93) {
                retcode = ERR_NEED_APV_93;
                goto fail_ldev;
        }
@@ -2454,12 +2482,12 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
                device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
 
        if (new_disk_conf) {
-               mutex_lock(&device->tconn->conf_update);
+               mutex_lock(&first_peer_device(device)->connection->conf_update);
                old_disk_conf = device->ldev->disk_conf;
                *new_disk_conf = *old_disk_conf;
                new_disk_conf->disk_size = (sector_t)rs.resize_size;
                rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf);
-               mutex_unlock(&device->tconn->conf_update);
+               mutex_unlock(&first_peer_device(device)->connection->conf_update);
                synchronize_rcu();
                kfree(old_disk_conf);
        }
@@ -2499,7 +2527,6 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info)
 int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
 {
        enum drbd_ret_code retcode;
-       struct drbd_tconn *tconn;
        struct res_opts res_opts;
        int err;
 
@@ -2508,9 +2535,8 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
                return retcode;
        if (retcode != NO_ERROR)
                goto fail;
-       tconn = adm_ctx.tconn;
 
-       res_opts = tconn->res_opts;
+       res_opts = adm_ctx.resource->res_opts;
        if (should_set_defaults(info))
                set_res_opts_defaults(&res_opts);
 
@@ -2521,7 +2547,7 @@ int drbd_adm_resource_opts(struct sk_buff *skb, struct genl_info *info)
                goto fail;
        }
 
-       err = set_resource_options(tconn, &res_opts);
+       err = set_resource_options(adm_ctx.resource, &res_opts);
        if (err) {
                retcode = ERR_INVALID_REQUEST;
                if (err == -ENOMEM)
@@ -2710,9 +2736,9 @@ int drbd_adm_resume_io(struct sk_buff *skb, struct genl_info *info)
        retcode = drbd_request_state(device, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
        if (retcode == SS_SUCCESS) {
                if (device->state.conn < C_CONNECTED)
-                       tl_clear(device->tconn);
+                       tl_clear(first_peer_device(device)->connection);
                if (device->state.disk == D_DISKLESS || device->state.disk == D_FAILED)
-                       tl_restart(device->tconn, FAIL_FROZEN_DISK_IO);
+                       tl_restart(first_peer_device(device)->connection, FAIL_FROZEN_DISK_IO);
        }
        drbd_resume_io(device);
 
@@ -2727,23 +2753,27 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
 }
 
 static int nla_put_drbd_cfg_context(struct sk_buff *skb,
-               struct drbd_tconn *tconn, unsigned vnr)
+                                   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))
-               goto nla_put_failure;
-       if (nla_put_string(skb, T_ctx_resource_name, tconn->name))
+       if (device &&
+           nla_put_u32(skb, T_ctx_volume, device->vnr))
                goto nla_put_failure;
-       if (tconn->my_addr_len &&
-           nla_put(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr))
-               goto nla_put_failure;
-       if (tconn->peer_addr_len &&
-           nla_put(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr))
+       if (nla_put_string(skb, T_ctx_resource_name, connection->resource->name))
                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;
 
@@ -2753,9 +2783,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;
@@ -2779,10 +2822,10 @@ 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, device->tconn, 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->tconn->res_opts, exclude_sensitive))
+       if (res_opts_to_skb(skb, &device->resource->res_opts, exclude_sensitive))
                goto nla_put_failure;
 
        rcu_read_lock();
@@ -2795,7 +2838,7 @@ static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
        if (!err) {
                struct net_conf *nc;
 
-               nc = rcu_dereference(device->tconn->net_conf);
+               nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
                if (nc)
                        err = net_conf_to_skb(skb, nc, exclude_sensitive);
        }
@@ -2899,18 +2942,19 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct drbd_device *device;
        struct drbd_genlmsghdr *dh;
-       struct drbd_tconn *pos = (struct drbd_tconn*)cb->args[0];
-       struct drbd_tconn *tconn = NULL;
-       struct drbd_tconn *tmp;
+       struct drbd_resource *pos = (struct drbd_resource *)cb->args[0];
+       struct drbd_resource *resource = NULL;
+       struct drbd_resource *tmp;
        unsigned volume = cb->args[1];
 
        /* Open coded, deferred, iteration:
-        * list_for_each_entry_safe(tconn, tmp, &drbd_tconns, all_tconn) {
-        *      idr_for_each_entry(&tconn->volumes, device, i) {
+        * for_each_resource_safe(resource, tmp, &drbd_resources) {
+        *      connection = "first connection of resource or undefined";
+        *      idr_for_each_entry(&resource->devices, device, i) {
         *        ...
         *      }
         * }
-        * where tconn 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,
@@ -2924,39 +2968,39 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
         * on each iteration.
         */
 
-       /* synchronize with conn_create()/conn_destroy() */
+       /* synchronize with conn_create()/drbd_destroy_connection() */
        rcu_read_lock();
        /* revalidate iterator position */
-       list_for_each_entry_rcu(tmp, &drbd_tconns, all_tconn) {
+       for_each_resource_rcu(tmp, &drbd_resources) {
                if (pos == NULL) {
                        /* first iteration */
                        pos = tmp;
-                       tconn = pos;
+                       resource = pos;
                        break;
                }
                if (tmp == pos) {
-                       tconn = pos;
+                       resource = pos;
                        break;
                }
        }
-       if (tconn) {
-next_tconn:
-               device = idr_get_next(&tconn->volumes, &volume);
+       if (resource) {
+next_resource:
+               device = idr_get_next(&resource->devices, &volume);
                if (!device) {
-                       /* No more volumes to dump on this tconn.
-                        * Advance tconn iterator. */
-                       pos = list_entry_rcu(tconn->all_tconn.next,
-                                            struct drbd_tconn, all_tconn);
-                       /* Did we dump any volume on this tconn 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->all_tconn == &drbd_tconns || cb->args[2])
+                               if (&pos->resources == &drbd_resources || cb->args[2])
                                        goto out;
                                volume = 0;
-                               tconn = pos;
-                               goto next_tconn;
+                               resource = pos;
+                               goto next_resource;
                        }
                }
 
@@ -2967,22 +3011,28 @@ next_tconn:
                        goto out;
 
                if (!device) {
-                       /* This is a tconn without a single volume.
+                       /* 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, tconn, VOLUME_UNSPECIFIED))
-                               goto cancel;
-                       nc = rcu_dereference(tconn->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;
                }
 
-               D_ASSERT(device->vnr == volume);
-               D_ASSERT(device->tconn == tconn);
+               D_ASSERT(device, device->vnr == volume);
+               D_ASSERT(device, device->resource == resource);
 
                dh->minor = device_to_minor(device);
                dh->ret_code = NO_ERROR;
@@ -2994,15 +3044,15 @@ cancel:
                }
 done:
                genlmsg_end(skb, dh);
-        }
+       }
 
 out:
        rcu_read_unlock();
        /* where to start the next iteration */
-        cb->args[0] = (long)pos;
-        cb->args[1] = (pos == tconn) ? volume + 1 : 0;
+       cb->args[0] = (long)pos;
+       cb->args[1] = (pos == resource) ? volume + 1 : 0;
 
-       /* No more tconns/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;
 }
@@ -3022,7 +3072,7 @@ 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 *resource_name;
-       struct drbd_tconn *tconn;
+       struct drbd_resource *resource;
        int maxtype;
 
        /* Is this a followup call? */
@@ -3051,18 +3101,19 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
        if (!nla)
                return -EINVAL;
        resource_name = nla_data(nla);
-       tconn = conn_get_by_name(resource_name);
-
-       if (!tconn)
+       if (!*resource_name)
+               return -ENODEV;
+       resource = drbd_find_resource(resource_name);
+       if (!resource)
                return -ENODEV;
 
-       kref_put(&tconn->kref, &conn_destroy); /* get_one_status() (re)validates tconn by itself */
+       kref_put(&resource->kref, drbd_destroy_resource); /* get_one_status() revalidates the resource */
 
        /* prime iterators, and set "filter" mode mark:
-        * only dump this tconn. */
-       cb->args[0] = (long)tconn;
+        * only dump this connection. */
+       cb->args[0] = (long)resource;
        /* cb->args[1] = 0; passed in this way. */
-       cb->args[2] = (long)tconn;
+       cb->args[2] = (long)resource;
 
 dump:
        return get_one_status(skb, cb);
@@ -3169,9 +3220,10 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* this is "skip initial sync", assume to be clean */
-       if (device->state.conn == C_CONNECTED && device->tconn->agreed_pro_version >= 90 &&
+       if (device->state.conn == C_CONNECTED &&
+           first_peer_device(device)->connection->agreed_pro_version >= 90 &&
            device->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) {
-               dev_info(DEV, "Preparing to skip initial sync\n");
+               drbd_info(device, "Preparing to skip initial sync\n");
                skip_initial_sync = 1;
        } else if (device->state.conn != C_STANDALONE) {
                retcode = ERR_CONNECTED;
@@ -3185,17 +3237,17 @@ int drbd_adm_new_c_uuid(struct sk_buff *skb, struct genl_info *info)
                err = drbd_bitmap_io(device, &drbd_bmio_clear_n_write,
                        "clear_n_write from new_c_uuid", BM_LOCKED_MASK);
                if (err) {
-                       dev_err(DEV, "Writing bitmap failed with %d\n",err);
+                       drbd_err(device, "Writing bitmap failed with %d\n", err);
                        retcode = ERR_IO_MD_DISK;
                }
                if (skip_initial_sync) {
                        drbd_send_uuids_skip_initial_sync(device);
                        _drbd_uuid_set(device, UI_BITMAP, 0);
                        drbd_print_uuids(device, "cleared bitmap UUID");
-                       spin_lock_irq(&device->tconn->req_lock);
+                       spin_lock_irq(&first_peer_device(device)->connection->req_lock);
                        _drbd_set_state(_NS2(device, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE),
                                        CS_VERBOSE, NULL);
-                       spin_unlock_irq(&device->tconn->req_lock);
+                       spin_unlock_irq(&first_peer_device(device)->connection->req_lock);
                }
        }
 
@@ -3249,7 +3301,7 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
-       if (adm_ctx.tconn) {
+       if (adm_ctx.resource) {
                if (info->nlhdr->nlmsg_flags & NLM_F_EXCL) {
                        retcode = ERR_INVALID_REQUEST;
                        drbd_msg_put_info("resource exists");
@@ -3265,7 +3317,7 @@ out:
        return 0;
 }
 
-int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
+int drbd_adm_new_minor(struct sk_buff *skb, struct genl_info *info)
 {
        struct drbd_genlmsghdr *dh = info->userhdr;
        enum drbd_ret_code retcode;
@@ -3288,7 +3340,7 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* drbd_adm_prepare made sure already
-        * that device->tconn and device->vnr match the request. */
+        * that first_peer_device(device)->connection and device->vnr match the request. */
        if (adm_ctx.device) {
                if (info->nlhdr->nlmsg_flags & NLM_F_EXCL)
                        retcode = ERR_MINOR_EXISTS;
@@ -3296,13 +3348,13 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       retcode = conn_new_minor(adm_ctx.tconn, dh->minor, adm_ctx.volume);
+       retcode = drbd_create_device(adm_ctx.connection, dh->minor, adm_ctx.volume);
 out:
        drbd_adm_finish(info, retcode);
        return 0;
 }
 
-static enum drbd_ret_code adm_delete_minor(struct drbd_device *device)
+static enum drbd_ret_code adm_del_minor(struct drbd_device *device)
 {
        if (device->state.disk == D_DISKLESS &&
            /* no need to be device->state.conn == C_STANDALONE &&
@@ -3311,18 +3363,13 @@ static enum drbd_ret_code adm_delete_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);
-               idr_remove(&device->tconn->volumes, device->vnr);
-               idr_remove(&minors, device_to_minor(device));
-               destroy_workqueue(device->submit.wq);
-               del_gendisk(device->vdisk);
-               synchronize_rcu();
-               kref_put(&device->kref, &drbd_minor_destroy);
+               drbd_delete_device(device);
                return NO_ERROR;
        } else
                return ERR_MINOR_CONFIGURED;
 }
 
-int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
+int drbd_adm_del_minor(struct sk_buff *skb, struct genl_info *info)
 {
        enum drbd_ret_code retcode;
 
@@ -3332,7 +3379,7 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
        if (retcode != NO_ERROR)
                goto out;
 
-       retcode = adm_delete_minor(adm_ctx.device);
+       retcode = adm_del_minor(adm_ctx.device);
 out:
        drbd_adm_finish(info, retcode);
        return 0;
@@ -3341,54 +3388,49 @@ out:
 int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
 {
        int retcode; /* enum drbd_ret_code rsp. enum drbd_state_rv */
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        unsigned i;
 
-       retcode = drbd_adm_prepare(skb, info, 0);
+       retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
        if (!adm_ctx.reply_skb)
                return retcode;
        if (retcode != NO_ERROR)
                goto out;
 
-       if (!adm_ctx.tconn) {
-               retcode = ERR_RES_NOT_KNOWN;
-               goto out;
-       }
-
        /* demote */
-       idr_for_each_entry(&adm_ctx.tconn->volumes, device, i) {
-               retcode = drbd_set_role(device, R_SECONDARY, 0);
+       idr_for_each_entry(&adm_ctx.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(adm_ctx.tconn, 0);
+       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.tconn->volumes, device, i) {
-               retcode = adm_detach(device, 0);
+       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
+               retcode = adm_detach(peer_device->device, 0);
                if (retcode < SS_SUCCESS || retcode > NO_ERROR) {
                        drbd_msg_put_info("failed to detach");
                        goto out;
                }
        }
 
-       /* If we reach this, all volumes (of this tconn) are Secondary,
+       /* 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.tconn->worker);
+       drbd_thread_stop(&adm_ctx.connection->worker);
 
        /* Now, nothing can fail anymore */
 
        /* delete volumes */
-       idr_for_each_entry(&adm_ctx.tconn->volumes, device, i) {
-               retcode = adm_delete_minor(device);
+       idr_for_each_entry(&adm_ctx.connection->peer_devices, peer_device, i) {
+               retcode = adm_del_minor(peer_device->device);
                if (retcode != NO_ERROR) {
                        /* "can not happen" */
                        drbd_msg_put_info("failed to delete volume");
@@ -3397,10 +3439,12 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* delete connection */
-       if (conn_lowest_minor(adm_ctx.tconn) < 0) {
-               list_del_rcu(&adm_ctx.tconn->all_tconn);
+       if (conn_lowest_minor(adm_ctx.connection) < 0) {
+               struct drbd_resource *resource = adm_ctx.connection->resource;
+
+               list_del_rcu(&resource->resources);
                synchronize_rcu();
-               kref_put(&adm_ctx.tconn->kref, &conn_destroy);
+               drbd_free_resource(resource);
 
                retcode = NO_ERROR;
        } else {
@@ -3416,6 +3460,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);
@@ -3424,18 +3470,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.tconn) < 0) {
-               list_del_rcu(&adm_ctx.tconn->all_tconn);
-               synchronize_rcu();
-               kref_put(&adm_ctx.tconn->kref, &conn_destroy);
-
-               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.tconn->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;
@@ -3481,7 +3533,7 @@ void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib)
 nla_put_failure:
        nlmsg_free(msg);
 failed:
-       dev_err(DEV, "Error %d while broadcasting event. "
+       drbd_err(device, "Error %d while broadcasting event. "
                        "Event seq:%u sib_reason:%u\n",
                        err, seq, sib->sib_reason);
 }
This page took 0.058125 seconds and 5 git commands to generate.