NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/56332: swap on 4k sector device uses only 1/8 of the configured capacity



The following reply was made to PR kern/56332; it has been noted by GNATS.

From: mlelstv%serpens.de@localhost (Michael van Elst)
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: kern/56332: swap on 4k sector device uses only 1/8 of the configured capacity
Date: Wed, 28 Jul 2021 05:31:57 -0000 (UTC)

 tnn%nygren.pp.se@localhost writes:
 
 >ld4 at nvme0 nsid 1
 >ld4: 238 GB, 7752 cyl, 128 head, 63 sec, 4096 bytes/sect x 62514774 sectors
 >dk3 at ld4: 8388608 blocks at 50397440, type: swap
 >... but only 4 GiB is available.
 
 That looks like a bug in the dk driver.
 
 swap/dump are somewhat magic. Drivers have their own entry points to
 handle a swap (and dump) partition:
 
 DEVsize -> return the number of blocks
 DEVdump -> dump that many bytes to a given block number.
 
 Users of the driver will use DEV_BSIZE blocks, like for regular I/O.
 
 But dksize() returns sc_size and dkdump() checks block numbers against
 sc_size and offsets them by sc_offset. Both use the physical sector
 sizes (sc_size is 8388608, sc_offset is 50397440).
 
 So it's not only reporting the wrong size, but also writes to the
 wrong position on the disk if the physical sector size is not DEV_BSIZE.
 
 The regular I/O code does the right translation. So maybe (untested):
 
 Index: dk.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/dkwedge/dk.c,v
 retrieving revision 1.105
 diff -p -u -r1.105 dk.c
 --- dk.c	2 Jun 2021 17:56:40 -0000	1.105
 +++ dk.c	28 Jul 2021 05:31:14 -0000
 @@ -1639,6 +1639,7 @@ static int
  dksize(dev_t dev)
  {
  	struct dkwedge_softc *sc = dkwedge_lookup(dev);
 +	uint64_t p_size;
  	int rv = -1;
  
  	if (sc == NULL)
 @@ -1651,12 +1652,13 @@ dksize(dev_t dev)
  
  	/* Our content type is static, no need to open the device. */
  
 +	p_size   = sc->sc_size << sc->sc_parent->dk_blkshift;
  	if (strcmp(sc->sc_ptype, DKW_PTYPE_SWAP) == 0) {
  		/* Saturate if we are larger than INT_MAX. */
 -		if (sc->sc_size > INT_MAX)
 +		if (p_size > INT_MAX)
  			rv = INT_MAX;
  		else
 -			rv = (int) sc->sc_size;
 +			rv = (int) p_size;
  	}
  
  	mutex_exit(&sc->sc_parent->dk_rawlock);
 @@ -1675,6 +1677,7 @@ dkdump(dev_t dev, daddr_t blkno, void *v
  {
  	struct dkwedge_softc *sc = dkwedge_lookup(dev);
  	const struct bdevsw *bdev;
 +	uint64_t p_size, p_offset;
  	int rv = 0;
  
  	if (sc == NULL)
 @@ -1697,16 +1700,20 @@ dkdump(dev_t dev, daddr_t blkno, void *v
  		rv = EINVAL;
  		goto out;
  	}
 -	if (blkno < 0 || blkno + size / DEV_BSIZE > sc->sc_size) {
 +
 +	p_offset = sc->sc_offset << sc->sc_parent->dk_blkshift;
 +	p_size   = sc->sc_size << sc->sc_parent->dk_blkshift;
 +
 +	if (blkno < 0 || blkno + size / DEV_BSIZE > p_size) {
  		printf("%s: blkno (%" PRIu64 ") + size / DEV_BSIZE (%zu) > "
 -		    "sc->sc_size (%" PRIu64 ")\n", __func__, blkno,
 -		    size / DEV_BSIZE, sc->sc_size);
 +		    "p_size (%" PRIu64 ")\n", __func__, blkno,
 +		    size / DEV_BSIZE, p_size);
  		rv = EINVAL;
  		goto out;
  	}
  
  	bdev = bdevsw_lookup(sc->sc_pdev);
 -	rv = (*bdev->d_dump)(sc->sc_pdev, blkno + sc->sc_offset, va, size);
 +	rv = (*bdev->d_dump)(sc->sc_pdev, blkno + p_offset, va, size);
  
  out:
  	mutex_exit(&sc->sc_parent->dk_rawlock);
 


Home | Main Index | Thread Index | Old Index