block: Fix discard topology stacking and reporting
authorMartin K. Petersen <martin.petersen@oracle.com>
Wed, 18 May 2011 08:37:35 +0000 (10:37 +0200)
committerJens Axboe <jaxboe@fusionio.com>
Wed, 18 May 2011 08:37:35 +0000 (10:37 +0200)
In some cases we would end up stacking discard_zeroes_data incorrectly.
Fix this by enabling the feature by default for stacking drivers and
clearing it for low-level drivers. Incorporating a device that does not
support dzd will then cause the feature to be disabled in the stacking
driver.

Also ensure that the maximum discard value does not overflow when
exported in sysfs and return 0 in the alignment and dzd fields for
devices that don't support discard.

Reported-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@kernel.org
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
block/blk-settings.c
block/blk-sysfs.c
include/linux/blkdev.h

index cd3c428e194f90e633fcb0137d7e3501edfd5851..fa1eb0449a05f0db45de3ab8e6a01a2fc2a95238 100644 (file)
@@ -120,7 +120,7 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->discard_granularity = 0;
        lim->discard_alignment = 0;
        lim->discard_misaligned = 0;
-       lim->discard_zeroes_data = -1;
+       lim->discard_zeroes_data = 1;
        lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
        lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
        lim->alignment_offset = 0;
@@ -166,6 +166,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
 
        blk_set_default_limits(&q->limits);
        blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
+       q->limits.discard_zeroes_data = 0;
 
        /*
         * by default assume old behaviour and bounce for any highmem page
index 6d735122bc59499693d8682d4730c92ff63c91be..53bd0c77bfda1d08e0febc998bd3b74ea68d3250 100644 (file)
@@ -152,7 +152,8 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
 
 static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(q->limits.max_discard_sectors << 9, page);
+       return sprintf(page, "%llu\n",
+                      (unsigned long long)q->limits.max_discard_sectors << 9);
 }
 
 static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
index 9f921bf4bf8c2d25319631066335d916fb173204..520d8618ed762fa73463473baa2198fe1e3c73dc 100644 (file)
@@ -257,7 +257,7 @@ struct queue_limits {
        unsigned char           misaligned;
        unsigned char           discard_misaligned;
        unsigned char           cluster;
-       signed char             discard_zeroes_data;
+       unsigned char           discard_zeroes_data;
 };
 
 struct request_queue
@@ -1069,13 +1069,16 @@ static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector
 {
        unsigned int alignment = (sector << 9) & (lim->discard_granularity - 1);
 
+       if (!lim->max_discard_sectors)
+               return 0;
+
        return (lim->discard_granularity + lim->discard_alignment - alignment)
                & (lim->discard_granularity - 1);
 }
 
 static inline unsigned int queue_discard_zeroes_data(struct request_queue *q)
 {
-       if (q->limits.discard_zeroes_data == 1)
+       if (q->limits.max_discard_sectors && q->limits.discard_zeroes_data == 1)
                return 1;
 
        return 0;