drbd: Pass a peer device to a number of fuctions
[deliverable/linux.git] / drivers / block / drbd / drbd_main.c
index e4fd1806dc2507f08ff47a9c4905e44d81f527f0..64a084c159eeebb0ef874c7dd3aca6d419663706 100644 (file)
@@ -58,9 +58,6 @@
 #include "drbd_vli.h"
 
 static DEFINE_MUTEX(drbd_main_mutex);
-int drbd_worker(struct drbd_thread *);
-
-int drbd_init(void);
 static int drbd_open(struct block_device *bdev, fmode_t mode);
 static void drbd_release(struct gendisk *gd, fmode_t mode);
 static int w_md_sync(struct drbd_work *w, int unused);
@@ -117,8 +114,8 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0
 /* in 2.6.x, our device mapping and config info contains our virtual gendisks
  * as member "struct gendisk *vdisk;"
  */
-struct idr minors;
-struct list_head drbd_connections;  /* list of struct drbd_connection */
+struct idr drbd_devices;
+struct list_head drbd_resources;
 
 struct kmem_cache *drbd_request_cache;
 struct kmem_cache *drbd_ee_cache;      /* peer requests */
@@ -198,7 +195,7 @@ void tl_release(struct drbd_connection *connection, unsigned int barrier_nr,
        int expect_epoch = 0;
        int expect_size = 0;
 
-       spin_lock_irq(&connection->req_lock);
+       spin_lock_irq(&connection->resource->req_lock);
 
        /* find oldest not yet barrier-acked write request,
         * count writes in its epoch. */
@@ -227,18 +224,18 @@ void tl_release(struct drbd_connection *connection, unsigned int barrier_nr,
 
        /* first some paranoia code */
        if (req == NULL) {
-               conn_err(connection, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
+               drbd_err(connection, "BAD! BarrierAck #%u received, but no epoch in tl!?\n",
                         barrier_nr);
                goto bail;
        }
        if (expect_epoch != barrier_nr) {
-               conn_err(connection, "BAD! BarrierAck #%u received, expected #%u!\n",
+               drbd_err(connection, "BAD! BarrierAck #%u received, expected #%u!\n",
                         barrier_nr, expect_epoch);
                goto bail;
        }
 
        if (expect_size != set_size) {
-               conn_err(connection, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
+               drbd_err(connection, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
                         barrier_nr, set_size, expect_size);
                goto bail;
        }
@@ -255,12 +252,12 @@ void tl_release(struct drbd_connection *connection, unsigned int barrier_nr,
                        break;
                _req_mod(req, BARRIER_ACKED);
        }
-       spin_unlock_irq(&connection->req_lock);
+       spin_unlock_irq(&connection->resource->req_lock);
 
        return;
 
 bail:
-       spin_unlock_irq(&connection->req_lock);
+       spin_unlock_irq(&connection->resource->req_lock);
        conn_request_state(connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD);
 }
 
@@ -284,9 +281,9 @@ void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what)
 
 void tl_restart(struct drbd_connection *connection, enum drbd_req_event what)
 {
-       spin_lock_irq(&connection->req_lock);
+       spin_lock_irq(&connection->resource->req_lock);
        _tl_restart(connection, what);
-       spin_unlock_irq(&connection->req_lock);
+       spin_unlock_irq(&connection->resource->req_lock);
 }
 
 /**
@@ -308,10 +305,10 @@ void tl_clear(struct drbd_connection *connection)
  */
 void tl_abort_disk_io(struct drbd_device *device)
 {
-       struct drbd_connection *connection = device->connection;
+       struct drbd_connection *connection = first_peer_device(device)->connection;
        struct drbd_request *req, *r;
 
-       spin_lock_irq(&connection->req_lock);
+       spin_lock_irq(&connection->resource->req_lock);
        list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests) {
                if (!(req->rq_state & RQ_LOCAL_PENDING))
                        continue;
@@ -319,7 +316,7 @@ void tl_abort_disk_io(struct drbd_device *device)
                        continue;
                _req_mod(req, ABORT_DISK_IO);
        }
-       spin_unlock_irq(&connection->req_lock);
+       spin_unlock_irq(&connection->resource->req_lock);
 }
 
 static int drbd_thread_setup(void *arg)
@@ -330,7 +327,8 @@ static int drbd_thread_setup(void *arg)
        int retval;
 
        snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s",
-                thi->name[0], thi->connection->name);
+                thi->name[0],
+                thi->connection->resource->name);
 
 restart:
        retval = thi->function(thi);
@@ -348,7 +346,7 @@ restart:
         */
 
        if (thi->t_state == RESTARTING) {
-               conn_info(connection, "Restarting %s thread\n", thi->name);
+               drbd_info(connection, "Restarting %s thread\n", thi->name);
                thi->t_state = RUNNING;
                spin_unlock_irqrestore(&thi->t_lock, flags);
                goto restart;
@@ -360,11 +358,11 @@ restart:
        complete_all(&thi->stop);
        spin_unlock_irqrestore(&thi->t_lock, flags);
 
-       conn_info(connection, "Terminating %s\n", current->comm);
+       drbd_info(connection, "Terminating %s\n", current->comm);
 
        /* Release mod reference taken when thread was started */
 
-       kref_put(&connection->kref, &conn_destroy);
+       kref_put(&connection->kref, drbd_destroy_connection);
        module_put(THIS_MODULE);
        return retval;
 }
@@ -392,12 +390,12 @@ int drbd_thread_start(struct drbd_thread *thi)
 
        switch (thi->t_state) {
        case NONE:
-               conn_info(connection, "Starting %s thread (from %s [%d])\n",
+               drbd_info(connection, "Starting %s thread (from %s [%d])\n",
                         thi->name, current->comm, current->pid);
 
                /* Get ref on module for thread - this is released when thread exits */
                if (!try_module_get(THIS_MODULE)) {
-                       conn_err(connection, "Failed to get module reference in drbd_thread_start\n");
+                       drbd_err(connection, "Failed to get module reference in drbd_thread_start\n");
                        spin_unlock_irqrestore(&thi->t_lock, flags);
                        return false;
                }
@@ -411,12 +409,12 @@ int drbd_thread_start(struct drbd_thread *thi)
                flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
 
                nt = kthread_create(drbd_thread_setup, (void *) thi,
-                                   "drbd_%c_%s", thi->name[0], thi->connection->name);
+                                   "drbd_%c_%s", thi->name[0], thi->connection->resource->name);
 
                if (IS_ERR(nt)) {
-                       conn_err(connection, "Couldn't start thread\n");
+                       drbd_err(connection, "Couldn't start thread\n");
 
-                       kref_put(&connection->kref, &conn_destroy);
+                       kref_put(&connection->kref, drbd_destroy_connection);
                        module_put(THIS_MODULE);
                        return false;
                }
@@ -428,7 +426,7 @@ int drbd_thread_start(struct drbd_thread *thi)
                break;
        case EXITING:
                thi->t_state = RESTARTING;
-               conn_info(connection, "Restarting %s thread (from %s [%d])\n",
+               drbd_info(connection, "Restarting %s thread (from %s [%d])\n",
                                thi->name, current->comm, current->pid);
                /* fall through */
        case RUNNING:
@@ -495,42 +493,53 @@ char *drbd_task_to_thread_name(struct drbd_connection *connection, struct task_s
 
 int conn_lowest_minor(struct drbd_connection *connection)
 {
-       struct drbd_device *device;
-       int vnr = 0, m;
+       struct drbd_peer_device *peer_device;
+       int vnr = 0, minor = -1;
 
        rcu_read_lock();
-       device = idr_get_next(&connection->volumes, &vnr);
-       m = device ? device_to_minor(device) : -1;
+       peer_device = idr_get_next(&connection->peer_devices, &vnr);
+       if (peer_device)
+               minor = device_to_minor(peer_device->device);
        rcu_read_unlock();
 
-       return m;
+       return minor;
 }
 
 #ifdef CONFIG_SMP
 /**
  * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
- * @device:    DRBD device.
  *
- * Forces all threads of a device onto the same CPU. This is beneficial for
+ * Forces all threads of a resource onto the same CPU. This is beneficial for
  * DRBD's performance. May be overwritten by user's configuration.
  */
-void drbd_calc_cpu_mask(struct drbd_connection *connection)
+static void drbd_calc_cpu_mask(cpumask_var_t *cpu_mask)
 {
-       int ord, cpu;
+       unsigned int *resources_per_cpu, min_index = ~0;
 
-       /* user override. */
-       if (cpumask_weight(connection->cpu_mask))
-               return;
+       resources_per_cpu = kzalloc(nr_cpu_ids * sizeof(*resources_per_cpu), GFP_KERNEL);
+       if (resources_per_cpu) {
+               struct drbd_resource *resource;
+               unsigned int cpu, min = ~0;
 
-       ord = conn_lowest_minor(connection) % cpumask_weight(cpu_online_mask);
-       for_each_online_cpu(cpu) {
-               if (ord-- == 0) {
-                       cpumask_set_cpu(cpu, connection->cpu_mask);
-                       return;
+               rcu_read_lock();
+               for_each_resource_rcu(resource, &drbd_resources) {
+                       for_each_cpu(cpu, resource->cpu_mask)
+                               resources_per_cpu[cpu]++;
                }
+               rcu_read_unlock();
+               for_each_online_cpu(cpu) {
+                       if (resources_per_cpu[cpu] < min) {
+                               min = resources_per_cpu[cpu];
+                               min_index = cpu;
+                       }
+               }
+               kfree(resources_per_cpu);
+       }
+       if (min_index == ~0) {
+               cpumask_setall(*cpu_mask);
+               return;
        }
-       /* should not be reached */
-       cpumask_setall(connection->cpu_mask);
+       cpumask_set_cpu(min_index, *cpu_mask);
 }
 
 /**
@@ -548,8 +557,10 @@ void drbd_thread_current_set_cpu(struct drbd_thread *thi)
        if (!thi->reset_cpu_mask)
                return;
        thi->reset_cpu_mask = 0;
-       set_cpus_allowed_ptr(p, thi->connection->cpu_mask);
+       set_cpus_allowed_ptr(p, thi->connection->resource->cpu_mask);
 }
+#else
+#define drbd_calc_cpu_mask(A) ({})
 #endif
 
 /**
@@ -631,9 +642,9 @@ void *conn_prepare_command(struct drbd_connection *connection, struct drbd_socke
        return p;
 }
 
-void *drbd_prepare_command(struct drbd_device *device, struct drbd_socket *sock)
+void *drbd_prepare_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock)
 {
-       return conn_prepare_command(device->connection, sock);
+       return conn_prepare_command(peer_device->connection, sock);
 }
 
 static int __send_command(struct drbd_connection *connection, int vnr,
@@ -680,14 +691,14 @@ int conn_send_command(struct drbd_connection *connection, struct drbd_socket *so
        return err;
 }
 
-int drbd_send_command(struct drbd_device *device, struct drbd_socket *sock,
+int drbd_send_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock,
                      enum drbd_packet cmd, unsigned int header_size,
                      void *data, unsigned int size)
 {
        int err;
 
-       err = __send_command(device->connection, device->vnr, sock, cmd, header_size,
-                            data, size);
+       err = __send_command(peer_device->connection, peer_device->device->vnr,
+                            sock, cmd, header_size, data, size);
        mutex_unlock(&sock->mutex);
        return err;
 }
@@ -712,23 +723,23 @@ int drbd_send_ping_ack(struct drbd_connection *connection)
        return conn_send_command(connection, sock, P_PING_ACK, 0, NULL, 0);
 }
 
-int drbd_send_sync_param(struct drbd_device *device)
+int drbd_send_sync_param(struct drbd_peer_device *peer_device)
 {
        struct drbd_socket *sock;
        struct p_rs_param_95 *p;
        int size;
-       const int apv = device->connection->agreed_pro_version;
+       const int apv = peer_device->connection->agreed_pro_version;
        enum drbd_packet cmd;
        struct net_conf *nc;
        struct disk_conf *dc;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
 
        rcu_read_lock();
-       nc = rcu_dereference(device->connection->net_conf);
+       nc = rcu_dereference(peer_device->connection->net_conf);
 
        size = apv <= 87 ? sizeof(struct p_rs_param)
                : apv == 88 ? sizeof(struct p_rs_param)
@@ -741,14 +752,14 @@ int drbd_send_sync_param(struct drbd_device *device)
        /* initialize verify_alg and csums_alg */
        memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
 
-       if (get_ldev(device)) {
-               dc = rcu_dereference(device->ldev->disk_conf);
+       if (get_ldev(peer_device->device)) {
+               dc = rcu_dereference(peer_device->device->ldev->disk_conf);
                p->resync_rate = cpu_to_be32(dc->resync_rate);
                p->c_plan_ahead = cpu_to_be32(dc->c_plan_ahead);
                p->c_delay_target = cpu_to_be32(dc->c_delay_target);
                p->c_fill_target = cpu_to_be32(dc->c_fill_target);
                p->c_max_rate = cpu_to_be32(dc->c_max_rate);
-               put_ldev(device);
+               put_ldev(peer_device->device);
        } else {
                p->resync_rate = cpu_to_be32(DRBD_RESYNC_RATE_DEF);
                p->c_plan_ahead = cpu_to_be32(DRBD_C_PLAN_AHEAD_DEF);
@@ -763,7 +774,7 @@ int drbd_send_sync_param(struct drbd_device *device)
                strcpy(p->csums_alg, nc->csums_alg);
        rcu_read_unlock();
 
-       return drbd_send_command(device, sock, cmd, size, NULL, 0);
+       return drbd_send_command(peer_device, sock, cmd, size, NULL, 0);
 }
 
 int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cmd)
@@ -784,7 +795,7 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
        if (nc->tentative && connection->agreed_pro_version < 92) {
                rcu_read_unlock();
                mutex_unlock(&sock->mutex);
-               conn_err(connection, "--dry-run is not supported by peer");
+               drbd_err(connection, "--dry-run is not supported by peer");
                return -EOPNOTSUPP;
        }
 
@@ -822,8 +833,9 @@ int drbd_send_protocol(struct drbd_connection *connection)
        return err;
 }
 
-static int _drbd_send_uuids(struct drbd_device *device, u64 uuid_flags)
+static int _drbd_send_uuids(struct drbd_peer_device *peer_device, u64 uuid_flags)
 {
+       struct drbd_device *device = peer_device->device;
        struct drbd_socket *sock;
        struct p_uuids *p;
        int i;
@@ -831,8 +843,8 @@ static int _drbd_send_uuids(struct drbd_device *device, u64 uuid_flags)
        if (!get_ldev_if_state(device, D_NEGOTIATING))
                return 0;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p) {
                put_ldev(device);
                return -EIO;
@@ -845,31 +857,31 @@ static int _drbd_send_uuids(struct drbd_device *device, u64 uuid_flags)
        device->comm_bm_set = drbd_bm_total_weight(device);
        p->uuid[UI_SIZE] = cpu_to_be64(device->comm_bm_set);
        rcu_read_lock();
-       uuid_flags |= rcu_dereference(device->connection->net_conf)->discard_my_data ? 1 : 0;
+       uuid_flags |= rcu_dereference(peer_device->connection->net_conf)->discard_my_data ? 1 : 0;
        rcu_read_unlock();
        uuid_flags |= test_bit(CRASHED_PRIMARY, &device->flags) ? 2 : 0;
        uuid_flags |= device->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0;
        p->uuid[UI_FLAGS] = cpu_to_be64(uuid_flags);
 
        put_ldev(device);
-       return drbd_send_command(device, sock, P_UUIDS, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, P_UUIDS, sizeof(*p), NULL, 0);
 }
 
-int drbd_send_uuids(struct drbd_device *device)
+int drbd_send_uuids(struct drbd_peer_device *peer_device)
 {
-       return _drbd_send_uuids(device, 0);
+       return _drbd_send_uuids(peer_device, 0);
 }
 
-int drbd_send_uuids_skip_initial_sync(struct drbd_device *device)
+int drbd_send_uuids_skip_initial_sync(struct drbd_peer_device *peer_device)
 {
-       return _drbd_send_uuids(device, 8);
+       return _drbd_send_uuids(peer_device, 8);
 }
 
 void drbd_print_uuids(struct drbd_device *device, const char *text)
 {
        if (get_ldev_if_state(device, D_NEGOTIATING)) {
                u64 *uuid = device->ldev->md.uuid;
-               dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX\n",
+               drbd_info(device, "%s %016llX:%016llX:%016llX:%016llX\n",
                     text,
                     (unsigned long long)uuid[UI_CURRENT],
                     (unsigned long long)uuid[UI_BITMAP],
@@ -877,19 +889,20 @@ void drbd_print_uuids(struct drbd_device *device, const char *text)
                     (unsigned long long)uuid[UI_HISTORY_END]);
                put_ldev(device);
        } else {
-               dev_info(DEV, "%s effective data uuid: %016llX\n",
+               drbd_info(device, "%s effective data uuid: %016llX\n",
                                text,
                                (unsigned long long)device->ed_uuid);
        }
 }
 
-void drbd_gen_and_send_sync_uuid(struct drbd_device *device)
+void drbd_gen_and_send_sync_uuid(struct drbd_peer_device *peer_device)
 {
+       struct drbd_device *device = peer_device->device;
        struct drbd_socket *sock;
        struct p_rs_uuid *p;
        u64 uuid;
 
-       D_ASSERT(device->state.disk == D_UP_TO_DATE);
+       D_ASSERT(device, device->state.disk == D_UP_TO_DATE);
 
        uuid = device->ldev->md.uuid[UI_BITMAP];
        if (uuid && uuid != UUID_JUST_CREATED)
@@ -900,16 +913,17 @@ void drbd_gen_and_send_sync_uuid(struct drbd_device *device)
        drbd_print_uuids(device, "updated sync UUID");
        drbd_md_sync(device);
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (p) {
                p->uuid = cpu_to_be64(uuid);
-               drbd_send_command(device, sock, P_SYNC_UUID, sizeof(*p), NULL, 0);
+               drbd_send_command(peer_device, sock, P_SYNC_UUID, sizeof(*p), NULL, 0);
        }
 }
 
-int drbd_send_sizes(struct drbd_device *device, int trigger_reply, enum dds_flags flags)
+int drbd_send_sizes(struct drbd_peer_device *peer_device, int trigger_reply, enum dds_flags flags)
 {
+       struct drbd_device *device = peer_device->device;
        struct drbd_socket *sock;
        struct p_sizes *p;
        sector_t d_size, u_size;
@@ -917,7 +931,7 @@ int drbd_send_sizes(struct drbd_device *device, int trigger_reply, enum dds_flag
        unsigned int max_bio_size;
 
        if (get_ldev_if_state(device, D_NEGOTIATING)) {
-               D_ASSERT(device->ldev->backing_bdev);
+               D_ASSERT(device, device->ldev->backing_bdev);
                d_size = drbd_get_max_capacity(device->ldev);
                rcu_read_lock();
                u_size = rcu_dereference(device->ldev->disk_conf)->disk_size;
@@ -933,14 +947,14 @@ int drbd_send_sizes(struct drbd_device *device, int trigger_reply, enum dds_flag
                max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */
        }
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
 
-       if (device->connection->agreed_pro_version <= 94)
+       if (peer_device->connection->agreed_pro_version <= 94)
                max_bio_size = min(max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
-       else if (device->connection->agreed_pro_version < 100)
+       else if (peer_device->connection->agreed_pro_version < 100)
                max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE_P95);
 
        p->d_size = cpu_to_be64(d_size);
@@ -949,29 +963,29 @@ int drbd_send_sizes(struct drbd_device *device, int trigger_reply, enum dds_flag
        p->max_bio_size = cpu_to_be32(max_bio_size);
        p->queue_order_type = cpu_to_be16(q_order_type);
        p->dds_flags = cpu_to_be16(flags);
-       return drbd_send_command(device, sock, P_SIZES, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, P_SIZES, sizeof(*p), NULL, 0);
 }
 
 /**
  * drbd_send_current_state() - Sends the drbd state to the peer
- * @device:    DRBD device.
+ * @peer_device:       DRBD peer device.
  */
-int drbd_send_current_state(struct drbd_device *device)
+int drbd_send_current_state(struct drbd_peer_device *peer_device)
 {
        struct drbd_socket *sock;
        struct p_state *p;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
-       p->state = cpu_to_be32(device->state.i); /* Within the send mutex */
-       return drbd_send_command(device, sock, P_STATE, sizeof(*p), NULL, 0);
+       p->state = cpu_to_be32(peer_device->device->state.i); /* Within the send mutex */
+       return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0);
 }
 
 /**
  * drbd_send_state() - After a state change, sends the new state to the peer
- * @device:      DRBD device.
+ * @peer_device:      DRBD peer device.
  * @state:     the state to send, not necessarily the current state.
  *
  * Each state change queues an "after_state_ch" work, which will eventually
@@ -979,31 +993,31 @@ int drbd_send_current_state(struct drbd_device *device)
  * between queuing and processing of the after_state_ch work, we still
  * want to send each intermediary state in the order it occurred.
  */
-int drbd_send_state(struct drbd_device *device, union drbd_state state)
+int drbd_send_state(struct drbd_peer_device *peer_device, union drbd_state state)
 {
        struct drbd_socket *sock;
        struct p_state *p;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->state = cpu_to_be32(state.i); /* Within the send mutex */
-       return drbd_send_command(device, sock, P_STATE, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0);
 }
 
-int drbd_send_state_req(struct drbd_device *device, union drbd_state mask, union drbd_state val)
+int drbd_send_state_req(struct drbd_peer_device *peer_device, union drbd_state mask, union drbd_state val)
 {
        struct drbd_socket *sock;
        struct p_req_state *p;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->mask = cpu_to_be32(mask.i);
        p->val = cpu_to_be32(val.i);
-       return drbd_send_command(device, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0);
 }
 
 int conn_send_state_req(struct drbd_connection *connection, union drbd_state mask, union drbd_state val)
@@ -1022,16 +1036,16 @@ int conn_send_state_req(struct drbd_connection *connection, union drbd_state mas
        return conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0);
 }
 
-void drbd_send_sr_reply(struct drbd_device *device, enum drbd_state_rv retcode)
+void drbd_send_sr_reply(struct drbd_peer_device *peer_device, enum drbd_state_rv retcode)
 {
        struct drbd_socket *sock;
        struct p_req_state_reply *p;
 
-       sock = &device->connection->meta;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->meta;
+       p = drbd_prepare_command(peer_device, sock);
        if (p) {
                p->retcode = cpu_to_be32(retcode);
-               drbd_send_command(device, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0);
+               drbd_send_command(peer_device, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0);
        }
 }
 
@@ -1081,9 +1095,9 @@ static int fill_bitmap_rle_bits(struct drbd_device *device,
 
        /* may we use this feature? */
        rcu_read_lock();
-       use_rle = rcu_dereference(device->connection->net_conf)->use_rle;
+       use_rle = rcu_dereference(first_peer_device(device)->connection->net_conf)->use_rle;
        rcu_read_unlock();
-       if (!use_rle || device->connection->agreed_pro_version < 90)
+       if (!use_rle || first_peer_device(device)->connection->agreed_pro_version < 90)
                return 0;
 
        if (c->bit_offset >= c->bm_bits)
@@ -1124,7 +1138,7 @@ static int fill_bitmap_rle_bits(struct drbd_device *device,
                /* paranoia: catch zero runlength.
                 * can only happen if bitmap is modified while we scan it. */
                if (rl == 0) {
-                       dev_err(DEV, "unexpected zero runlength while encoding bitmap "
+                       drbd_err(device, "unexpected zero runlength while encoding bitmap "
                            "t:%u bo:%lu\n", toggle, c->bit_offset);
                        return -1;
                }
@@ -1133,7 +1147,7 @@ static int fill_bitmap_rle_bits(struct drbd_device *device,
                if (bits == -ENOBUFS) /* buffer full */
                        break;
                if (bits <= 0) {
-                       dev_err(DEV, "error while encoding bitmap: %d\n", bits);
+                       drbd_err(device, "error while encoding bitmap: %d\n", bits);
                        return 0;
                }
 
@@ -1172,8 +1186,8 @@ static int fill_bitmap_rle_bits(struct drbd_device *device,
 static int
 send_bitmap_rle_or_plain(struct drbd_device *device, struct bm_xfer_ctx *c)
 {
-       struct drbd_socket *sock = &device->connection->data;
-       unsigned int header_size = drbd_header_size(device->connection);
+       struct drbd_socket *sock = &first_peer_device(device)->connection->data;
+       unsigned int header_size = drbd_header_size(first_peer_device(device)->connection);
        struct p_compressed_bm *p = sock->sbuf + header_size;
        int len, err;
 
@@ -1184,7 +1198,7 @@ send_bitmap_rle_or_plain(struct drbd_device *device, struct bm_xfer_ctx *c)
 
        if (len) {
                dcbp_set_code(p, RLE_VLI_Bits);
-               err = __send_command(device->connection, device->vnr, sock,
+               err = __send_command(first_peer_device(device)->connection, device->vnr, sock,
                                     P_COMPRESSED_BITMAP, sizeof(*p) + len,
                                     NULL, 0);
                c->packets[0]++;
@@ -1205,7 +1219,7 @@ send_bitmap_rle_or_plain(struct drbd_device *device, struct bm_xfer_ctx *c)
                len = num_words * sizeof(*p);
                if (len)
                        drbd_bm_get_lel(device, c->word_offset, num_words, p);
-               err = __send_command(device->connection, device->vnr, sock, P_BITMAP, len, NULL, 0);
+               err = __send_command(first_peer_device(device)->connection, device->vnr, sock, P_BITMAP, len, NULL, 0);
                c->word_offset += num_words;
                c->bit_offset = c->word_offset * BITS_PER_LONG;
 
@@ -1236,13 +1250,13 @@ static int _drbd_send_bitmap(struct drbd_device *device)
 
        if (get_ldev(device)) {
                if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC)) {
-                       dev_info(DEV, "Writing the whole bitmap, MDF_FullSync was set.\n");
+                       drbd_info(device, "Writing the whole bitmap, MDF_FullSync was set.\n");
                        drbd_bm_set_all(device);
                        if (drbd_bm_write(device)) {
                                /* write_bm did fail! Leave full sync flag set in Meta P_DATA
                                 * but otherwise process as per normal - need to tell other
                                 * side that a full resync is required! */
-                               dev_err(DEV, "Failed to write bitmap to disk!\n");
+                               drbd_err(device, "Failed to write bitmap to disk!\n");
                        } else {
                                drbd_md_clear_flag(device, MDF_FULL_SYNC);
                                drbd_md_sync(device);
@@ -1265,7 +1279,7 @@ static int _drbd_send_bitmap(struct drbd_device *device)
 
 int drbd_send_bitmap(struct drbd_device *device)
 {
-       struct drbd_socket *sock = &device->connection->data;
+       struct drbd_socket *sock = &first_peer_device(device)->connection->data;
        int err = -1;
 
        mutex_lock(&sock->mutex);
@@ -1300,42 +1314,42 @@ void drbd_send_b_ack(struct drbd_connection *connection, u32 barrier_nr, u32 set
  * @blksize:   size in byte, needs to be in big endian byte order
  * @block_id:  Id, big endian byte order
  */
-static int _drbd_send_ack(struct drbd_device *device, enum drbd_packet cmd,
+static int _drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
                          u64 sector, u32 blksize, u64 block_id)
 {
        struct drbd_socket *sock;
        struct p_block_ack *p;
 
-       if (device->state.conn < C_CONNECTED)
+       if (peer_device->device->state.conn < C_CONNECTED)
                return -EIO;
 
-       sock = &device->connection->meta;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->meta;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->sector = sector;
        p->block_id = block_id;
        p->blksize = blksize;
-       p->seq_num = cpu_to_be32(atomic_inc_return(&device->packet_seq));
-       return drbd_send_command(device, sock, cmd, sizeof(*p), NULL, 0);
+       p->seq_num = cpu_to_be32(atomic_inc_return(&peer_device->device->packet_seq));
+       return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0);
 }
 
 /* dp->sector and dp->block_id already/still in network byte order,
  * data_size is payload size according to dp->head,
  * and may need to be corrected for digest size. */
-void drbd_send_ack_dp(struct drbd_device *device, enum drbd_packet cmd,
+void drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
                      struct p_data *dp, int data_size)
 {
-       if (device->connection->peer_integrity_tfm)
-               data_size -= crypto_hash_digestsize(device->connection->peer_integrity_tfm);
-       _drbd_send_ack(device, cmd, dp->sector, cpu_to_be32(data_size),
+       if (peer_device->connection->peer_integrity_tfm)
+               data_size -= crypto_hash_digestsize(peer_device->connection->peer_integrity_tfm);
+       _drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size),
                       dp->block_id);
 }
 
-void drbd_send_ack_rp(struct drbd_device *device, enum drbd_packet cmd,
+void drbd_send_ack_rp(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
                      struct p_block_req *rp)
 {
-       _drbd_send_ack(device, cmd, rp->sector, rp->blksize, rp->block_id);
+       _drbd_send_ack(peer_device, cmd, rp->sector, rp->blksize, rp->block_id);
 }
 
 /**
@@ -1344,10 +1358,10 @@ void drbd_send_ack_rp(struct drbd_device *device, enum drbd_packet cmd,
  * @cmd:       packet command code
  * @peer_req:  peer request
  */
-int drbd_send_ack(struct drbd_device *device, enum drbd_packet cmd,
+int drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
                  struct drbd_peer_request *peer_req)
 {
-       return _drbd_send_ack(device, cmd,
+       return _drbd_send_ack(peer_device, cmd,
                              cpu_to_be64(peer_req->i.sector),
                              cpu_to_be32(peer_req->i.size),
                              peer_req->block_id);
@@ -1355,32 +1369,32 @@ int drbd_send_ack(struct drbd_device *device, enum drbd_packet cmd,
 
 /* This function misuses the block_id field to signal if the blocks
  * are is sync or not. */
-int drbd_send_ack_ex(struct drbd_device *device, enum drbd_packet cmd,
+int drbd_send_ack_ex(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
                     sector_t sector, int blksize, u64 block_id)
 {
-       return _drbd_send_ack(device, cmd,
+       return _drbd_send_ack(peer_device, cmd,
                              cpu_to_be64(sector),
                              cpu_to_be32(blksize),
                              cpu_to_be64(block_id));
 }
 
-int drbd_send_drequest(struct drbd_device *device, int cmd,
+int drbd_send_drequest(struct drbd_peer_device *peer_device, int cmd,
                       sector_t sector, int size, u64 block_id)
 {
        struct drbd_socket *sock;
        struct p_block_req *p;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->sector = cpu_to_be64(sector);
        p->block_id = block_id;
        p->blksize = cpu_to_be32(size);
-       return drbd_send_command(device, sock, cmd, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0);
 }
 
-int drbd_send_drequest_csum(struct drbd_device *device, sector_t sector, int size,
+int drbd_send_drequest_csum(struct drbd_peer_device *peer_device, sector_t sector, int size,
                            void *digest, int digest_size, enum drbd_packet cmd)
 {
        struct drbd_socket *sock;
@@ -1388,30 +1402,29 @@ int drbd_send_drequest_csum(struct drbd_device *device, sector_t sector, int siz
 
        /* FIXME: Put the digest into the preallocated socket buffer.  */
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->sector = cpu_to_be64(sector);
        p->block_id = ID_SYNCER /* unused */;
        p->blksize = cpu_to_be32(size);
-       return drbd_send_command(device, sock, cmd, sizeof(*p),
-                                digest, digest_size);
+       return drbd_send_command(peer_device, sock, cmd, sizeof(*p), digest, digest_size);
 }
 
-int drbd_send_ov_request(struct drbd_device *device, sector_t sector, int size)
+int drbd_send_ov_request(struct drbd_peer_device *peer_device, sector_t sector, int size)
 {
        struct drbd_socket *sock;
        struct p_block_req *p;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->sector = cpu_to_be64(sector);
        p->block_id = ID_SYNCER /* unused */;
        p->blksize = cpu_to_be32(size);
-       return drbd_send_command(device, sock, P_OV_REQUEST, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, P_OV_REQUEST, sizeof(*p), NULL, 0);
 }
 
 /* called on sndtimeo
@@ -1433,7 +1446,7 @@ static int we_should_drop_the_connection(struct drbd_connection *connection, str
 
        drop_it = !--connection->ko_count;
        if (!drop_it) {
-               conn_err(connection, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
+               drbd_err(connection, "[%s/%d] sock_sendmsg time expired, ko = %u\n",
                         current->comm, current->pid, connection->ko_count);
                request_ping(connection);
        }
@@ -1469,26 +1482,26 @@ static void drbd_update_congested(struct drbd_connection *connection)
  * As a workaround, we disable sendpage on pages
  * with page_count == 0 or PageSlab.
  */
-static int _drbd_no_send_page(struct drbd_device *device, struct page *page,
+static int _drbd_no_send_page(struct drbd_peer_device *peer_device, struct page *page,
                              int offset, size_t size, unsigned msg_flags)
 {
        struct socket *socket;
        void *addr;
        int err;
 
-       socket = device->connection->data.socket;
+       socket = peer_device->connection->data.socket;
        addr = kmap(page) + offset;
-       err = drbd_send_all(device->connection, socket, addr, size, msg_flags);
+       err = drbd_send_all(peer_device->connection, socket, addr, size, msg_flags);
        kunmap(page);
        if (!err)
-               device->send_cnt += size >> 9;
+               peer_device->device->send_cnt += size >> 9;
        return err;
 }
 
-static int _drbd_send_page(struct drbd_device *device, struct page *page,
+static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *page,
                    int offset, size_t size, unsigned msg_flags)
 {
-       struct socket *socket = device->connection->data.socket;
+       struct socket *socket = peer_device->connection->data.socket;
        mm_segment_t oldfs = get_fs();
        int len = size;
        int err = -EIO;
@@ -1500,10 +1513,10 @@ static int _drbd_send_page(struct drbd_device *device, struct page *page,
         * __page_cache_release a page that would actually still be referenced
         * by someone, leading to some obscure delayed Oops somewhere else. */
        if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
-               return _drbd_no_send_page(device, page, offset, size, msg_flags);
+               return _drbd_no_send_page(peer_device, page, offset, size, msg_flags);
 
        msg_flags |= MSG_NOSIGNAL;
-       drbd_update_congested(device->connection);
+       drbd_update_congested(peer_device->connection);
        set_fs(KERNEL_DS);
        do {
                int sent;
@@ -1511,11 +1524,11 @@ static int _drbd_send_page(struct drbd_device *device, struct page *page,
                sent = socket->ops->sendpage(socket, page, offset, len, msg_flags);
                if (sent <= 0) {
                        if (sent == -EAGAIN) {
-                               if (we_should_drop_the_connection(device->connection, socket))
+                               if (we_should_drop_the_connection(peer_device->connection, socket))
                                        break;
                                continue;
                        }
-                       dev_warn(DEV, "%s: size=%d len=%d sent=%d\n",
+                       drbd_warn(peer_device->device, "%s: size=%d len=%d sent=%d\n",
                             __func__, (int)size, len, sent);
                        if (sent < 0)
                                err = sent;
@@ -1525,16 +1538,16 @@ static int _drbd_send_page(struct drbd_device *device, struct page *page,
                offset += sent;
        } while (len > 0 /* THINK && device->cstate >= C_CONNECTED*/);
        set_fs(oldfs);
-       clear_bit(NET_CONGESTED, &device->connection->flags);
+       clear_bit(NET_CONGESTED, &peer_device->connection->flags);
 
        if (len == 0) {
                err = 0;
-               device->send_cnt += size >> 9;
+               peer_device->device->send_cnt += size >> 9;
        }
        return err;
 }
 
-static int _drbd_send_bio(struct drbd_device *device, struct bio *bio)
+static int _drbd_send_bio(struct drbd_peer_device *peer_device, struct bio *bio)
 {
        struct bio_vec bvec;
        struct bvec_iter iter;
@@ -1543,7 +1556,7 @@ static int _drbd_send_bio(struct drbd_device *device, struct bio *bio)
        bio_for_each_segment(bvec, bio, iter) {
                int err;
 
-               err = _drbd_no_send_page(device, bvec.bv_page,
+               err = _drbd_no_send_page(peer_device, bvec.bv_page,
                                         bvec.bv_offset, bvec.bv_len,
                                         bio_iter_last(bvec, iter)
                                         ? 0 : MSG_MORE);
@@ -1553,7 +1566,7 @@ static int _drbd_send_bio(struct drbd_device *device, struct bio *bio)
        return 0;
 }
 
-static int _drbd_send_zc_bio(struct drbd_device *device, struct bio *bio)
+static int _drbd_send_zc_bio(struct drbd_peer_device *peer_device, struct bio *bio)
 {
        struct bio_vec bvec;
        struct bvec_iter iter;
@@ -1562,7 +1575,7 @@ static int _drbd_send_zc_bio(struct drbd_device *device, struct bio *bio)
        bio_for_each_segment(bvec, bio, iter) {
                int err;
 
-               err = _drbd_send_page(device, bvec.bv_page,
+               err = _drbd_send_page(peer_device, bvec.bv_page,
                                      bvec.bv_offset, bvec.bv_len,
                                      bio_iter_last(bvec, iter) ? 0 : MSG_MORE);
                if (err)
@@ -1571,7 +1584,7 @@ static int _drbd_send_zc_bio(struct drbd_device *device, struct bio *bio)
        return 0;
 }
 
-static int _drbd_send_zc_ee(struct drbd_device *device,
+static int _drbd_send_zc_ee(struct drbd_peer_device *peer_device,
                            struct drbd_peer_request *peer_req)
 {
        struct page *page = peer_req->pages;
@@ -1582,7 +1595,7 @@ static int _drbd_send_zc_ee(struct drbd_device *device,
        page_chain_for_each(page) {
                unsigned l = min_t(unsigned, len, PAGE_SIZE);
 
-               err = _drbd_send_page(device, page, 0, l,
+               err = _drbd_send_page(peer_device, page, 0, l,
                                      page_chain_next(page) ? MSG_MORE : 0);
                if (err)
                        return err;
@@ -1591,9 +1604,9 @@ static int _drbd_send_zc_ee(struct drbd_device *device,
        return 0;
 }
 
-static u32 bio_flags_to_wire(struct drbd_device *device, unsigned long bi_rw)
+static u32 bio_flags_to_wire(struct drbd_connection *connection, unsigned long bi_rw)
 {
-       if (device->connection->agreed_pro_version >= 95)
+       if (connection->agreed_pro_version >= 95)
                return  (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) |
                        (bi_rw & REQ_FUA ? DP_FUA : 0) |
                        (bi_rw & REQ_FLUSH ? DP_FLUSH : 0) |
@@ -1605,28 +1618,30 @@ static u32 bio_flags_to_wire(struct drbd_device *device, unsigned long bi_rw)
 /* Used to send write requests
  * R_PRIMARY -> Peer   (P_DATA)
  */
-int drbd_send_dblock(struct drbd_device *device, struct drbd_request *req)
+int drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req)
 {
+       struct drbd_device *device = peer_device->device;
        struct drbd_socket *sock;
        struct p_data *p;
        unsigned int dp_flags = 0;
        int dgs;
        int err;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
-       dgs = device->connection->integrity_tfm ? crypto_hash_digestsize(device->connection->integrity_tfm) : 0;
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
+       dgs = peer_device->connection->integrity_tfm ?
+             crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
 
        if (!p)
                return -EIO;
        p->sector = cpu_to_be64(req->i.sector);
        p->block_id = (unsigned long)req;
        p->seq_num = cpu_to_be32(atomic_inc_return(&device->packet_seq));
-       dp_flags = bio_flags_to_wire(device, req->master_bio->bi_rw);
+       dp_flags = bio_flags_to_wire(peer_device->connection, req->master_bio->bi_rw);
        if (device->state.conn >= C_SYNC_SOURCE &&
            device->state.conn <= C_PAUSED_SYNC_T)
                dp_flags |= DP_MAY_SET_IN_SYNC;
-       if (device->connection->agreed_pro_version >= 100) {
+       if (peer_device->connection->agreed_pro_version >= 100) {
                if (req->rq_state & RQ_EXP_RECEIVE_ACK)
                        dp_flags |= DP_SEND_RECEIVE_ACK;
                if (req->rq_state & RQ_EXP_WRITE_ACK)
@@ -1634,8 +1649,8 @@ int drbd_send_dblock(struct drbd_device *device, struct drbd_request *req)
        }
        p->dp_flags = cpu_to_be32(dp_flags);
        if (dgs)
-               drbd_csum_bio(device, device->connection->integrity_tfm, req->master_bio, p + 1);
-       err = __send_command(device->connection, device->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
+               drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, p + 1);
+       err = __send_command(peer_device->connection, device->vnr, sock, P_DATA, sizeof(*p) + dgs, NULL, req->i.size);
        if (!err) {
                /* For protocol A, we have to memcpy the payload into
                 * socket buffers, as we may complete right away
@@ -1649,18 +1664,18 @@ int drbd_send_dblock(struct drbd_device *device, struct drbd_request *req)
                 * receiving side, we sure have detected corruption elsewhere.
                 */
                if (!(req->rq_state & (RQ_EXP_RECEIVE_ACK | RQ_EXP_WRITE_ACK)) || dgs)
-                       err = _drbd_send_bio(device, req->master_bio);
+                       err = _drbd_send_bio(peer_device, req->master_bio);
                else
-                       err = _drbd_send_zc_bio(device, req->master_bio);
+                       err = _drbd_send_zc_bio(peer_device, req->master_bio);
 
                /* double check digest, sometimes buffers have been modified in flight. */
                if (dgs > 0 && dgs <= 64) {
                        /* 64 byte, 512 bit, is the largest digest size
                         * currently supported in kernel crypto. */
                        unsigned char digest[64];
-                       drbd_csum_bio(device, device->connection->integrity_tfm, req->master_bio, digest);
+                       drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, digest);
                        if (memcmp(p + 1, digest, dgs)) {
-                               dev_warn(DEV,
+                               drbd_warn(device,
                                        "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n",
                                        (unsigned long long)req->i.sector, req->i.size);
                        }
@@ -1677,18 +1692,20 @@ int drbd_send_dblock(struct drbd_device *device, struct drbd_request *req)
  *  Peer       -> (diskless) R_PRIMARY   (P_DATA_REPLY)
  *  C_SYNC_SOURCE -> C_SYNC_TARGET         (P_RS_DATA_REPLY)
  */
-int drbd_send_block(struct drbd_device *device, enum drbd_packet cmd,
+int drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd,
                    struct drbd_peer_request *peer_req)
 {
+       struct drbd_device *device = peer_device->device;
        struct drbd_socket *sock;
        struct p_data *p;
        int err;
        int dgs;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
 
-       dgs = device->connection->integrity_tfm ? crypto_hash_digestsize(device->connection->integrity_tfm) : 0;
+       dgs = peer_device->connection->integrity_tfm ?
+             crypto_hash_digestsize(peer_device->connection->integrity_tfm) : 0;
 
        if (!p)
                return -EIO;
@@ -1697,27 +1714,27 @@ int drbd_send_block(struct drbd_device *device, enum drbd_packet cmd,
        p->seq_num = 0;  /* unused */
        p->dp_flags = 0;
        if (dgs)
-               drbd_csum_ee(device, device->connection->integrity_tfm, peer_req, p + 1);
-       err = __send_command(device->connection, device->vnr, sock, cmd, sizeof(*p) + dgs, NULL, peer_req->i.size);
+               drbd_csum_ee(peer_device->connection->integrity_tfm, peer_req, p + 1);
+       err = __send_command(peer_device->connection, device->vnr, sock, cmd, sizeof(*p) + dgs, NULL, peer_req->i.size);
        if (!err)
-               err = _drbd_send_zc_ee(device, peer_req);
+               err = _drbd_send_zc_ee(peer_device, peer_req);
        mutex_unlock(&sock->mutex);  /* locked by drbd_prepare_command() */
 
        return err;
 }
 
-int drbd_send_out_of_sync(struct drbd_device *device, struct drbd_request *req)
+int drbd_send_out_of_sync(struct drbd_peer_device *peer_device, struct drbd_request *req)
 {
        struct drbd_socket *sock;
        struct p_block_desc *p;
 
-       sock = &device->connection->data;
-       p = drbd_prepare_command(device, sock);
+       sock = &peer_device->connection->data;
+       p = drbd_prepare_command(peer_device, sock);
        if (!p)
                return -EIO;
        p->sector = cpu_to_be64(req->i.sector);
        p->blksize = cpu_to_be32(req->i.size);
-       return drbd_send_command(device, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0);
+       return drbd_send_command(peer_device, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0);
 }
 
 /*
@@ -1796,7 +1813,7 @@ int drbd_send(struct drbd_connection *connection, struct socket *sock,
 
        if (rv <= 0) {
                if (rv != -EAGAIN) {
-                       conn_err(connection, "%s_sendmsg returned %d\n",
+                       drbd_err(connection, "%s_sendmsg returned %d\n",
                                 sock == connection->meta.socket ? "msock" : "sock",
                                 rv);
                        conn_request_state(connection, NS(conn, C_BROKEN_PIPE), CS_HARD);
@@ -1832,7 +1849,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
        int rv = 0;
 
        mutex_lock(&drbd_main_mutex);
-       spin_lock_irqsave(&device->connection->req_lock, flags);
+       spin_lock_irqsave(&device->resource->req_lock, flags);
        /* to have a stable device->state.role
         * and no race with updating open_cnt */
 
@@ -1845,7 +1862,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
 
        if (!rv)
                device->open_cnt++;
-       spin_unlock_irqrestore(&device->connection->req_lock, flags);
+       spin_unlock_irqrestore(&device->resource->req_lock, flags);
        mutex_unlock(&drbd_main_mutex);
 
        return rv;
@@ -1950,9 +1967,9 @@ void drbd_init_set_defaults(struct drbd_device *device)
 void drbd_device_cleanup(struct drbd_device *device)
 {
        int i;
-       if (device->connection->receiver.t_state != NONE)
-               dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
-                               device->connection->receiver.t_state);
+       if (first_peer_device(device)->connection->receiver.t_state != NONE)
+               drbd_err(device, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
+                               first_peer_device(device)->connection->receiver.t_state);
 
        device->al_writ_cnt  =
        device->bm_writ_cnt  =
@@ -1970,7 +1987,7 @@ void drbd_device_cleanup(struct drbd_device *device)
                device->rs_mark_left[i] = 0;
                device->rs_mark_time[i] = 0;
        }
-       D_ASSERT(device->connection->net_conf == NULL);
+       D_ASSERT(device, first_peer_device(device)->connection->net_conf == NULL);
 
        drbd_set_my_capacity(device, 0);
        if (device->bitmap) {
@@ -1984,16 +2001,16 @@ void drbd_device_cleanup(struct drbd_device *device)
 
        clear_bit(AL_SUSPENDED, &device->flags);
 
-       D_ASSERT(list_empty(&device->active_ee));
-       D_ASSERT(list_empty(&device->sync_ee));
-       D_ASSERT(list_empty(&device->done_ee));
-       D_ASSERT(list_empty(&device->read_ee));
-       D_ASSERT(list_empty(&device->net_ee));
-       D_ASSERT(list_empty(&device->resync_reads));
-       D_ASSERT(list_empty(&device->connection->sender_work.q));
-       D_ASSERT(list_empty(&device->resync_work.list));
-       D_ASSERT(list_empty(&device->unplug_work.list));
-       D_ASSERT(list_empty(&device->go_diskless.list));
+       D_ASSERT(device, list_empty(&device->active_ee));
+       D_ASSERT(device, list_empty(&device->sync_ee));
+       D_ASSERT(device, list_empty(&device->done_ee));
+       D_ASSERT(device, list_empty(&device->read_ee));
+       D_ASSERT(device, list_empty(&device->net_ee));
+       D_ASSERT(device, list_empty(&device->resync_reads));
+       D_ASSERT(device, list_empty(&first_peer_device(device)->connection->sender_work.q));
+       D_ASSERT(device, list_empty(&device->resync_work.list));
+       D_ASSERT(device, list_empty(&device->unplug_work.list));
+       D_ASSERT(device, list_empty(&device->go_diskless.list));
 
        drbd_set_defaults(device);
 }
@@ -2010,7 +2027,7 @@ static void drbd_destroy_mempools(void)
                drbd_pp_vacant--;
        }
 
-       /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */
+       /* D_ASSERT(device, atomic_read(&drbd_pp_vacant)==0); */
 
        if (drbd_md_io_bio_set)
                bioset_free(drbd_md_io_bio_set);
@@ -2136,35 +2153,36 @@ static void drbd_release_all_peer_reqs(struct drbd_device *device)
 
        rr = drbd_free_peer_reqs(device, &device->active_ee);
        if (rr)
-               dev_err(DEV, "%d EEs in active list found!\n", rr);
+               drbd_err(device, "%d EEs in active list found!\n", rr);
 
        rr = drbd_free_peer_reqs(device, &device->sync_ee);
        if (rr)
-               dev_err(DEV, "%d EEs in sync list found!\n", rr);
+               drbd_err(device, "%d EEs in sync list found!\n", rr);
 
        rr = drbd_free_peer_reqs(device, &device->read_ee);
        if (rr)
-               dev_err(DEV, "%d EEs in read list found!\n", rr);
+               drbd_err(device, "%d EEs in read list found!\n", rr);
 
        rr = drbd_free_peer_reqs(device, &device->done_ee);
        if (rr)
-               dev_err(DEV, "%d EEs in done list found!\n", rr);
+               drbd_err(device, "%d EEs in done list found!\n", rr);
 
        rr = drbd_free_peer_reqs(device, &device->net_ee);
        if (rr)
-               dev_err(DEV, "%d EEs in net list found!\n", rr);
+               drbd_err(device, "%d EEs in net list found!\n", rr);
 }
 
 /* caution. no locking. */
-void drbd_minor_destroy(struct kref *kref)
+void drbd_destroy_device(struct kref *kref)
 {
        struct drbd_device *device = container_of(kref, struct drbd_device, kref);
-       struct drbd_connection *connection = device->connection;
+       struct drbd_resource *resource = device->resource;
+       struct drbd_connection *connection;
 
        del_timer_sync(&device->request_timer);
 
        /* paranoia asserts */
-       D_ASSERT(device->open_cnt == 0);
+       D_ASSERT(device, device->open_cnt == 0);
        /* end paranoia asserts */
 
        /* cleanup stuff that may have been allocated during
@@ -2190,9 +2208,12 @@ void drbd_minor_destroy(struct kref *kref)
        put_disk(device->vdisk);
        blk_cleanup_queue(device->rq_queue);
        kfree(device->rs_plan_s);
+       kfree(first_peer_device(device));
        kfree(device);
 
-       kref_put(&connection->kref, &conn_destroy);
+       for_each_connection(connection, resource)
+               kref_put(&connection->kref, drbd_destroy_connection);
+       kref_put(&resource->kref, drbd_destroy_resource);
 }
 
 /* One global retry thread, if we need to push back some bio and have it
@@ -2229,7 +2250,7 @@ static void do_retry(struct work_struct *ws)
                                (req->rq_state & RQ_LOCAL_ABORTED) != 0);
 
                if (!expected)
-                       dev_err(DEV, "req=%p completion_ref=%d rq_state=%x\n",
+                       drbd_err(device, "req=%p completion_ref=%d rq_state=%x\n",
                                req, atomic_read(&req->completion_ref),
                                req->rq_state);
 
@@ -2273,12 +2294,33 @@ void drbd_restart_request(struct drbd_request *req)
        queue_work(retry.wq, &retry.worker);
 }
 
+void drbd_destroy_resource(struct kref *kref)
+{
+       struct drbd_resource *resource =
+               container_of(kref, struct drbd_resource, kref);
+
+       idr_destroy(&resource->devices);
+       free_cpumask_var(resource->cpu_mask);
+       kfree(resource->name);
+       kfree(resource);
+}
+
+void drbd_free_resource(struct drbd_resource *resource)
+{
+       struct drbd_connection *connection, *tmp;
+
+       for_each_connection_safe(connection, tmp, resource) {
+               list_del(&connection->connections);
+               kref_put(&connection->kref, drbd_destroy_connection);
+       }
+       kref_put(&resource->kref, drbd_destroy_resource);
+}
 
 static void drbd_cleanup(void)
 {
        unsigned int i;
        struct drbd_device *device;
-       struct drbd_connection *connection, *tmp;
+       struct drbd_resource *resource, *tmp;
 
        unregister_reboot_notifier(&drbd_notifier);
 
@@ -2298,26 +2340,19 @@ static void drbd_cleanup(void)
 
        drbd_genl_unregister();
 
-       idr_for_each_entry(&minors, device, i) {
-               idr_remove(&minors, device_to_minor(device));
-               idr_remove(&device->connection->volumes, device->vnr);
-               destroy_workqueue(device->submit.wq);
-               del_gendisk(device->vdisk);
-               /* synchronize_rcu(); No other threads running at this point */
-               kref_put(&device->kref, &drbd_minor_destroy);
-       }
+       idr_for_each_entry(&drbd_devices, device, i)
+               drbd_delete_device(device);
 
        /* not _rcu since, no other updater anymore. Genl already unregistered */
-       list_for_each_entry_safe(connection, tmp, &drbd_connections, connections) {
-               list_del(&connection->connections); /* not _rcu no proc, not other threads */
-               /* synchronize_rcu(); */
-               kref_put(&connection->kref, &conn_destroy);
+       for_each_resource_safe(resource, tmp, &drbd_resources) {
+               list_del(&resource->resources);
+               drbd_free_resource(resource);
        }
 
        drbd_destroy_mempools();
        unregister_blkdev(DRBD_MAJOR, "drbd");
 
-       idr_destroy(&minors);
+       idr_destroy(&drbd_devices);
 
        printk(KERN_INFO "drbd: module cleanup done.\n");
 }
@@ -2343,7 +2378,7 @@ static int drbd_congested(void *congested_data, int bdi_bits)
                goto out;
        }
 
-       if (test_bit(CALLBACK_PENDING, &device->connection->flags)) {
+       if (test_bit(CALLBACK_PENDING, &first_peer_device(device)->connection->flags)) {
                r |= (1 << BDI_async_congested);
                /* Without good local data, we would need to read from remote,
                 * and that would need the worker thread as well, which is
@@ -2367,7 +2402,8 @@ static int drbd_congested(void *congested_data, int bdi_bits)
                        reason = 'b';
        }
 
-       if (bdi_bits & (1 << BDI_async_congested) && test_bit(NET_CONGESTED, &device->connection->flags)) {
+       if (bdi_bits & (1 << BDI_async_congested) &&
+           test_bit(NET_CONGESTED, &first_peer_device(device)->connection->flags)) {
                r |= (1 << BDI_async_congested);
                reason = reason == 'b' ? 'a' : 'n';
        }
@@ -2384,39 +2420,42 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq)
        init_waitqueue_head(&wq->q_wait);
 }
 
-struct drbd_connection *conn_get_by_name(const char *name)
+struct drbd_resource *drbd_find_resource(const char *name)
 {
-       struct drbd_connection *connection;
+       struct drbd_resource *resource;
 
        if (!name || !name[0])
                return NULL;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(connection, &drbd_connections, connections) {
-               if (!strcmp(connection->name, name)) {
-                       kref_get(&connection->kref);
+       for_each_resource_rcu(resource, &drbd_resources) {
+               if (!strcmp(resource->name, name)) {
+                       kref_get(&resource->kref);
                        goto found;
                }
        }
-       connection = NULL;
+       resource = NULL;
 found:
        rcu_read_unlock();
-       return connection;
+       return resource;
 }
 
 struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
                                     void *peer_addr, int peer_addr_len)
 {
+       struct drbd_resource *resource;
        struct drbd_connection *connection;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(connection, &drbd_connections, connections) {
-               if (connection->my_addr_len == my_addr_len &&
-                   connection->peer_addr_len == peer_addr_len &&
-                   !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
-                   !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
-                       kref_get(&connection->kref);
-                       goto found;
+       for_each_resource_rcu(resource, &drbd_resources) {
+               for_each_connection_rcu(connection, resource) {
+                       if (connection->my_addr_len == my_addr_len &&
+                           connection->peer_addr_len == peer_addr_len &&
+                           !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
+                           !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
+                               kref_get(&connection->kref);
+                               goto found;
+                       }
                }
        }
        connection = NULL;
@@ -2463,8 +2502,9 @@ void conn_free_crypto(struct drbd_connection *connection)
        connection->int_dig_vv = NULL;
 }
 
-int set_resource_options(struct drbd_connection *connection, struct res_opts *res_opts)
+int set_resource_options(struct drbd_resource *resource, struct res_opts *res_opts)
 {
+       struct drbd_connection *connection;
        cpumask_var_t new_cpu_mask;
        int err;
 
@@ -2477,22 +2517,24 @@ int set_resource_options(struct drbd_connection *connection, struct res_opts *re
 
        /* silently ignore cpu mask on UP kernel */
        if (nr_cpu_ids > 1 && res_opts->cpu_mask[0] != 0) {
-               /* FIXME: Get rid of constant 32 here */
-               err = bitmap_parse(res_opts->cpu_mask, 32,
+               err = bitmap_parse(res_opts->cpu_mask, DRBD_CPU_MASK_SIZE,
                                   cpumask_bits(new_cpu_mask), nr_cpu_ids);
                if (err) {
-                       conn_warn(connection, "bitmap_parse() failed with %d\n", err);
+                       drbd_warn(resource, "bitmap_parse() failed with %d\n", err);
                        /* retcode = ERR_CPU_MASK_PARSE; */
                        goto fail;
                }
        }
-       connection->res_opts = *res_opts;
-       if (!cpumask_equal(connection->cpu_mask, new_cpu_mask)) {
-               cpumask_copy(connection->cpu_mask, new_cpu_mask);
-               drbd_calc_cpu_mask(connection);
-               connection->receiver.reset_cpu_mask = 1;
-               connection->asender.reset_cpu_mask = 1;
-               connection->worker.reset_cpu_mask = 1;
+       resource->res_opts = *res_opts;
+       if (cpumask_empty(new_cpu_mask))
+               drbd_calc_cpu_mask(&new_cpu_mask);
+       if (!cpumask_equal(resource->cpu_mask, new_cpu_mask)) {
+               cpumask_copy(resource->cpu_mask, new_cpu_mask);
+               for_each_connection_rcu(connection, resource) {
+                       connection->receiver.reset_cpu_mask = 1;
+                       connection->asender.reset_cpu_mask = 1;
+                       connection->worker.reset_cpu_mask = 1;
+               }
        }
        err = 0;
 
@@ -2502,30 +2544,49 @@ fail:
 
 }
 
+struct drbd_resource *drbd_create_resource(const char *name)
+{
+       struct drbd_resource *resource;
+
+       resource = kzalloc(sizeof(struct drbd_resource), GFP_KERNEL);
+       if (!resource)
+               goto fail;
+       resource->name = kstrdup(name, GFP_KERNEL);
+       if (!resource->name)
+               goto fail_free_resource;
+       if (!zalloc_cpumask_var(&resource->cpu_mask, GFP_KERNEL))
+               goto fail_free_name;
+       kref_init(&resource->kref);
+       idr_init(&resource->devices);
+       INIT_LIST_HEAD(&resource->connections);
+       list_add_tail_rcu(&resource->resources, &drbd_resources);
+       mutex_init(&resource->conf_update);
+       spin_lock_init(&resource->req_lock);
+       return resource;
+
+fail_free_name:
+       kfree(resource->name);
+fail_free_resource:
+       kfree(resource);
+fail:
+       return NULL;
+}
+
 /* caller must be under genl_lock() */
 struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
 {
+       struct drbd_resource *resource;
        struct drbd_connection *connection;
 
        connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL);
        if (!connection)
                return NULL;
 
-       connection->name = kstrdup(name, GFP_KERNEL);
-       if (!connection->name)
-               goto fail;
-
        if (drbd_alloc_socket(&connection->data))
                goto fail;
        if (drbd_alloc_socket(&connection->meta))
                goto fail;
 
-       if (!zalloc_cpumask_var(&connection->cpu_mask, GFP_KERNEL))
-               goto fail;
-
-       if (set_resource_options(connection, res_opts))
-               goto fail;
-
        connection->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
        if (!connection->current_epoch)
                goto fail;
@@ -2541,54 +2602,62 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
        connection->send.current_epoch_nr = 0;
        connection->send.current_epoch_writes = 0;
 
+       resource = drbd_create_resource(name);
+       if (!resource)
+               goto fail;
+
        connection->cstate = C_STANDALONE;
        mutex_init(&connection->cstate_mutex);
-       spin_lock_init(&connection->req_lock);
-       mutex_init(&connection->conf_update);
        init_waitqueue_head(&connection->ping_wait);
-       idr_init(&connection->volumes);
+       idr_init(&connection->peer_devices);
 
        drbd_init_workqueue(&connection->sender_work);
        mutex_init(&connection->data.mutex);
        mutex_init(&connection->meta.mutex);
 
-       drbd_thread_init(connection, &connection->receiver, drbdd_init, "receiver");
+       drbd_thread_init(connection, &connection->receiver, drbd_receiver, "receiver");
        drbd_thread_init(connection, &connection->worker, drbd_worker, "worker");
        drbd_thread_init(connection, &connection->asender, drbd_asender, "asender");
 
        kref_init(&connection->kref);
-       list_add_tail_rcu(&connection->connections, &drbd_connections);
 
+       connection->resource = resource;
+
+       if (set_resource_options(resource, res_opts))
+               goto fail_resource;
+
+       kref_get(&resource->kref);
+       list_add_tail_rcu(&connection->connections, &resource->connections);
        return connection;
 
+fail_resource:
+       list_del(&resource->resources);
+       drbd_free_resource(resource);
 fail:
        kfree(connection->current_epoch);
-       free_cpumask_var(connection->cpu_mask);
        drbd_free_socket(&connection->meta);
        drbd_free_socket(&connection->data);
-       kfree(connection->name);
        kfree(connection);
-
        return NULL;
 }
 
-void conn_destroy(struct kref *kref)
+void drbd_destroy_connection(struct kref *kref)
 {
        struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref);
+       struct drbd_resource *resource = connection->resource;
 
        if (atomic_read(&connection->current_epoch->epoch_size) !=  0)
-               conn_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size));
+               drbd_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size));
        kfree(connection->current_epoch);
 
-       idr_destroy(&connection->volumes);
+       idr_destroy(&connection->peer_devices);
 
-       free_cpumask_var(connection->cpu_mask);
        drbd_free_socket(&connection->meta);
        drbd_free_socket(&connection->data);
-       kfree(connection->name);
        kfree(connection->int_dig_in);
        kfree(connection->int_dig_vv);
        kfree(connection);
+       kref_put(&resource->kref, drbd_destroy_resource);
 }
 
 static int init_submitter(struct drbd_device *device)
@@ -2606,13 +2675,14 @@ static int init_submitter(struct drbd_device *device)
        return 0;
 }
 
-enum drbd_ret_code conn_new_minor(struct drbd_connection *connection, unsigned int minor, int vnr)
+enum drbd_ret_code drbd_create_device(struct drbd_resource *resource, unsigned int minor, int vnr)
 {
+       struct drbd_connection *connection;
        struct drbd_device *device;
+       struct drbd_peer_device *peer_device, *tmp_peer_device;
        struct gendisk *disk;
        struct request_queue *q;
-       int vnr_got = vnr;
-       int minor_got = minor;
+       int id;
        enum drbd_ret_code err = ERR_NOMEM;
 
        device = minor_to_device(minor);
@@ -2623,10 +2693,10 @@ enum drbd_ret_code conn_new_minor(struct drbd_connection *connection, unsigned i
        device = kzalloc(sizeof(struct drbd_device), GFP_KERNEL);
        if (!device)
                return ERR_NOMEM;
+       kref_init(&device->kref);
 
-       kref_get(&connection->kref);
-       device->connection = connection;
-
+       kref_get(&resource->kref);
+       device->resource = resource;
        device->minor = minor;
        device->vnr = vnr;
 
@@ -2666,7 +2736,7 @@ enum drbd_ret_code conn_new_minor(struct drbd_connection *connection, unsigned i
        blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
        blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
        blk_queue_merge_bvec(q, drbd_merge_bvec);
-       q->queue_lock = &device->connection->req_lock; /* needed since we use */
+       q->queue_lock = &resource->req_lock;
 
        device->md_io_page = alloc_page(GFP_KERNEL);
        if (!device->md_io_page)
@@ -2677,23 +2747,47 @@ enum drbd_ret_code conn_new_minor(struct drbd_connection *connection, unsigned i
        device->read_requests = RB_ROOT;
        device->write_requests = RB_ROOT;
 
-       minor_got = idr_alloc(&minors, device, minor, minor + 1, GFP_KERNEL);
-       if (minor_got < 0) {
-               if (minor_got == -ENOSPC) {
+       id = idr_alloc(&drbd_devices, device, minor, minor + 1, GFP_KERNEL);
+       if (id < 0) {
+               if (id == -ENOSPC) {
                        err = ERR_MINOR_EXISTS;
                        drbd_msg_put_info("requested minor exists already");
                }
                goto out_no_minor_idr;
        }
+       kref_get(&device->kref);
 
-       vnr_got = idr_alloc(&connection->volumes, device, vnr, vnr + 1, GFP_KERNEL);
-       if (vnr_got < 0) {
-               if (vnr_got == -ENOSPC) {
-                       err = ERR_INVALID_REQUEST;
-                       drbd_msg_put_info("requested volume exists already");
+       id = idr_alloc(&resource->devices, device, vnr, vnr + 1, GFP_KERNEL);
+       if (id < 0) {
+               if (id == -ENOSPC) {
+                       err = ERR_MINOR_EXISTS;
+                       drbd_msg_put_info("requested minor exists already");
                }
                goto out_idr_remove_minor;
        }
+       kref_get(&device->kref);
+
+       INIT_LIST_HEAD(&device->peer_devices);
+       for_each_connection(connection, resource) {
+               peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
+               if (!peer_device)
+                       goto out_idr_remove_from_resource;
+               peer_device->connection = connection;
+               peer_device->device = device;
+
+               list_add(&peer_device->peer_devices, &device->peer_devices);
+               kref_get(&device->kref);
+
+               id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL);
+               if (id < 0) {
+                       if (id == -ENOSPC) {
+                               err = ERR_INVALID_REQUEST;
+                               drbd_msg_put_info("requested volume exists already");
+                       }
+                       goto out_idr_remove_from_resource;
+               }
+               kref_get(&connection->kref);
+       }
 
        if (init_submitter(device)) {
                err = ERR_NOMEM;
@@ -2702,19 +2796,33 @@ enum drbd_ret_code conn_new_minor(struct drbd_connection *connection, unsigned i
        }
 
        add_disk(disk);
-       kref_init(&device->kref); /* one ref for both idrs and the the add_disk */
 
        /* inherit the connection state */
-       device->state.conn = connection->cstate;
-       if (device->state.conn == C_WF_REPORT_PARAMS)
-               drbd_connected(device);
+       device->state.conn = first_connection(resource)->cstate;
+       if (device->state.conn == C_WF_REPORT_PARAMS) {
+               for_each_peer_device(peer_device, device)
+                       drbd_connected(peer_device);
+       }
 
        return NO_ERROR;
 
 out_idr_remove_vol:
-       idr_remove(&connection->volumes, vnr_got);
+       idr_remove(&connection->peer_devices, vnr);
+out_idr_remove_from_resource:
+       for_each_connection(connection, resource) {
+               peer_device = idr_find(&connection->peer_devices, vnr);
+               if (peer_device) {
+                       idr_remove(&connection->peer_devices, vnr);
+                       kref_put(&connection->kref, drbd_destroy_connection);
+               }
+       }
+       for_each_peer_device_safe(peer_device, tmp_peer_device, device) {
+               list_del(&peer_device->peer_devices);
+               kfree(peer_device);
+       }
+       idr_remove(&resource->devices, vnr);
 out_idr_remove_minor:
-       idr_remove(&minors, minor_got);
+       idr_remove(&drbd_devices, minor);
        synchronize_rcu();
 out_no_minor_idr:
        drbd_bm_cleanup(device);
@@ -2725,11 +2833,28 @@ out_no_io_page:
 out_no_disk:
        blk_cleanup_queue(q);
 out_no_q:
+       kref_put(&resource->kref, drbd_destroy_resource);
        kfree(device);
-       kref_put(&connection->kref, &conn_destroy);
        return err;
 }
 
+void drbd_delete_device(struct drbd_device *device)
+{
+       struct drbd_resource *resource = device->resource;
+       struct drbd_connection *connection;
+       int refs = 3;
+
+       for_each_connection(connection, resource) {
+               idr_remove(&connection->peer_devices, device->vnr);
+               refs++;
+       }
+       idr_remove(&resource->devices, device->vnr);
+       idr_remove(&drbd_devices, device_to_minor(device));
+       del_gendisk(device->vdisk);
+       synchronize_rcu();
+       kref_sub(&device->kref, refs, drbd_destroy_device);
+}
+
 int __init drbd_init(void)
 {
        int err;
@@ -2760,10 +2885,10 @@ int __init drbd_init(void)
        init_waitqueue_head(&drbd_pp_wait);
 
        drbd_proc = NULL; /* play safe for drbd_cleanup */
-       idr_init(&minors);
+       idr_init(&drbd_devices);
 
        rwlock_init(&global_state_lock);
-       INIT_LIST_HEAD(&drbd_connections);
+       INIT_LIST_HEAD(&drbd_resources);
 
        err = drbd_genl_register();
        if (err) {
@@ -2843,15 +2968,17 @@ void drbd_free_sock(struct drbd_connection *connection)
 
 void conn_md_sync(struct drbd_connection *connection)
 {
-       struct drbd_device *device;
+       struct drbd_peer_device *peer_device;
        int vnr;
 
        rcu_read_lock();
-       idr_for_each_entry(&connection->volumes, device, vnr) {
+       idr_for_each_entry(&connection->peer_devices, peer_device, vnr) {
+               struct drbd_device *device = peer_device->device;
+
                kref_get(&device->kref);
                rcu_read_unlock();
                drbd_md_sync(device);
-               kref_put(&device->kref, &drbd_minor_destroy);
+               kref_put(&device->kref, drbd_destroy_device);
                rcu_read_lock();
        }
        rcu_read_unlock();
@@ -2908,12 +3035,12 @@ void drbd_md_write(struct drbd_device *device, void *b)
        buffer->al_stripes = cpu_to_be32(device->ldev->md.al_stripes);
        buffer->al_stripe_size_4k = cpu_to_be32(device->ldev->md.al_stripe_size_4k);
 
-       D_ASSERT(drbd_md_ss(device->ldev) == device->ldev->md.md_offset);
+       D_ASSERT(device, drbd_md_ss(device->ldev) == device->ldev->md.md_offset);
        sector = device->ldev->md.md_offset;
 
        if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
                /* this was a try anyways ... */
-               dev_err(DEV, "meta data update failed!\n");
+               drbd_err(device, "meta data update failed!\n");
                drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
        }
 }
@@ -2995,7 +3122,7 @@ static int check_activity_log_stripe_size(struct drbd_device *device,
 
        return 0;
 err:
-       dev_err(DEV, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n",
+       drbd_err(device, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n",
                        al_stripes, al_stripe_size_4k);
        return -EINVAL;
 }
@@ -3067,7 +3194,7 @@ static int check_offsets_and_sizes(struct drbd_device *device, struct drbd_backi
        return 0;
 
 err:
-       dev_err(DEV, "meta data offsets don't make sense: idx=%d "
+       drbd_err(device, "meta data offsets don't make sense: idx=%d "
                        "al_s=%u, al_sz4k=%u, al_offset=%d, bm_offset=%d, "
                        "md_size_sect=%u, la_size=%llu, md_capacity=%llu\n",
                        in_core->meta_dev_idx,
@@ -3112,7 +3239,7 @@ int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
        if (drbd_md_sync_page_io(device, bdev, bdev->md.md_offset, READ)) {
                /* NOTE: can't do normal error processing here as this is
                   called BEFORE disk is attached */
-               dev_err(DEV, "Error while reading metadata.\n");
+               drbd_err(device, "Error while reading metadata.\n");
                rv = ERR_IO_MD_DISK;
                goto err;
        }
@@ -3122,7 +3249,7 @@ int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
        if (magic == DRBD_MD_MAGIC_84_UNCLEAN ||
            (magic == DRBD_MD_MAGIC_08 && !(flags & MDF_AL_CLEAN))) {
                        /* btw: that's Activity Log clean, not "all" clean. */
-               dev_err(DEV, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n");
+               drbd_err(device, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n");
                rv = ERR_MD_UNCLEAN;
                goto err;
        }
@@ -3130,14 +3257,14 @@ int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
        rv = ERR_MD_INVALID;
        if (magic != DRBD_MD_MAGIC_08) {
                if (magic == DRBD_MD_MAGIC_07)
-                       dev_err(DEV, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n");
+                       drbd_err(device, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n");
                else
-                       dev_err(DEV, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
+                       drbd_err(device, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
                goto err;
        }
 
        if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) {
-               dev_err(DEV, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
+               drbd_err(device, "unexpected bm_bytes_per_bit: %u (expected %u)\n",
                    be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE);
                goto err;
        }
@@ -3160,26 +3287,26 @@ int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
                goto err;
 
        if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) {
-               dev_err(DEV, "unexpected bm_offset: %d (expected %d)\n",
+               drbd_err(device, "unexpected bm_offset: %d (expected %d)\n",
                    be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset);
                goto err;
        }
        if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) {
-               dev_err(DEV, "unexpected md_size: %u (expected %u)\n",
+               drbd_err(device, "unexpected md_size: %u (expected %u)\n",
                    be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect);
                goto err;
        }
 
        rv = NO_ERROR;
 
-       spin_lock_irq(&device->connection->req_lock);
+       spin_lock_irq(&device->resource->req_lock);
        if (device->state.conn < C_CONNECTED) {
                unsigned int peer;
                peer = be32_to_cpu(buffer->la_peer_max_bio_size);
                peer = max(peer, DRBD_MAX_BIO_SIZE_SAFE);
                device->peer_max_bio_size = peer;
        }
-       spin_unlock_irq(&device->connection->req_lock);
+       spin_unlock_irq(&device->resource->req_lock);
 
  err:
        drbd_md_put_buffer(device);
@@ -3273,7 +3400,7 @@ void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local)
        bm_uuid = device->ldev->md.uuid[UI_BITMAP];
 
        if (bm_uuid)
-               dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid);
+               drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid);
 
        device->ldev->md.uuid[UI_BITMAP] = device->ldev->md.uuid[UI_CURRENT];
        __drbd_uuid_set(device, UI_CURRENT, val);
@@ -3298,7 +3425,7 @@ void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local)
        } else {
                unsigned long long bm_uuid = device->ldev->md.uuid[UI_BITMAP];
                if (bm_uuid)
-                       dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid);
+                       drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid);
 
                device->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1);
        }
@@ -3361,7 +3488,7 @@ static int w_bitmap_io(struct drbd_work *w, int unused)
        struct drbd_device *device = w->device;
        int rv = -EIO;
 
-       D_ASSERT(atomic_read(&device->ap_bio_cnt) == 0);
+       D_ASSERT(device, atomic_read(&device->ap_bio_cnt) == 0);
 
        if (get_ldev(device)) {
                drbd_bm_lock(device, work->why, work->flags);
@@ -3400,7 +3527,7 @@ static int w_go_diskless(struct drbd_work *w, int unused)
 {
        struct drbd_device *device = w->device;
 
-       D_ASSERT(device->state.disk == D_FAILED);
+       D_ASSERT(device, device->state.disk == D_FAILED);
        /* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
         * inc/dec it frequently. Once we are D_DISKLESS, no one will touch
         * the protected members anymore, though, so once put_ldev reaches zero
@@ -3454,13 +3581,13 @@ void drbd_queue_bitmap_io(struct drbd_device *device,
                          void (*done)(struct drbd_device *, int),
                          char *why, enum bm_flag flags)
 {
-       D_ASSERT(current == device->connection->worker.task);
+       D_ASSERT(device, current == first_peer_device(device)->connection->worker.task);
 
-       D_ASSERT(!test_bit(BITMAP_IO_QUEUED, &device->flags));
-       D_ASSERT(!test_bit(BITMAP_IO, &device->flags));
-       D_ASSERT(list_empty(&device->bm_io_work.w.list));
+       D_ASSERT(device, !test_bit(BITMAP_IO_QUEUED, &device->flags));
+       D_ASSERT(device, !test_bit(BITMAP_IO, &device->flags));
+       D_ASSERT(device, list_empty(&device->bm_io_work.w.list));
        if (device->bm_io_work.why)
-               dev_err(DEV, "FIXME going to queue '%s' but '%s' still pending?\n",
+               drbd_err(device, "FIXME going to queue '%s' but '%s' still pending?\n",
                        why, device->bm_io_work.why);
 
        device->bm_io_work.io_fn = io_fn;
@@ -3468,13 +3595,13 @@ void drbd_queue_bitmap_io(struct drbd_device *device,
        device->bm_io_work.why = why;
        device->bm_io_work.flags = flags;
 
-       spin_lock_irq(&device->connection->req_lock);
+       spin_lock_irq(&device->resource->req_lock);
        set_bit(BITMAP_IO, &device->flags);
        if (atomic_read(&device->ap_bio_cnt) == 0) {
                if (!test_and_set_bit(BITMAP_IO_QUEUED, &device->flags))
-                       drbd_queue_work(&device->connection->sender_work, &device->bm_io_work.w);
+                       drbd_queue_work(&first_peer_device(device)->connection->sender_work, &device->bm_io_work.w);
        }
-       spin_unlock_irq(&device->connection->req_lock);
+       spin_unlock_irq(&device->resource->req_lock);
 }
 
 /**
@@ -3491,7 +3618,7 @@ int drbd_bitmap_io(struct drbd_device *device, int (*io_fn)(struct drbd_device *
 {
        int rv;
 
-       D_ASSERT(current != device->connection->worker.task);
+       D_ASSERT(device, current != first_peer_device(device)->connection->worker.task);
 
        if ((flags & BM_LOCKED_SET_ALLOWED) == 0)
                drbd_suspend_io(device);
@@ -3532,16 +3659,16 @@ static void md_sync_timer_fn(unsigned long data)
 
        /* must not double-queue! */
        if (list_empty(&device->md_sync_work.list))
-               drbd_queue_work_front(&device->connection->sender_work, &device->md_sync_work);
+               drbd_queue_work_front(&first_peer_device(device)->connection->sender_work, &device->md_sync_work);
 }
 
 static int w_md_sync(struct drbd_work *w, int unused)
 {
        struct drbd_device *device = w->device;
 
-       dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
+       drbd_warn(device, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
 #ifdef DEBUG
-       dev_warn(DEV, "last md_mark_dirty: %s:%u\n",
+       drbd_warn(device, "last md_mark_dirty: %s:%u\n",
                device->last_md_mark_dirty.func, device->last_md_mark_dirty.line);
 #endif
        drbd_md_sync(device);
@@ -3631,7 +3758,7 @@ int drbd_wait_misc(struct drbd_device *device, struct drbd_interval *i)
        long timeout;
 
        rcu_read_lock();
-       nc = rcu_dereference(device->connection->net_conf);
+       nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
        if (!nc) {
                rcu_read_unlock();
                return -ETIMEDOUT;
@@ -3642,10 +3769,10 @@ int drbd_wait_misc(struct drbd_device *device, struct drbd_interval *i)
        /* Indicate to wake up device->misc_wait on progress.  */
        i->waiting = true;
        prepare_to_wait(&device->misc_wait, &wait, TASK_INTERRUPTIBLE);
-       spin_unlock_irq(&device->connection->req_lock);
+       spin_unlock_irq(&device->resource->req_lock);
        timeout = schedule_timeout(timeout);
        finish_wait(&device->misc_wait, &wait);
-       spin_lock_irq(&device->connection->req_lock);
+       spin_lock_irq(&device->resource->req_lock);
        if (!timeout || device->state.conn < C_CONNECTED)
                return -ETIMEDOUT;
        if (signal_pending(current))
@@ -3715,7 +3842,7 @@ _drbd_insert_fault(struct drbd_device *device, unsigned int type)
                fault_count++;
 
                if (__ratelimit(&drbd_ratelimit_state))
-                       dev_warn(DEV, "***Simulating %s failure\n",
+                       drbd_warn(device, "***Simulating %s failure\n",
                                _drbd_fault_str(type));
        }
 
This page took 0.057343 seconds and 5 git commands to generate.