问题
Turns out I misinterpreted wear leveling, I initially thought by accessing the drive as RAW I would lose this feature but as its a feature on the controller this explains why i am hitting millions of writes to the 'logical sector' I am testing
I am writing an application where I will be utilizing a RAW disk partition like a circular buffer, ie no filesystem.
I need somewhere to keep track of my read/write buffer heads that is persistent across boots, I was thinking i can create another partition to store these 2 pointers.
But I am worried about how many times I can write to a sector in the devices SOLID state drive before the sector dies so I wrote the code below to hammer a single sector and see how quickly it fails.
- create random block (512 bytes)
- write to sector 0 using pwrite
- read block from sector 0 using pread
- compare each byte
- exit when difference found.
but it has been running for millions of sector writes now!!
I would have expected it to fail somewhere standard like between 10,000-100,000 times?
I'm using pread/pwrite as below with a random buffer each loop and a comparison of both buffers afterwards.
void WriteBlock(const char* device, unsigned char* dataBlock, size_t sector, int size)
{
int fd = open(device, O_WRONLY);
if(fd <= 0)
{
std::cout << "error opening " << device << " '" << strerror(errno) << "'\r\n";
exit(EXIT_FAILURE);
}
ssize_t r = pwrite(fd, dataBlock, size, sector*SECTOR_SIZE);
if (r<=0 || r<size)
{
std::cout << "failure writing '" << strerror(errno) << "'\r\n";
exit(EXIT_FAILURE);
}
close(fd);
}
void ReadBlock(const char* device, unsigned char* dataBlock, size_t sector, int size)
{
int fd = open(device, O_RDONLY);
if(fd <= 0)
{
std::cout << "error opening " << device << "\r\n";
exit(EXIT_FAILURE);
}
ssize_t r = pread(fd, dataBlock, size, sector*SECTOR_SIZE);
if (r<=0 || r<size)
{
std::cout << "failure writing '" << strerror(errno) << "'\r\n";
exit(EXIT_FAILURE);
}
close(fd);
}
the code just keeps on running with the write buffer equal to the read buffer every time.
FYI i'm not comparing the write buffer to itself! if i hard code a value into the read buffer it catches this and interprets as a failure.
回答1:
I would have expected it to fail somewhere standard like between 10,000-100,000 times?
Most solid state drives have wear levelling. What this means is that when you write to logical block 0 the device says "Hey, the old data in logical block 0 is getting overwritten, so I can just pretend a completely different physical block is now logical block 0". By continually writing to the same logical block, you can be writing to many completely different physical blocks.
To defeat wear leveling (and actually write to the same physical block) you have to convince the device that all other blocks are in use. This isn't possible because there's spare capacity. For example, for a 1 TiB device you can fill all 1 TiB of logical blocks with data (without doing any "trim", etc), but there might be an extra 512 GiB of spare space and your writes to the same logical block will be spread across that 512 GiB of spare space; and by the time you actually see an error it may mean that every block in that 512 GiB of spare space has failed (and not just one block).
If you know how much spare space there actually is, then you might be able to do calculations based on that - e.g. if there's 1 thousand spare blocks and you do 1 billion writes before seeing an error, then you might be able to say "1 billion writes / 1 thousand blocks = 1 million writes to each physical block".
Now, imagine you're a manufacturer and you've got a 1000 GiB drive. You decide to sell it as a consumer drive (with the assumption that the drive will be mostly empty and wear leveling will be able to work well) and that you can say it's a 900 GiB drive (with 100 GiB of spare blocks) that will fail after 10000 writes. Then you decide to also sell the exact same drive as an enterprise drive (with the assumption that the drive will probably be full and wear leveling won't be so effective) and that you can say it's a 900 GiB drive (with 100 GiB of spare blocks) that will fail after 2000 writes. Then you decide you can increase the amount of spare space, and also sell the "mostly the same" drive as an 500 GiB enterprise drive (with 500 GiB of spare blocks) that will fail after 20000 writes.
Next; imagine that you test 1000 identical drives (with the software you're writing) and measure "20000 writes before failure on average, under the specific conditions used for testing (e.g. with the rest of the logical blocks all free/empty)". This information is mostly useless - if someone uses the same drive under different conditions (e.g. with less logical blocks free/empty) then it'll fail sooner (or later) than you said it would.
For a (potentially better) alternative; you might be able to use information obtained from "S.M.A.R.T." (see https://en.wikipedia.org/wiki/S.M.A.R.T. ). Unfortunately some of the most useful pieces of information you can get is manufacturer specific (e.g. Used Reserved Block Count Total, Unused Reserved Block Count Total), and some devices (USB flash) don't support it at all.
来源:https://stackoverflow.com/questions/54180391/im-testing-solid-state-write-failure-times-c-code-and-the-device-isnt-failin