Each LBA has one of these three LBP(logical block provisioning) states:
- LBP1: Mapped.
- LBP2: Deallocated. (unmapped)
- LBP3: Anchored. (unmapped)
The LBP2: Deallocated is mandatory for thin provisioned logical unit.
The deallocated
means neither the mapping resource nor LBA to physical
block(s) relationship is allocated.
The anchored
means the LBA mapping resources is associated while LBA to
physical block(s) relationship is uncertain.
There are two provisioning type:
-
Resource provisioned:
PROVISIONING TYPE 001b
of VPD0x82
.The device server shall able to all LBAs reported in the
RETURNED LOGICAL BLOCK ADDRESS
field of theREAD CAPACITY (10)
.This is often used by SSD where SSD firmware need to know which block/sector is not used.
But why SSD firmware need to know unused block/sector?
In short, SSD firmware don't have to read original data on overwrite action from group page if all blocks in that page is marked as unused.
Detail from Wikipedia:
-
Thin provisioned:
PROVISIONING TYPE 010b
of VPD0x82
.The device server can indicate a larger capacity in the
RETURNED LOGICAL BLOCK ADDRESS
field of theREAD CAPACITY (10)
then amiable LBAs.Often used in SAN for saving unused capacity -- over booking but not used.
The Provisioning type
could be checked via command:
$ sudo sg_vpd --page=0xb2 /dev/sda
Logical block provisioning VPD page (SBC):
Unmap command supported (LBPU): 0
Write same (16) with unmap bit supported (LBWS): 1
Write same (10) with unmap bit supported (LBWS10): 0
Logical block provisioning read zeros (LBPRZ): 0
Anchored LBAs supported (ANC_SUP): 0
Threshold exponent: 0
Descriptor present (DP): 0
Minimum percentage: 0
Provisioning type: 0
Threshold percentage: 0
To do unmap operation, device server shall support at least one of the following unmap mechanisms:
-
The UNMAP 0x42 command.
-
The UNMAP bit in the
WRITE SAME (10)
0x41 command orWRITE SAME (16)
0x93 command orWRITE SAME (32)
0x7f command.
The kernel read the Logical block provisioning(LBP)
VPD 0xb2 page and
Block limits(BL)
VPD 0xb0 page to find out which unmap mechanism should be
used.
-
If LBP VPD is not supported:
- Use UNMAP command if BL VPD says
MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
bigger than 1. - Use Write same 16 command otherwise.
- Use UNMAP command if BL VPD says
-
If LBP VPD is supported:
- Use
UNMAP
0x42 command if LBP VPD saysLBUP
is 1. - Use
WRITE SAME (16)
0x93 command if LBP VPD saysLBPWS
is 1. - Use
WRITE SAME (10)
0x41 command if LBP VPD saysLBPWS10
is 1. - Disable unmap support otherwise.
- Use
Linux kernel related codes:
The function sd_read_block_limits()
in driver/scsi/sd.c
is called every
time a new scsi disk found: (linux kernel code version: v4.14.13)
if (!sdkp->lbpvpd) { /* LBP VPD page not provided */
if (sdkp->max_unmap_blocks)
sd_config_discard(sdkp, SD_LBP_UNMAP);
else
sd_config_discard(sdkp, SD_LBP_WS16);
} else { /* LBP VPD page tells us what to use */
if (sdkp->lbpu && sdkp->max_unmap_blocks)
sd_config_discard(sdkp, SD_LBP_UNMAP);
else if (sdkp->lbpws)
sd_config_discard(sdkp, SD_LBP_WS16);
else if (sdkp->lbpws10)
sd_config_discard(sdkp, SD_LBP_WS10);
else
sd_config_discard(sdkp, SD_LBP_DISABLE);
}
The write same 32 is not supported by linux by v4.14.13 yet.
From userspace, you may check the provisioning mode via command:
$ for x in /sys/class/scsi_disk/* ; do echo $x; cat $x/provisioning_mode; done
/sys/class/scsi_disk/0:0:0:0
writesame_16
/sys/class/scsi_disk/4:0:0:0
full
To query LBP VPD page:
$ sudo sg_vpd --page=lbpv /dev/sda
Logical block provisioning VPD page (SBC):
Unmap command supported (LBPU): 0
Write same (16) with unmap bit supported (LBWS): 1
Write same (10) with unmap bit supported (LBWS10): 0
Logical block provisioning read zeros (LBPRZ): 0
Anchored LBAs supported (ANC_SUP): 0
Threshold exponent: 0
Descriptor present (DP): 0
Minimum percentage: 0
Provisioning type: 0
Threshold percentage: 0
To query BL VPD page:
$ sudo sg_vpd --page=bl /dev/sda
Block limits VPD page (SBC):
Write same non-zero (WSNZ): 0
Maximum compare and write length: 0 blocks
Optimal transfer length granularity: 1 blocks
Maximum transfer length: 0 blocks
Optimal transfer length: 0 blocks
Maximum prefetch length: 0 blocks
Maximum unmap LBA count: 0
Maximum unmap block descriptor count: 0
Optimal unmap granularity: 1
Unmap granularity alignment valid: 0
Unmap granularity alignment: 0
Maximum write same length: 0x3fffc0 blocks
Maximum atomic transfer length: 0
Atomic alignment: 0
Atomic transfer length granularity: 0
Maximum atomic transfer length with atomic boundary: 0
Maximum atomic boundary size: 0
To test UNMAP command, try sg_umap
.
To test WRITE SAME 10 or 16 or 32, try sg_write_same
.
Thanks for documenting this!
Note that the linux scsi maintainer is working on improving the logic used to set provisioning_mode in the kernel here: https://git.kernel.org/pub/scm/linux/kernel/git/mkp/linux.git/log/?h=5.18/discovery