Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drbd: make intelligent use of blkdev_issue_zeroout

drbd always wants its discard wire operations to zero the blocks, so
use blkdev_issue_zeroout with the BLKDEV_ZERO_UNMAP flag instead of
reinventing it poorly.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Christoph Hellwig and committed by
Jens Axboe
0dbed96a 71027e97

+7 -110
-3
drivers/block/drbd/drbd_debugfs.c
··· 236 236 seq_print_rq_state_bit(m, f & EE_CALL_AL_COMPLETE_IO, &sep, "in-AL"); 237 237 seq_print_rq_state_bit(m, f & EE_SEND_WRITE_ACK, &sep, "C"); 238 238 seq_print_rq_state_bit(m, f & EE_MAY_SET_IN_SYNC, &sep, "set-in-sync"); 239 - 240 - if (f & EE_IS_TRIM) 241 - __seq_print_rq_state_bit(m, f & EE_IS_TRIM_USE_ZEROOUT, &sep, "zero-out", "trim"); 242 239 seq_print_rq_state_bit(m, f & EE_WRITE_SAME, &sep, "write-same"); 243 240 seq_putc(m, '\n'); 244 241 }
-6
drivers/block/drbd/drbd_int.h
··· 437 437 438 438 /* is this a TRIM aka REQ_DISCARD? */ 439 439 __EE_IS_TRIM, 440 - /* our lower level cannot handle trim, 441 - * and we want to fall back to zeroout instead */ 442 - __EE_IS_TRIM_USE_ZEROOUT, 443 440 444 441 /* In case a barrier failed, 445 442 * we need to resubmit without the barrier flag. */ ··· 479 482 #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) 480 483 #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) 481 484 #define EE_IS_TRIM (1<<__EE_IS_TRIM) 482 - #define EE_IS_TRIM_USE_ZEROOUT (1<<__EE_IS_TRIM_USE_ZEROOUT) 483 485 #define EE_RESUBMITTED (1<<__EE_RESUBMITTED) 484 486 #define EE_WAS_ERROR (1<<__EE_WAS_ERROR) 485 487 #define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST) ··· 1557 1561 extern void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req); 1558 1562 1559 1563 /* drbd_receiver.c */ 1560 - extern int drbd_issue_discard_or_zero_out(struct drbd_device *device, 1561 - sector_t start, unsigned int nr_sectors, bool discard); 1562 1564 extern int drbd_receiver(struct drbd_thread *thi); 1563 1565 extern int drbd_ack_receiver(struct drbd_thread *thi); 1564 1566 extern void drbd_send_ping_wf(struct work_struct *ws);
+4 -98
drivers/block/drbd/drbd_receiver.c
··· 1448 1448 drbd_info(resource, "Method to ensure write ordering: %s\n", write_ordering_str[resource->write_ordering]); 1449 1449 } 1450 1450 1451 - /* 1452 - * We *may* ignore the discard-zeroes-data setting, if so configured. 1453 - * 1454 - * Assumption is that it "discard_zeroes_data=0" is only because the backend 1455 - * may ignore partial unaligned discards. 1456 - * 1457 - * LVM/DM thin as of at least 1458 - * LVM version: 2.02.115(2)-RHEL7 (2015-01-28) 1459 - * Library version: 1.02.93-RHEL7 (2015-01-28) 1460 - * Driver version: 4.29.0 1461 - * still behaves this way. 1462 - * 1463 - * For unaligned (wrt. alignment and granularity) or too small discards, 1464 - * we zero-out the initial (and/or) trailing unaligned partial chunks, 1465 - * but discard all the aligned full chunks. 1466 - * 1467 - * At least for LVM/DM thin, the result is effectively "discard_zeroes_data=1". 1468 - */ 1469 - int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, unsigned int nr_sectors, bool discard) 1470 - { 1471 - struct block_device *bdev = device->ldev->backing_bdev; 1472 - struct request_queue *q = bdev_get_queue(bdev); 1473 - sector_t tmp, nr; 1474 - unsigned int max_discard_sectors, granularity; 1475 - int alignment; 1476 - int err = 0; 1477 - 1478 - if (!discard) 1479 - goto zero_out; 1480 - 1481 - /* Zero-sector (unknown) and one-sector granularities are the same. */ 1482 - granularity = max(q->limits.discard_granularity >> 9, 1U); 1483 - alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; 1484 - 1485 - max_discard_sectors = min(q->limits.max_discard_sectors, (1U << 22)); 1486 - max_discard_sectors -= max_discard_sectors % granularity; 1487 - if (unlikely(!max_discard_sectors)) 1488 - goto zero_out; 1489 - 1490 - if (nr_sectors < granularity) 1491 - goto zero_out; 1492 - 1493 - tmp = start; 1494 - if (sector_div(tmp, granularity) != alignment) { 1495 - if (nr_sectors < 2*granularity) 1496 - goto zero_out; 1497 - /* start + gran - (start + gran - align) % gran */ 1498 - tmp = start + granularity - alignment; 1499 - tmp = start + granularity - sector_div(tmp, granularity); 1500 - 1501 - nr = tmp - start; 1502 - err |= blkdev_issue_zeroout(bdev, start, nr, GFP_NOIO, 1503 - BLKDEV_ZERO_NOUNMAP); 1504 - nr_sectors -= nr; 1505 - start = tmp; 1506 - } 1507 - while (nr_sectors >= granularity) { 1508 - nr = min_t(sector_t, nr_sectors, max_discard_sectors); 1509 - err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO, 1510 - BLKDEV_ZERO_NOUNMAP); 1511 - nr_sectors -= nr; 1512 - start += nr; 1513 - } 1514 - zero_out: 1515 - if (nr_sectors) { 1516 - err |= blkdev_issue_zeroout(bdev, start, nr_sectors, GFP_NOIO, 1517 - BLKDEV_ZERO_NOUNMAP); 1518 - } 1519 - return err != 0; 1520 - } 1521 - 1522 - static bool can_do_reliable_discards(struct drbd_device *device) 1523 - { 1524 - struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev); 1525 - struct disk_conf *dc; 1526 - bool can_do; 1527 - 1528 - if (!blk_queue_discard(q)) 1529 - return false; 1530 - 1531 - if (q->limits.discard_zeroes_data) 1532 - return true; 1533 - 1534 - rcu_read_lock(); 1535 - dc = rcu_dereference(device->ldev->disk_conf); 1536 - can_do = dc->discard_zeroes_if_aligned; 1537 - rcu_read_unlock(); 1538 - return can_do; 1539 - } 1540 - 1541 1451 static void drbd_issue_peer_discard(struct drbd_device *device, struct drbd_peer_request *peer_req) 1542 1452 { 1543 - /* If the backend cannot discard, or does not guarantee 1544 - * read-back zeroes in discarded ranges, we fall back to 1545 - * zero-out. Unless configuration specifically requested 1546 - * otherwise. */ 1547 - if (!can_do_reliable_discards(device)) 1548 - peer_req->flags |= EE_IS_TRIM_USE_ZEROOUT; 1453 + struct block_device *bdev = device->ldev->backing_bdev; 1549 1454 1550 - if (drbd_issue_discard_or_zero_out(device, peer_req->i.sector, 1551 - peer_req->i.size >> 9, !(peer_req->flags & EE_IS_TRIM_USE_ZEROOUT))) 1455 + if (blkdev_issue_zeroout(bdev, peer_req->i.sector, peer_req->i.size >> 9, 1456 + GFP_NOIO, 0)) 1552 1457 peer_req->flags |= EE_WAS_ERROR; 1458 + 1553 1459 drbd_endio_write_sec_final(peer_req); 1554 1460 } 1555 1461
+3 -3
drivers/block/drbd/drbd_req.c
··· 1148 1148 1149 1149 static void drbd_process_discard_req(struct drbd_request *req) 1150 1150 { 1151 - int err = drbd_issue_discard_or_zero_out(req->device, 1152 - req->i.sector, req->i.size >> 9, true); 1151 + struct block_device *bdev = req->device->ldev->backing_bdev; 1153 1152 1154 - if (err) 1153 + if (blkdev_issue_zeroout(bdev, req->i.sector, req->i.size >> 9, 1154 + GFP_NOIO, 0)) 1155 1155 req->private_bio->bi_error = -EIO; 1156 1156 bio_endio(req->private_bio); 1157 1157 }