On Mon, 2017-03-20 at 16:43 -0400, Christoph Hellwig wrote:
> @@ -698,13 +698,19 @@ static void sd_config_discard(struct scsi_disk *sdkp, 
> unsigned int mode)
>               break;
>  
>       case SD_LBP_ATA_TRIM:
> -             max_blocks = 65535 * (512 / sizeof(__le64));
> +             max_ranges = 512 / sizeof(__le64);
> +             max_range_size = USHRT_MAX;
> +             max_blocks = max_ranges * max_range_size;
>               if (sdkp->device->ata_trim_zeroes_data)
>                       q->limits.discard_zeroes_data = 1;
>               break;
>       }
>  
>       blk_queue_max_discard_sectors(q, max_blocks * (logical_block_size >> 
> 9));
> +     if (max_ranges)
> +             blk_queue_max_discard_segments(q, max_ranges);
> +     if (max_range_size)
> +             blk_queue_max_discard_segment_size(q, max_range_size);
>       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
>  }

Hello Christoph,

Does blk_queue_max_discard_segment_size() expect a second argument that is a
number of bytes? Is max_range_size a number of logical blocks that each have
a size 1 << sector_shift?

> @@ -826,14 +832,21 @@ static int sd_setup_ata_trim_cmnd(struct scsi_cmnd *cmd)
>       cmd->cmnd[8] = data_len;
>  
>       buf = page_address(rq->special_vec.bv_page);
> -     for (i = 0; i < (data_len >> 3); i++) {
> -             u64 n = min(nr_sectors, 0xffffu);
> +     __rq_for_each_bio(bio, rq) {
> +             u64 sector = bio->bi_iter.bi_sector >> (sector_shift - 9);
> +             u32 nr_sectors = bio->bi_iter.bi_size >> sector_shift;
>  
> -             buf[i] = cpu_to_le64(sector | (n << 48));
> -             if (nr_sectors <= 0xffff)
> -                     break;
> -             sector += 0xffff;
> -             nr_sectors -= 0xffff;
> +             do {
> +                     u64 n = min(nr_sectors, 0xffffu);
> +
> +                     buf[i] = cpu_to_le64(sector | (n << 48));
> +                     if (nr_sectors <= 0xffff)
> +                             break;
> +                     sector += 0xffff;
> +                     nr_sectors -= 0xffff;
> +                     i++;
> +
> +             } while (!WARN_ON_ONCE(i >= data_len >> 3));
>       }
>  
>       cmd->allowed = SD_MAX_RETRIES;

It's unfortunate that the loop-end test occurs twice (i < data_len >> 3).
Please consider using put_unaligned_le64() instead of cpu_to_le64() such
that the data type of buf can be changed from __le64* into void *. With
that change and by introducing e.g. the following:

void *end;
[ ... ]
end = (void *)buf + data_len;

the loop variable 'i' can be eliminated. If buf[i++] = ... would be
changed into *buf++ = ... then that would allow to change the two
occurrences of (i < data_len >> 3) into (buf < end).

Thanks,

Bart.

Reply via email to