|
@@ -551,6 +551,47 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * zram_bio_discard - handler on discard request
|
|
|
+ * @index: physical block index in PAGE_SIZE units
|
|
|
+ * @offset: byte offset within physical block
|
|
|
+ */
|
|
|
+static void zram_bio_discard(struct zram *zram, u32 index,
|
|
|
+ int offset, struct bio *bio)
|
|
|
+{
|
|
|
+ size_t n = bio->bi_iter.bi_size;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * zram manages data in physical block size units. Because logical block
|
|
|
+ * size isn't identical with physical block size on some arch, we
|
|
|
+ * could get a discard request pointing to a specific offset within a
|
|
|
+ * certain physical block. Although we can handle this request by
|
|
|
+ * reading that physiclal block and decompressing and partially zeroing
|
|
|
+ * and re-compressing and then re-storing it, this isn't reasonable
|
|
|
+ * because our intent with a discard request is to save memory. So
|
|
|
+ * skipping this logical block is appropriate here.
|
|
|
+ */
|
|
|
+ if (offset) {
|
|
|
+ if (n < offset)
|
|
|
+ return;
|
|
|
+
|
|
|
+ n -= offset;
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (n >= PAGE_SIZE) {
|
|
|
+ /*
|
|
|
+ * Discard request can be large so the lock hold times could be
|
|
|
+ * lengthy. So take the lock once per page.
|
|
|
+ */
|
|
|
+ write_lock(&zram->meta->tb_lock);
|
|
|
+ zram_free_page(zram, index);
|
|
|
+ write_unlock(&zram->meta->tb_lock);
|
|
|
+ index++;
|
|
|
+ n -= PAGE_SIZE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void zram_reset_device(struct zram *zram, bool reset_capacity)
|
|
|
{
|
|
|
size_t index;
|
|
@@ -686,6 +727,12 @@ static void __zram_make_request(struct zram *zram, struct bio *bio)
|
|
|
offset = (bio->bi_iter.bi_sector &
|
|
|
(SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
|
|
|
|
|
|
+ if (unlikely(bio->bi_rw & REQ_DISCARD)) {
|
|
|
+ zram_bio_discard(zram, index, offset, bio);
|
|
|
+ bio_endio(bio, 0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
bio_for_each_segment(bvec, bio, iter) {
|
|
|
int max_transfer_size = PAGE_SIZE - offset;
|
|
|
|
|
@@ -855,6 +902,21 @@ static int create_device(struct zram *zram, int device_id)
|
|
|
ZRAM_LOGICAL_BLOCK_SIZE);
|
|
|
blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
|
|
|
blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
|
|
|
+ zram->disk->queue->limits.discard_granularity = PAGE_SIZE;
|
|
|
+ zram->disk->queue->limits.max_discard_sectors = UINT_MAX;
|
|
|
+ /*
|
|
|
+ * zram_bio_discard() will clear all logical blocks if logical block
|
|
|
+ * size is identical with physical block size(PAGE_SIZE). But if it is
|
|
|
+ * different, we will skip discarding some parts of logical blocks in
|
|
|
+ * the part of the request range which isn't aligned to physical block
|
|
|
+ * size. So we can't ensure that all discarded logical blocks are
|
|
|
+ * zeroed.
|
|
|
+ */
|
|
|
+ if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE)
|
|
|
+ zram->disk->queue->limits.discard_zeroes_data = 1;
|
|
|
+ else
|
|
|
+ zram->disk->queue->limits.discard_zeroes_data = 0;
|
|
|
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue);
|
|
|
|
|
|
add_disk(zram->disk);
|
|
|
|