mirror of
https://github.com/SCST-project/scst.git
synced 2026-10-22 14:12:33 +00:00
dev_user_map_buf() takes the handler's buffer pages with
get_user_pages(FOLL_WRITE). With SCST_USER_MEM_REUSE_* the buffer stays
cached in the SGV pool and is reused by later commands, so SCST keeps
these page references for a long time.
A page reference does not keep the handler and SCST on the same page
across fork(). After the handler forks, its private pages are shared
copy-on-write, and the handler's next write to a cached buffer moves the
handler to a new copy while SCST keeps using the old page. SCST then
returns stale data to the initiator. For READ CAPACITY it also takes the
stale bytes as the block length and changes the device geometry, for
example:
1 << 30 != 1145132097
scst_user: ...: Changed block shift from 12 into 30 / 30
Any fork() in the handler triggers this, including a crash reporter that
clones a minidump writer without CLONE_VM, system() and popen().
Pin the pages with FOLL_LONGTERM instead. Since Linux 5.9 (commit
70e806e4e645, "mm: Do early cow for pinned pages during fork() for
ptes"), fork() gives the child a copy of a pinned anonymous page, so the
handler and SCST keep sharing the same page. pin_user_pages() itself is
older, but before 5.9 fork() write-protects pinned pages like any other,
so pinning alone does not help there. Release them with
unpin_user_pages(), marking them dirty with SetPageDirty() as before.
unpin_user_pages_dirty_lock() is not usable here: it takes the page
lock, and on_free_cmd() can release an uncached buffer in atomic
context. Use the pin from Linux 5.9; older kernels, including
distribution kernels based on them, keep the existing code.
doc/scst_user_spec.sgml so far required handlers that fork() to mark
their data buffers MADV_DONTFORK. With the pin that is only needed on
kernels older than 5.9, and for private HugeTLB buffers on kernels older
than 5.12: fork() copies pinned HugeTLB pages only since commit
4eae4efa2c29 ("hugetlb: do early cow when page pinned on src mm"), which
5.10.y and 5.11.y do not have. Update that note and the source comment
accordingly. Also document that data
buffers should be anonymous or shared memory: since Linux 6.5 the kernel
refuses a long term writable pin of a MAP_SHARED mapping of a regular
file on a file system with writeback, and a command using such a buffer
then fails with INTERNAL TARGET FAILURE sense. Such a buffer was not
safe with get_user_pages() either, because SCST could write to it while
the file system wrote it back.
Add scst-USER-buffers, which maps a KUnit-owned user buffer with
dev_user_map_buf() and releases it with dev_user_unmap_buf() with
interrupts disabled, checking that the pages are unpinned and marked
dirty only after a write.