On Mon, Jul 04, 2011 at 05:11:35PM -0700, Matthew Dempsky wrote:
> A bunch of disk drivers currently check whether a buf request is
> sector-aligned (e.g., vnd(4)) or that a request is for a multiple of
> secsize (e.g., sd(4)), but none of them check both.
> 
> Instead of doing this in each disk driver, the logical place to
> validate this is in bounds_check_with_label().
> 
> While here, I rewrote bounds_check_with_label() to be a bit easier to
> read and be safer with integer arithmetic to avoid overflows (though I
> don't think in practice this is actually a risk).
> 
> Once this goes in, I'll start updating the xxstrategy() methods to
> remove these redundant checks.
> 
> ok?
> 
> 
> Index: subr_disk.c
> ===================================================================
> RCS file: /home/mdempsky/anoncvs/cvs/src/sys/kern/subr_disk.c,v
> retrieving revision 1.127
> diff -u -p -r1.127 subr_disk.c
> --- subr_disk.c       30 Jun 2011 16:28:05 -0000      1.127
> +++ subr_disk.c       4 Jul 2011 23:59:39 -0000
> @@ -687,25 +687,30 @@ int
>  bounds_check_with_label(struct buf *bp, struct disklabel *lp)
>  {
>       struct partition *p = &lp->d_partitions[DISKPART(bp->b_dev)];
> -     daddr64_t sz = howmany(bp->b_bcount, DEV_BSIZE);
> +     daddr64_t partblocks, sz;
>  
> -     /* Avoid division by zero, negative offsets and negative sizes. */
> -     if (lp->d_secpercyl == 0 || bp->b_blkno < 0 || sz < 0)
> +     /* Avoid division by zero, negative offsets, and negative sizes. */
> +     if (lp->d_secpercyl == 0 || bp->b_blkno < 0 || bp->b_bcount < 0)
>               goto bad;
>  
> -     /* beyond partition? */
> -     if (bp->b_blkno + sz > DL_SECTOBLK(lp, DL_GETPSIZE(p))) {
> -             sz = DL_SECTOBLK(lp, DL_GETPSIZE(p)) - bp->b_blkno;
> -             if (sz == 0) {
> -                     /* If exactly at end of disk, return EOF. */
> -                     bp->b_resid = bp->b_bcount;
> -                     return (-1);
> -             }
> -             if (sz < 0)
> -                     /* If past end of disk, return EINVAL. */
> -                     goto bad;
> +     /* Ensure transfer is a whole number of aligned sectors. */
> +     if ((bp->b_blkno % DL_BLKSPERSEC(lp)) != 0 ||
> +         (bp->b_bcount % lp->d_secsize) != 0)
> +             goto bad;
> +
> +     /* Ensure transfer starts within partition boundary. */
> +     partblocks = DL_SECTOBLK(lp, DL_GETPSIZE(p));
> +     if (bp->b_blkno > partblocks)
> +             goto bad;
> +
> +     /* If exactly at end of partition or 0-byte request, return EOF. */
> +     if (bp->b_blkno == partblocks || bp->b_bcount == 0)
> +             goto done;
>  
> -             /* Otherwise, truncate request. */
> +     /* Truncate request if it exceeds past the end of the partition. */
> +     sz = bp->b_bcount >> DEV_BSHIFT;
> +     if (sz > partblocks - bp->b_blkno) {
> +             sz = partblocks - bp->b_blkno;
>               bp->b_bcount = sz << DEV_BSHIFT;
>       }
>  
> @@ -714,9 +719,11 @@ bounds_check_with_label(struct buf *bp, 
>           DL_SECTOBLK(lp, lp->d_secpercyl);
>       return (1);
>  
> -bad:
> + bad:
>       bp->b_error = EINVAL;
>       bp->b_flags |= B_ERROR;
> + done:
> +     bp->b_resid = bp->b_bcount;
>       return (-1);
>  }
> 

I like this a *lot*. My only question is why the whitespace before bad: and 
done:? ok krw@

.... Ken

Reply via email to