Fix concurrency bug when writing non-aligned data.
Currently, clients attempting to concurrently write two (non-overlapping) buffers may end-up overwriting each others changes if one of the buffers is non-aligned. This commit fixes the issue by always locking objects for mutation.
It also removes an accidental double-fetching of the object during read-modify-write.
Merge request reports
Activity
@ebblake What do you think? See also thread on the mailing list.
I read the mailing list thread first, but agree that we have a potentially nasty data corruption bug in our current locking mechanism in the blocksize filter. I'm less familiar with the S3 plugin to know if it is suffering from the same problem, but it looks like we need to consider some form of rwlock solution (where we allow parallel aligned operations under the rdlock, but exclusive unaligned operations under the wrlock, regardless of whether the operation is pread or pwrite, and where we then need to worry about starvation issues if we favor readers or favor writers).
I am a bit confused. The current form of the plugin causes data corruption. Not in theory, but in practice. When used with the Kernel's NBD client this happens within minutes of using the filesystem. The patch adds the missing locking procedures. Can you provide some more details on what you would like to consider in more depth?
Do you think there may not be an issue that needs fixing? Or that the patch does not fix the issue? Or that the patch has some other unintended effects?
247 252 def pwrite_multi(s3, buf, offset, flags): 248 253 "Write data to objects" 249 254 250 to_write = len(buf) 251 252 255 # memoryviews can be sliced without copying the data 253 256 if not isinstance(buf, memoryview): 254 257 buf = memoryview(buf) 255 258 256 (blockno1, block_offset) = divmod(offset, obj_size) 257 if block_offset: 259 (blockno1, block_offset1) = divmod(offset, obj_size) - Resolved by Nikolaus Rath
- Resolved by Nikolaus Rath
- Resolved by Nikolaus Rath
- Resolved by Nikolaus Rath
We've previously done all of this in a more straightforward way, by considering the unaligned head, aligned main, and unaligned tail of requests. An example would be this code in the cache filter. It's simpler, although it uses a single lock rather than per-block locks.
Yes, but I think it's not sufficiently simpler to justify the loss of parallelism. Do you see this differently?
It would get rid of the
MultiLock
class (so less code), but if we consider this an abstraction that we can assume to work, then in the actual plugin code it just replaceswith obj_lock(key)
withwith global_lock
. I do not think this is a big win.
added 21 commits
-
c54b4d1d...b2612d2c - 20 commits from branch
nbdkit:master
- 04fcadd6 - Fix concurrency bug when writing non-aligned data.
-
c54b4d1d...b2612d2c - 20 commits from branch
added 13 commits
-
04fcadd6...83f1b300 - 12 commits from branch
nbdkit:master
- f1ec9409 - Fix concurrency bug when writing non-aligned data.
-
04fcadd6...83f1b300 - 12 commits from branch
Thanks, this is upstream as commit 97739efe.
Edited by Richard W.M. Jones