]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/block/drbd/drbd_main.c
drbd: Fixes from the drbd-8.3 branch
[mirror_ubuntu-bionic-kernel.git] / drivers / block / drbd / drbd_main.c
index 178c711bc4af8df5f1eb7b52089eafe356826c1b..822fb3d4235614d4bf386352fb043f35a9d16891 100644 (file)
@@ -215,6 +215,7 @@ static int tl_init(struct drbd_tconn *tconn)
        tconn->oldest_tle = b;
        tconn->newest_tle = b;
        INIT_LIST_HEAD(&tconn->out_of_sequence_requests);
+       INIT_LIST_HEAD(&tconn->barrier_acked_requests);
 
        return 1;
 }
@@ -315,7 +316,7 @@ void tl_release(struct drbd_tconn *tconn, unsigned int barrier_nr,
           These have been list_move'd to the out_of_sequence_requests list in
           _req_mod(, BARRIER_ACKED) above.
           */
-       list_del_init(&b->requests);
+       list_splice_init(&b->requests, &tconn->barrier_acked_requests);
        mdev = b->w.mdev;
 
        nob = b->next;
@@ -367,8 +368,10 @@ void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
                        req = list_entry(le, struct drbd_request, tl_requests);
                        rv = _req_mod(req, what);
 
-                       n_writes += (rv & MR_WRITE) >> MR_WRITE_SHIFT;
-                       n_reads  += (rv & MR_READ) >> MR_READ_SHIFT;
+                       if (rv & MR_WRITE)
+                               n_writes++;
+                       if (rv & MR_READ)
+                               n_reads++;
                }
                tmp = b->next;
 
@@ -417,8 +420,23 @@ void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
                b = tmp;
                list_splice(&carry_reads, &b->requests);
        }
-}
 
+       /* Actions operating on the disk state, also want to work on
+          requests that got barrier acked. */
+       switch (what) {
+       case FAIL_FROZEN_DISK_IO:
+       case RESTART_FROZEN_DISK_IO:
+               list_for_each_safe(le, tle, &tconn->barrier_acked_requests) {
+                       req = list_entry(le, struct drbd_request, tl_requests);
+                       _req_mod(req, what);
+               }
+       case CONNECTION_LOST_WHILE_PENDING:
+       case RESEND:
+               break;
+       default:
+               conn_err(tconn, "what = %d in _tl_restart()\n", what);
+       }
+}
 
 /**
  * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
@@ -467,6 +485,41 @@ void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what)
        spin_unlock_irq(&tconn->req_lock);
 }
 
+/**
+ * tl_abort_disk_io() - Abort disk I/O for all requests for a certain mdev in the TL
+ * @mdev:      DRBD device.
+ */
+void tl_abort_disk_io(struct drbd_conf *mdev)
+{
+       struct drbd_tconn *tconn = mdev->tconn;
+       struct drbd_tl_epoch *b;
+       struct list_head *le, *tle;
+       struct drbd_request *req;
+
+       spin_lock_irq(&tconn->req_lock);
+       b = tconn->oldest_tle;
+       while (b) {
+               list_for_each_safe(le, tle, &b->requests) {
+                       req = list_entry(le, struct drbd_request, tl_requests);
+                       if (!(req->rq_state & RQ_LOCAL_PENDING))
+                               continue;
+                       if (req->w.mdev == mdev)
+                               _req_mod(req, ABORT_DISK_IO);
+               }
+               b = b->next;
+       }
+
+       list_for_each_safe(le, tle, &tconn->barrier_acked_requests) {
+               req = list_entry(le, struct drbd_request, tl_requests);
+               if (!(req->rq_state & RQ_LOCAL_PENDING))
+                       continue;
+               if (req->w.mdev == mdev)
+                       _req_mod(req, ABORT_DISK_IO);
+       }
+
+       spin_unlock_irq(&tconn->req_lock);
+}
+
 static int drbd_thread_setup(void *arg)
 {
        struct drbd_thread *thi = (struct drbd_thread *) arg;
@@ -926,7 +979,7 @@ int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd)
        rcu_read_lock();
        nc = rcu_dereference(tconn->net_conf);
 
-       if (nc->dry_run && tconn->agreed_pro_version < 92) {
+       if (nc->tentative && tconn->agreed_pro_version < 92) {
                rcu_read_unlock();
                mutex_unlock(&sock->mutex);
                conn_err(tconn, "--dry-run is not supported by peer");
@@ -945,7 +998,7 @@ int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd)
        cf = 0;
        if (nc->discard_my_data)
                cf |= CF_DISCARD_MY_DATA;
-       if (nc->dry_run)
+       if (nc->tentative)
                cf |= CF_DRY_RUN;
        p->conn_flags    = cpu_to_be32(cf);
 
@@ -1034,7 +1087,11 @@ void drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev)
 
        D_ASSERT(mdev->state.disk == D_UP_TO_DATE);
 
-       uuid = mdev->ldev->md.uuid[UI_BITMAP] + UUID_NEW_BM_OFFSET;
+       uuid = mdev->ldev->md.uuid[UI_BITMAP];
+       if (uuid && uuid != UUID_JUST_CREATED)
+               uuid = uuid + UUID_NEW_BM_OFFSET;
+       else
+               get_random_bytes(&uuid, sizeof(u64));
        drbd_uuid_set(mdev, UI_BITMAP, uuid);
        drbd_print_uuids(mdev, "updated sync UUID");
        drbd_md_sync(mdev);
@@ -1075,6 +1132,12 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
        p = drbd_prepare_command(mdev, sock);
        if (!p)
                return -EIO;
+
+       if (mdev->tconn->agreed_pro_version <= 94)
+               max_bio_size = min_t(int, max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
+       else if (mdev->tconn->agreed_pro_version < 100)
+               max_bio_size = min_t(int, max_bio_size, DRBD_MAX_BIO_SIZE_P95);
+
        p->d_size = cpu_to_be64(d_size);
        p->u_size = cpu_to_be64(u_size);
        p->c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
@@ -1722,8 +1785,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
 
        sock = &mdev->tconn->data;
        p = drbd_prepare_command(mdev, sock);
-       dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_tfm) ?
-               crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
+       dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
 
        if (!p)
                return -EIO;
@@ -1796,8 +1858,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packet cmd,
        sock = &mdev->tconn->data;
        p = drbd_prepare_command(mdev, sock);
 
-       dgs = (mdev->tconn->agreed_pro_version >= 87 && mdev->tconn->integrity_tfm) ?
-               crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
+       dgs = mdev->tconn->integrity_tfm ? crypto_hash_digestsize(mdev->tconn->integrity_tfm) : 0;
 
        if (!p)
                return -EIO;
@@ -1997,8 +2058,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
        atomic_set(&mdev->rs_sect_in, 0);
        atomic_set(&mdev->rs_sect_ev, 0);
        atomic_set(&mdev->ap_in_flight, 0);
+       atomic_set(&mdev->md_io_in_use, 0);
 
-       mutex_init(&mdev->md_io_mutex);
        mutex_init(&mdev->own_state_mutex);
        mdev->state_mutex = &mdev->own_state_mutex;
 
@@ -2276,6 +2337,8 @@ void drbd_minor_destroy(struct kref *kref)
        struct drbd_conf *mdev = container_of(kref, struct drbd_conf, kref);
        struct drbd_tconn *tconn = mdev->tconn;
 
+       del_timer_sync(&mdev->request_timer);
+
        /* paranoia asserts */
        D_ASSERT(mdev->open_cnt == 0);
        D_ASSERT(list_empty(&mdev->tconn->data.work.q));
@@ -2420,6 +2483,27 @@ found:
        return tconn;
 }
 
+struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len,
+                                    void *peer_addr, int peer_addr_len)
+{
+       struct drbd_tconn *tconn;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) {
+               if (tconn->my_addr_len == my_addr_len &&
+                   tconn->peer_addr_len == peer_addr_len &&
+                   !memcmp(&tconn->my_addr, my_addr, my_addr_len) &&
+                   !memcmp(&tconn->peer_addr, peer_addr, peer_addr_len)) {
+                       kref_get(&tconn->kref);
+                       goto found;
+               }
+       }
+       tconn = NULL;
+found:
+       rcu_read_unlock();
+       return tconn;
+}
+
 static int drbd_alloc_socket(struct drbd_socket *socket)
 {
        socket->rbuf = (void *) __get_free_page(GFP_KERNEL);
@@ -2458,8 +2542,47 @@ void conn_free_crypto(struct drbd_tconn *tconn)
        tconn->int_dig_vv = NULL;
 }
 
+int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts)
+{
+       cpumask_var_t new_cpu_mask;
+       int err;
+
+       if (!zalloc_cpumask_var(&new_cpu_mask, GFP_KERNEL))
+               return -ENOMEM;
+               /*
+               retcode = ERR_NOMEM;
+               drbd_msg_put_info("unable to allocate cpumask");
+               */
+
+       /* 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, 0,
+                               cpumask_bits(new_cpu_mask), nr_cpu_ids);
+               if (err) {
+                       conn_warn(tconn, "__bitmap_parse() failed with %d\n", err);
+                       /* retcode = ERR_CPU_MASK_PARSE; */
+                       goto fail;
+               }
+       }
+       tconn->res_opts = *res_opts;
+       if (!cpumask_equal(tconn->cpu_mask, new_cpu_mask)) {
+               cpumask_copy(tconn->cpu_mask, new_cpu_mask);
+               drbd_calc_cpu_mask(tconn);
+               tconn->receiver.reset_cpu_mask = 1;
+               tconn->asender.reset_cpu_mask = 1;
+               tconn->worker.reset_cpu_mask = 1;
+       }
+       err = 0;
+
+fail:
+       free_cpumask_var(new_cpu_mask);
+       return err;
+
+}
+
 /* caller must be under genl_lock() */
-struct drbd_tconn *conn_create(const char *name)
+struct drbd_tconn *conn_create(const char *name, struct res_opts *res_opts)
 {
        struct drbd_tconn *tconn;
 
@@ -2479,6 +2602,9 @@ struct drbd_tconn *conn_create(const char *name)
        if (!zalloc_cpumask_var(&tconn->cpu_mask, GFP_KERNEL))
                goto fail;
 
+       if (set_resource_options(tconn, res_opts))
+               goto fail;
+
        if (!tl_init(tconn))
                goto fail;
 
@@ -2499,8 +2625,6 @@ struct drbd_tconn *conn_create(const char *name)
        drbd_thread_init(tconn, &tconn->worker, drbd_worker, "worker");
        drbd_thread_init(tconn, &tconn->asender, drbd_asender, "asender");
 
-       drbd_set_res_opts_defaults(&tconn->res_opts);
-
        kref_init(&tconn->kref);
        list_add_tail_rcu(&tconn->all_tconn, &drbd_tconns);
 
@@ -2801,15 +2925,17 @@ void drbd_md_sync(struct drbd_conf *mdev)
        if (!get_ldev_if_state(mdev, D_FAILED))
                return;
 
-       mutex_lock(&mdev->md_io_mutex);
-       buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page);
+       buffer = drbd_md_get_buffer(mdev);
+       if (!buffer)
+               goto out;
+
        memset(buffer, 0, 512);
 
        buffer->la_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev));
        for (i = UI_CURRENT; i < UI_SIZE; i++)
                buffer->uuid[i] = cpu_to_be64(mdev->ldev->md.uuid[i]);
        buffer->flags = cpu_to_be32(mdev->ldev->md.flags);
-       buffer->magic = cpu_to_be32(DRBD_MD_MAGIC);
+       buffer->magic = cpu_to_be32(DRBD_MD_MAGIC_84_UNCLEAN);
 
        buffer->md_size_sect  = cpu_to_be32(mdev->ldev->md.md_size_sect);
        buffer->al_offset     = cpu_to_be32(mdev->ldev->md.al_offset);
@@ -2833,7 +2959,8 @@ void drbd_md_sync(struct drbd_conf *mdev)
         * since we updated it on metadata. */
        mdev->ldev->md.la_size_sect = drbd_get_capacity(mdev->this_bdev);
 
-       mutex_unlock(&mdev->md_io_mutex);
+       drbd_md_put_buffer(mdev);
+out:
        put_ldev(mdev);
 }
 
@@ -2843,18 +2970,20 @@ void drbd_md_sync(struct drbd_conf *mdev)
  * @bdev:      Device from which the meta data should be read in.
  *
  * Return 0 (NO_ERROR) on success, and an enum drbd_ret_code in case
- * something goes wrong.  Currently only: ERR_IO_MD_DISK, ERR_MD_INVALID.
+ * something goes wrong.
  */
 int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
 {
        struct meta_data_on_disk *buffer;
+       u32 magic, flags;
        int i, rv = NO_ERROR;
 
        if (!get_ldev_if_state(mdev, D_ATTACHING))
                return ERR_IO_MD_DISK;
 
-       mutex_lock(&mdev->md_io_mutex);
-       buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page);
+       buffer = drbd_md_get_buffer(mdev);
+       if (!buffer)
+               goto out;
 
        if (drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) {
                /* NOTE: can't do normal error processing here as this is
@@ -2864,8 +2993,20 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
                goto err;
        }
 
-       if (buffer->magic != cpu_to_be32(DRBD_MD_MAGIC)) {
-               dev_err(DEV, "Error while reading metadata, magic not found.\n");
+       magic = be32_to_cpu(buffer->magic);
+       flags = be32_to_cpu(buffer->flags);
+       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");
+               rv = ERR_MD_UNCLEAN;
+               goto err;
+       }
+       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");
+               else
+                       dev_err(DEV, "Meta data magic not found. Did you \"drbdadm create-md\"?\n");
                rv = ERR_MD_INVALID;
                goto err;
        }
@@ -2910,13 +3051,9 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
        }
        spin_unlock_irq(&mdev->tconn->req_lock);
 
-       /* This blocks wants to be get removed... */
-       bdev->disk_conf->al_extents = be32_to_cpu(buffer->al_nr_extents);
-       if (bdev->disk_conf->al_extents < DRBD_AL_EXTENTS_MIN)
-               bdev->disk_conf->al_extents = DRBD_AL_EXTENTS_DEF;
-
  err:
-       mutex_unlock(&mdev->md_io_mutex);
+       drbd_md_put_buffer(mdev);
+ out:
        put_ldev(mdev);
 
        return rv;