drbd: Iterate over all connections
[deliverable/linux.git] / drivers / block / drbd / drbd_main.c
index 4da017d22f4b35617df02c534fc5e9e6f3a3e812..54df98fa288183f7d9e35d0bcfbbada55ce58c61 100644 (file)
@@ -118,7 +118,7 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0
  * as member "struct gendisk *vdisk;"
  */
 struct idr drbd_devices;
-struct list_head drbd_connections;  /* list of struct drbd_connection */
+struct list_head drbd_resources;
 
 struct kmem_cache *drbd_request_cache;
 struct kmem_cache *drbd_ee_cache;      /* peer requests */
@@ -227,18 +227,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;
        }
@@ -330,7 +330,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 +349,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,7 +361,7 @@ 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 */
 
@@ -392,12 +393,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,10 +412,10 @@ 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, drbd_destroy_connection);
                        module_put(THIS_MODULE);
@@ -428,7 +429,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,15 +496,16 @@ 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
@@ -784,7 +786,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;
        }
 
@@ -869,7 +871,7 @@ 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,7 +879,7 @@ 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);
        }
@@ -889,7 +891,7 @@ void drbd_gen_and_send_sync_uuid(struct drbd_device *device)
        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)
@@ -917,7 +919,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;
@@ -1124,7 +1126,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 +1135,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;
                }
 
@@ -1236,13 +1238,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);
@@ -1433,7 +1435,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);
        }
@@ -1515,7 +1517,7 @@ static int _drbd_send_page(struct drbd_device *device, struct page *page,
                                        break;
                                continue;
                        }
-                       dev_warn(DEV, "%s: size=%d len=%d sent=%d\n",
+                       drbd_warn(device, "%s: size=%d len=%d sent=%d\n",
                             __func__, (int)size, len, sent);
                        if (sent < 0)
                                err = sent;
@@ -1661,7 +1663,7 @@ int drbd_send_dblock(struct drbd_device *device, struct drbd_request *req)
                        unsigned char digest[64];
                        drbd_csum_bio(device, first_peer_device(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);
                        }
@@ -1798,7 +1800,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);
@@ -1953,7 +1955,7 @@ void drbd_device_cleanup(struct drbd_device *device)
 {
        int i;
        if (first_peer_device(device)->connection->receiver.t_state != NONE)
-               dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
+               drbd_err(device, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
                                first_peer_device(device)->connection->receiver.t_state);
 
        device->al_writ_cnt  =
@@ -1972,7 +1974,7 @@ void drbd_device_cleanup(struct drbd_device *device)
                device->rs_mark_left[i] = 0;
                device->rs_mark_time[i] = 0;
        }
-       D_ASSERT(first_peer_device(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) {
@@ -1986,16 +1988,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(&first_peer_device(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);
 }
@@ -2012,7 +2014,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);
@@ -2138,35 +2140,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_destroy_device(struct kref *kref)
 {
        struct drbd_device *device = container_of(kref, struct drbd_device, kref);
-       struct drbd_connection *connection = first_peer_device(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
@@ -2195,7 +2198,9 @@ void drbd_destroy_device(struct kref *kref)
        kfree(first_peer_device(device));
        kfree(device);
 
-       kref_put(&connection->kref, drbd_destroy_connection);
+       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
@@ -2232,7 +2237,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);
 
@@ -2276,12 +2281,32 @@ 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);
+       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);
 
@@ -2301,20 +2326,13 @@ static void drbd_cleanup(void)
 
        drbd_genl_unregister();
 
-       idr_for_each_entry(&drbd_devices, device, i) {
-               idr_remove(&drbd_devices, device_to_minor(device));
-               idr_remove(&first_peer_device(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_destroy_device);
-       }
+       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, drbd_destroy_connection);
+       for_each_resource_safe(resource, tmp, &drbd_resources) {
+               list_del(&resource->resources);
+               drbd_free_resource(resource);
        }
 
        drbd_destroy_mempools();
@@ -2388,39 +2406,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;
@@ -2467,8 +2488,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;
 
@@ -2485,18 +2507,20 @@ int set_resource_options(struct drbd_connection *connection, struct res_opts *re
                err = bitmap_parse(res_opts->cpu_mask, 32,
                                   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;
+       for_each_connection_rcu(connection, resource) {
+               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;
+               }
        }
        err = 0;
 
@@ -2506,19 +2530,35 @@ fail:
 
 }
 
+struct drbd_resource *drbd_create_resource(const char *name)
+{
+       struct drbd_resource *resource;
+
+       resource = kmalloc(sizeof(struct drbd_resource), GFP_KERNEL);
+       if (!resource)
+               return NULL;
+       resource->name = kstrdup(name, GFP_KERNEL);
+       if (!resource->name) {
+               kfree(resource);
+               return NULL;
+       }
+       kref_init(&resource->kref);
+       idr_init(&resource->devices);
+       INIT_LIST_HEAD(&resource->connections);
+       list_add_tail_rcu(&resource->resources, &drbd_resources);
+       return resource;
+}
+
 /* 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))
@@ -2527,9 +2567,6 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
        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;
@@ -2545,12 +2582,16 @@ 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);
@@ -2561,38 +2602,46 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
        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 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)
@@ -2610,14 +2659,14 @@ static int init_submitter(struct drbd_device *device)
        return 0;
 }
 
-enum drbd_ret_code drbd_create_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;
+       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);
@@ -2628,16 +2677,10 @@ enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigne
        device = kzalloc(sizeof(struct drbd_device), GFP_KERNEL);
        if (!device)
                return ERR_NOMEM;
-       peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL);
-       if (!peer_device)
-               goto out_no_peer_device;
-
-       INIT_LIST_HEAD(&device->peer_devices);
-       list_add(&peer_device->peer_devices, &device->peer_devices);
-       kref_get(&connection->kref);
-       peer_device->connection = connection;
-       peer_device->device = device;
+       kref_init(&device->kref);
 
+       kref_get(&resource->kref);
+       device->resource = resource;
        device->minor = minor;
        device->vnr = vnr;
 
@@ -2677,7 +2720,7 @@ enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigne
        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 = &first_peer_device(device)->connection->req_lock; /* needed since we use */
+       q->queue_lock = &connection->req_lock;
 
        device->md_io_page = alloc_page(GFP_KERNEL);
        if (!device->md_io_page)
@@ -2688,23 +2731,47 @@ enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigne
        device->read_requests = RB_ROOT;
        device->write_requests = RB_ROOT;
 
-       minor_got = idr_alloc(&drbd_devices, 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;
@@ -2713,19 +2780,31 @@ enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigne
        }
 
        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;
+       device->state.conn = first_connection(resource)->cstate;
        if (device->state.conn == C_WF_REPORT_PARAMS)
                drbd_connected(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(&drbd_devices, minor_got);
+       idr_remove(&drbd_devices, minor);
        synchronize_rcu();
 out_no_minor_idr:
        drbd_bm_cleanup(device);
@@ -2736,12 +2815,28 @@ out_no_io_page:
 out_no_disk:
        blk_cleanup_queue(q);
 out_no_q:
-       kref_put(&connection->kref, drbd_destroy_connection);
-out_no_peer_device:
+       kref_put(&resource->kref, drbd_destroy_resource);
        kfree(device);
        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;
@@ -2775,7 +2870,7 @@ int __init drbd_init(void)
        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) {
@@ -2855,11 +2950,13 @@ 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);
@@ -2920,12 +3017,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);
        }
 }
@@ -3007,7 +3104,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;
 }
@@ -3079,7 +3176,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,
@@ -3124,7 +3221,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;
        }
@@ -3134,7 +3231,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;
        }
@@ -3142,14 +3239,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;
        }
@@ -3172,12 +3269,12 @@ 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;
        }
@@ -3285,7 +3382,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);
@@ -3310,7 +3407,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);
        }
@@ -3373,7 +3470,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);
@@ -3412,7 +3509,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
@@ -3466,13 +3563,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 == first_peer_device(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;
@@ -3503,7 +3600,7 @@ int drbd_bitmap_io(struct drbd_device *device, int (*io_fn)(struct drbd_device *
 {
        int rv;
 
-       D_ASSERT(current != first_peer_device(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);
@@ -3551,9 +3648,9 @@ 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);
@@ -3727,7 +3824,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.041218 seconds and 5 git commands to generate.