drbd: Enable QUEUE_FLAG_DISCARD only if the peer can recieve P_TRIM
authorLars Ellenberg <lars.ellenberg@linbit.com>
Mon, 28 Apr 2014 16:43:25 +0000 (18:43 +0200)
committerJens Axboe <axboe@fb.com>
Wed, 30 Apr 2014 19:46:55 +0000 (13:46 -0600)
Allow the user of REQ_DISCARD.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_protocol.h
drivers/block/drbd/drbd_receiver.c

index 29123dfb5f84d0618e9826c1d850ece3cb708039..d5f39fda6462fa39b9227c06ab6b083d52b78405 100644 (file)
@@ -618,6 +618,7 @@ struct drbd_connection {
        struct drbd_socket data;        /* data/barrier/cstate/parameter packets */
        struct drbd_socket meta;        /* ping/ack (metadata) packets */
        int agreed_pro_version;         /* actually used protocol version */
+       u32 agreed_features;
        unsigned long last_received;    /* in jiffies, either socket */
        unsigned int ko_count;
 
index bb3679263ea74e19495eb806cc1d428f1187d101..2364b781d9acec3eb086adb14df55053984bd83d 100644 (file)
@@ -1133,6 +1133,26 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_
 
        if (get_ldev_if_state(device, D_ATTACHING)) {
                struct request_queue * const b = device->ldev->backing_bdev->bd_disk->queue;
+               struct drbd_connection *connection = first_peer_device(device)->connection;
+
+               if (blk_queue_discard(b) &&
+                   (connection->cstate < C_CONNECTED || connection->agreed_features & FF_TRIM)) {
+                       /* inherit from backing queue */
+                       q->limits.discard_zeroes_data = 1;
+                       /* For now, don't allow more than one activity log extent worth of data
+                        * to be discarded in one go. We may need to rework drbd_al_begin_io()
+                        * to allow for even larger discard ranges */
+                       q->limits.max_discard_sectors = DRBD_MAX_DISCARD_SECTORS;
+
+                       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+                       /* REALLY? Is stacking secdiscard "legal"? */
+                       if (blk_queue_secdiscard(b))
+                               queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+               } else {
+                       q->limits.max_discard_sectors = 0;
+                       queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
+                       queue_flag_clear_unlocked(QUEUE_FLAG_SECDISCARD, q);
+               }
 
                blk_queue_stack_limits(q, b);
 
index 478c63d0b6f3c71a0a8d137ec425d2cb5d2fde99..2da9104a3851813010eae268fa778c82ac5b2d4c 100644 (file)
@@ -160,6 +160,8 @@ struct p_block_req {
  *   ReportParams
  */
 
+#define FF_TRIM      1
+
 struct p_connection_features {
        u32 protocol_min;
        u32 feature_flags;
index 9640b645d5ba7dc0d0cc1c05f42c6a6fcf1a9264..3fa3b78e2ea10caaff42d1470cdc965afe84038e 100644 (file)
 #include "drbd_int.h"
 #include "drbd_protocol.h"
 #include "drbd_req.h"
-
 #include "drbd_vli.h"
 
+#define PRO_FEATURES (FF_TRIM)
+
 struct packet_info {
        enum drbd_packet cmd;
        unsigned int size;
@@ -3705,6 +3706,13 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
                put_ldev(device);
        }
 
+       device->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+       drbd_reconsider_max_bio_size(device);
+       /* Leave drbd_reconsider_max_bio_size() before drbd_determine_dev_size().
+          In case we cleared the QUEUE_FLAG_DISCARD from our queue in
+          drbd_reconsider_max_bio_size(), we can be sure that after
+          drbd_determine_dev_size() no REQ_DISCARDs are in the queue. */
+
        ddsf = be16_to_cpu(p->dds_flags);
        if (get_ldev(device)) {
                dd = drbd_determine_dev_size(device, ddsf, NULL);
@@ -3717,9 +3725,6 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info
                drbd_set_my_capacity(device, p_size);
        }
 
-       device->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
-       drbd_reconsider_max_bio_size(device);
-
        if (get_ldev(device)) {
                if (device->ldev->known_size != drbd_get_capacity(device->ldev->backing_bdev)) {
                        device->ldev->known_size = drbd_get_capacity(device->ldev->backing_bdev);
@@ -4688,6 +4693,7 @@ static int drbd_send_features(struct drbd_connection *connection)
        memset(p, 0, sizeof(*p));
        p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
        p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
+       p->feature_flags = cpu_to_be32(PRO_FEATURES);
        return conn_send_command(connection, sock, P_CONNECTION_FEATURES, sizeof(*p), NULL, 0);
 }
 
@@ -4741,10 +4747,14 @@ static int drbd_do_features(struct drbd_connection *connection)
                goto incompat;
 
        connection->agreed_pro_version = min_t(int, PRO_VERSION_MAX, p->protocol_max);
+       connection->agreed_features = PRO_FEATURES & be32_to_cpu(p->feature_flags);
 
        drbd_info(connection, "Handshake successful: "
             "Agreed network protocol version %d\n", connection->agreed_pro_version);
 
+       drbd_info(connection, "Agreed to%ssupport TRIM on protocol level\n",
+                 connection->agreed_features & FF_TRIM ? " " : " not ");
+
        return 1;
 
  incompat: