]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/block/drbd/drbd_nl.c
drbd: add packet_type 27 (return_code_only) to netlink api
[karo-tx-linux.git] / drivers / block / drbd / drbd_nl.c
index 29e5c70e4e26c7f6e35b8bb1bec0b7f65442f3a0..6a6dde6c51c6076bd5346d09a6addc6113aad8fc 100644 (file)
@@ -765,22 +765,21 @@ static int drbd_check_al_size(struct drbd_conf *mdev)
        return 0;
 }
 
-void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __must_hold(local)
+void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size) __must_hold(local)
 {
        struct request_queue * const q = mdev->rq_queue;
        struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
        int max_segments = mdev->ldev->dc.max_bio_bvecs;
+       int max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
 
-       max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s);
-
-       blk_queue_max_hw_sectors(q, max_seg_s >> 9);
-       blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
-       blk_queue_max_segment_size(q, max_seg_s);
        blk_queue_logical_block_size(q, 512);
-       blk_queue_segment_boundary(q, PAGE_SIZE-1);
-       blk_stack_limits(&q->limits, &b->limits, 0);
+       blk_queue_max_hw_sectors(q, max_hw_sectors);
+       /* This is the workaround for "bio would need to, but cannot, be split" */
+       blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
+       blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
+       blk_queue_stack_limits(q, b);
 
-       dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q));
+       dev_info(DEV, "max BIO size = %u\n", queue_max_hw_sectors(q) << 9);
 
        if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
                dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
@@ -855,10 +854,10 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        sector_t max_possible_sectors;
        sector_t min_md_device_sectors;
        struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
-       struct inode *inode, *inode2;
+       struct block_device *bdev;
        struct lru_cache *resync_lru = NULL;
        union drbd_state ns, os;
-       unsigned int max_seg_s;
+       unsigned int max_bio_size;
        int rv;
        int cp_discovered = 0;
        int logical_block_size;
@@ -907,46 +906,40 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
                }
        }
 
-       nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0);
-       if (IS_ERR(nbc->lo_file)) {
+       bdev = blkdev_get_by_path(nbc->dc.backing_dev,
+                                 FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev);
+       if (IS_ERR(bdev)) {
                dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev,
-                   PTR_ERR(nbc->lo_file));
-               nbc->lo_file = NULL;
+                       PTR_ERR(bdev));
                retcode = ERR_OPEN_DISK;
                goto fail;
        }
+       nbc->backing_bdev = bdev;
 
-       inode = nbc->lo_file->f_dentry->d_inode;
-
-       if (!S_ISBLK(inode->i_mode)) {
-               retcode = ERR_DISK_NOT_BDEV;
-               goto fail;
-       }
-
-       nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0);
-       if (IS_ERR(nbc->md_file)) {
+       /*
+        * meta_dev_idx >= 0: external fixed size, possibly multiple
+        * drbd sharing one meta device.  TODO in that case, paranoia
+        * check that [md_bdev, meta_dev_idx] is not yet used by some
+        * other drbd minor!  (if you use drbd.conf + drbdadm, that
+        * should check it for you already; but if you don't, or
+        * someone fooled it, we need to double check here)
+        */
+       bdev = blkdev_get_by_path(nbc->dc.meta_dev,
+                                 FMODE_READ | FMODE_WRITE | FMODE_EXCL,
+                                 (nbc->dc.meta_dev_idx < 0) ?
+                                 (void *)mdev : (void *)drbd_m_holder);
+       if (IS_ERR(bdev)) {
                dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev,
-                   PTR_ERR(nbc->md_file));
-               nbc->md_file = NULL;
+                       PTR_ERR(bdev));
                retcode = ERR_OPEN_MD_DISK;
                goto fail;
        }
+       nbc->md_bdev = bdev;
 
-       inode2 = nbc->md_file->f_dentry->d_inode;
-
-       if (!S_ISBLK(inode2->i_mode)) {
-               retcode = ERR_MD_NOT_BDEV;
-               goto fail;
-       }
-
-       nbc->backing_bdev = inode->i_bdev;
-       if (bd_claim(nbc->backing_bdev, mdev)) {
-               printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n",
-                      nbc->backing_bdev, mdev,
-                      nbc->backing_bdev->bd_holder,
-                      nbc->backing_bdev->bd_contains->bd_holder,
-                      nbc->backing_bdev->bd_holders);
-               retcode = ERR_BDCLAIM_DISK;
+       if ((nbc->backing_bdev == nbc->md_bdev) !=
+           (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
+            nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
+               retcode = ERR_MD_IDX_INVALID;
                goto fail;
        }
 
@@ -955,28 +948,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
                        offsetof(struct bm_extent, lce));
        if (!resync_lru) {
                retcode = ERR_NOMEM;
-               goto release_bdev_fail;
-       }
-
-       /* meta_dev_idx >= 0: external fixed size,
-        * possibly multiple drbd sharing one meta device.
-        * TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is
-        * not yet used by some other drbd minor!
-        * (if you use drbd.conf + drbdadm,
-        * that should check it for you already; but if you don't, or someone
-        * fooled it, we need to double check here) */
-       nbc->md_bdev = inode2->i_bdev;
-       if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev
-                               : (void *) drbd_m_holder)) {
-               retcode = ERR_BDCLAIM_MD_DISK;
-               goto release_bdev_fail;
-       }
-
-       if ((nbc->backing_bdev == nbc->md_bdev) !=
-           (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
-            nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
-               retcode = ERR_MD_IDX_INVALID;
-               goto release_bdev2_fail;
+               goto fail;
        }
 
        /* RT - for drbd_get_max_capacity() DRBD_MD_INDEX_FLEX_INT */
@@ -987,7 +959,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
                        (unsigned long long) drbd_get_max_capacity(nbc),
                        (unsigned long long) nbc->dc.disk_size);
                retcode = ERR_DISK_TO_SMALL;
-               goto release_bdev2_fail;
+               goto fail;
        }
 
        if (nbc->dc.meta_dev_idx < 0) {
@@ -1004,7 +976,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
                dev_warn(DEV, "refusing attach: md-device too small, "
                     "at least %llu sectors needed for this meta-disk type\n",
                     (unsigned long long) min_md_device_sectors);
-               goto release_bdev2_fail;
+               goto fail;
        }
 
        /* Make sure the new disk is big enough
@@ -1012,7 +984,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        if (drbd_get_max_capacity(nbc) <
            drbd_get_capacity(mdev->this_bdev)) {
                retcode = ERR_DISK_TO_SMALL;
-               goto release_bdev2_fail;
+               goto fail;
        }
 
        nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
@@ -1035,7 +1007,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
        drbd_resume_io(mdev);
        if (retcode < SS_SUCCESS)
-               goto release_bdev2_fail;
+               goto fail;
 
        if (!get_ldev_if_state(mdev, D_ATTACHING))
                goto force_diskless;
@@ -1136,20 +1108,20 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        mdev->read_cnt = 0;
        mdev->writ_cnt = 0;
 
-       max_seg_s = DRBD_MAX_SEGMENT_SIZE;
+       max_bio_size = DRBD_MAX_BIO_SIZE;
        if (mdev->state.conn == C_CONNECTED) {
                /* We are Primary, Connected, and now attach a new local
                 * backing store. We must not increase the user visible maximum
                 * bio size on this device to something the peer may not be
                 * able to handle. */
                if (mdev->agreed_pro_version < 94)
-                       max_seg_s = queue_max_segment_size(mdev->rq_queue);
+                       max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
                else if (mdev->agreed_pro_version == 94)
-                       max_seg_s = DRBD_MAX_SIZE_H80_PACKET;
+                       max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
                /* else: drbd 8.3.9 and later, stay with default */
        }
 
-       drbd_setup_queue_param(mdev, max_seg_s);
+       drbd_setup_queue_param(mdev, max_bio_size);
 
        /* If I am currently not R_PRIMARY,
         * but meta data primary indicator is set,
@@ -1269,18 +1241,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
  force_diskless:
        drbd_force_state(mdev, NS(disk, D_FAILED));
        drbd_md_sync(mdev);
- release_bdev2_fail:
-       if (nbc)
-               bd_release(nbc->md_bdev);
- release_bdev_fail:
-       if (nbc)
-               bd_release(nbc->backing_bdev);
  fail:
        if (nbc) {
-               if (nbc->lo_file)
-                       fput(nbc->lo_file);
-               if (nbc->md_file)
-                       fput(nbc->md_file);
+               if (nbc->backing_bdev)
+                       blkdev_put(nbc->backing_bdev,
+                                  FMODE_READ | FMODE_WRITE | FMODE_EXCL);
+               if (nbc->md_bdev)
+                       blkdev_put(nbc->md_bdev,
+                                  FMODE_READ | FMODE_WRITE | FMODE_EXCL);
                kfree(nbc);
        }
        lc_destroy(resync_lru);
@@ -1355,6 +1323,8 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
        new_conf->wire_protocol    = DRBD_PROT_C;
        new_conf->ping_timeo       = DRBD_PING_TIMEO_DEF;
        new_conf->rr_conflict      = DRBD_RR_CONFLICT_DEF;
+       new_conf->on_congestion    = DRBD_ON_CONGESTION_DEF;
+       new_conf->cong_extents     = DRBD_CONG_EXTENTS_DEF;
 
        if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) {
                retcode = ERR_MANDATORY_TAG;
@@ -1376,6 +1346,11 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
                }
        }
 
+       if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A) {
+               retcode = ERR_CONG_NOT_PROTO_A;
+               goto fail;
+       }
+
        if (mdev->state.role == R_PRIMARY && new_conf->want_lose) {
                retcode = ERR_DISCARD;
                goto fail;
@@ -2220,7 +2195,8 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
                goto fail;
        }
 
-       if (nlp->packet_type >= P_nl_after_last_packet) {
+       if (nlp->packet_type >= P_nl_after_last_packet ||
+           nlp->packet_type == P_return_code_only) {
                retcode = ERR_PACKET_NR;
                goto fail;
        }
@@ -2236,7 +2212,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
        reply_size += cm->reply_body_size;
 
        /* allocation not in the IO path, cqueue thread context */
-       cn_reply = kmalloc(reply_size, GFP_KERNEL);
+       cn_reply = kzalloc(reply_size, GFP_KERNEL);
        if (!cn_reply) {
                retcode = ERR_NOMEM;
                goto fail;
@@ -2244,7 +2220,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms
        reply = (struct drbd_nl_cfg_reply *) cn_reply->data;
 
        reply->packet_type =
-               cm->reply_body_size ? nlp->packet_type : P_nl_after_last_packet;
+               cm->reply_body_size ? nlp->packet_type : P_return_code_only;
        reply->minor = nlp->drbd_minor;
        reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */
        /* reply->tag_list; might be modified by cm->function. */
@@ -2407,7 +2383,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev,
        /* receiver thread context, which is not in the writeout path (of this node),
         * but may be in the writeout path of the _other_ node.
         * GFP_NOIO to avoid potential "distributed deadlock". */
-       cn_reply = kmalloc(
+       cn_reply = kzalloc(
                sizeof(struct cn_msg)+
                sizeof(struct drbd_nl_cfg_reply)+
                sizeof(struct dump_ee_tag_len_struct)+
@@ -2429,10 +2405,11 @@ void drbd_bcast_ee(struct drbd_conf *mdev,
        tl = tl_add_int(tl, T_ee_sector, &e->sector);
        tl = tl_add_int(tl, T_ee_block_id, &e->block_id);
 
+       /* dump the first 32k */
+       len = min_t(unsigned, e->size, 32 << 10);
        put_unaligned(T_ee_data, tl++);
-       put_unaligned(e->size, tl++);
+       put_unaligned(len, tl++);
 
-       len = e->size;
        page = e->pages;
        page_chain_for_each(page) {
                void *d = kmap_atomic(page, KM_USER0);
@@ -2441,6 +2418,8 @@ void drbd_bcast_ee(struct drbd_conf *mdev,
                kunmap_atomic(d, KM_USER0);
                tl = (unsigned short*)((char*)tl + l);
                len -= l;
+               if (len == 0)
+                       break;
        }
        put_unaligned(TT_END, tl++); /* Close the tag list */
 
@@ -2539,6 +2518,7 @@ void drbd_nl_send_reply(struct cn_msg *req, int ret_code)
                (struct drbd_nl_cfg_reply *)cn_reply->data;
        int rr;
 
+       memset(buffer, 0, sizeof(buffer));
        cn_reply->id = req->id;
 
        cn_reply->seq = req->seq;
@@ -2546,6 +2526,7 @@ void drbd_nl_send_reply(struct cn_msg *req, int ret_code)
        cn_reply->len = sizeof(struct drbd_nl_cfg_reply);
        cn_reply->flags = 0;
 
+       reply->packet_type = P_return_code_only;
        reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor;
        reply->ret_code = ret_code;