Sebuah thread dapat mengakses page yang valid dan resident, tetapi tetap berhenti sebelum mengubah isinya. Dengan mode write-protect Linux userfaultfd, page yang terdaftar dapat ditandai sehingga write menghasilkan event page fault pada userfaultfd. Handler di userspace menerima event tersebut, menjalankan bookkeeping, melepas proteksi, lalu membiarkan thread yang tertahan melanjutkan eksekusi.

Mekanisme ini berada di antara permission page biasa dan accounting memori tingkat aplikasi. Page tetap menjadi bagian dari address space proses; kernel mengarahkan write fault ke protokol berbasis file descriptor, sehingga aplikasi tidak perlu membangun jalur kontrol serupa di atas mprotect() dan SIGSEGV.

Registration menentukan fault yang masuk ke protokol

Objek userfaultfd tidak otomatis mencegat aktivitas memori hanya karena descriptor telah dibuat. Userspace terlebih dahulu menegosiasikan API melalui UFFDIO_API, kemudian mendaftarkan rentang virtual memory dengan UFFDIO_REGISTER dan UFFDIO_REGISTER_MODE_WP.

Registration dan protection merupakan dua operasi terpisah. Registration menyatakan bahwa write-protect fault pada rentang tersebut menjadi bagian dari konteks userfaultfd ini. Setelah itu, UFFDIO_WRITEPROTECT dengan UFFDIO_WRITEPROTECT_MODE_WP mengaktifkan proteksi pada subrange page-aligned yang dipilih.

struct uffdio_writeprotect wp = {
    .range = {
        .start = (unsigned long)addr,
        .len = len,
    },
    .mode = UFFDIO_WRITEPROTECT_MODE_WP,
};

ioctl(uffd, UFFDIO_WRITEPROTECT, &wp);

Rentang yang diproteksi dapat lebih kecil daripada rentang yang didaftarkan. State dapat dikelola secara granular: satu descriptor dapat mengawasi mapping yang luas, sementara hanya page tertentu yang diaktifkan untuk intersepsi write pada suatu waktu.

Pesan fault menandai write yang terproteksi

Saat thread melakukan write ke page yang aktif diproteksi dalam mode synchronous write-protect, thread tersebut berhenti dan userfaultfd menjadi readable. Handler membaca struct uffd_msg. Untuk kelas fault ini, msg.arg.pagefault.flags memuat UFFD_PAGEFAULT_FLAG_WP; write-protect fault juga merepresentasikan akses write.

writer thread                 handler thread
     |                              |
     | store ke WP page             |
     v                              |
  blocked                           | read(uffd)
                                    v
                              WP fault message
                                    |
                              catat state page
                                    |
                              lepas WP
     |<-----------------------------+
     v
 store berlanjut

Event tersebut bukan salinan payload write. Event melaporkan akses yang mengalami fault beserta konteks alamatnya. Tindakan spesifik aplikasi, misalnya menandai bitmap migrasi atau mencatat transisi first-write, merupakan kebijakan handler.

Melepas proteksi menyelesaikan fault

Untuk synchronous write-protect fault, userspace menyelesaikan akses yang tertahan dengan memanggil UFFDIO_WRITEPROTECT lagi tanpa bit WP pada rentang yang relevan.

struct uffdio_writeprotect unprotect = {
    .range = {
        .start = page_start,
        .len = page_size,
    },
    .mode = 0,
};

ioctl(uffd, UFFDIO_WRITEPROTECT, &unprotect);

Secara default, pelepasan proteksi juga membangunkan thread yang menunggu fault pada rentang tersebut. UFFDIO_WRITEPROTECT_MODE_DONTWAKE dapat memisahkan perubahan permission dari wakeup ketika aplikasi perlu mengelompokkan beberapa transisi state.

Urutan ini merupakan properti utamanya: bookkeeping dapat dilakukan ketika write yang mengalami fault masih tertahan. Setelah proteksi dilepas, write berikutnya pada page tersebut berjalan normal sampai userspace mengaktifkan proteksi lagi.

Missing page dan protected page adalah state berbeda

Mode write-protect tidak menyatukan semua memory fault menjadi satu jenis event. Page dapat absent, present dan writable, atau present dan write-protected. Mode registration userfaultfd menangani bagian berbeda dari ruang state tersebut.

Sebuah rentang dapat didaftarkan dengan UFFDIO_REGISTER_MODE_MISSING sekaligus UFFDIO_REGISTER_MODE_WP. Dalam konfigurasi ini, missing-page fault tetap memerlukan population melalui operasi seperti UFFDIO_COPY atau UFFDIO_ZEROPAGE, sedangkan write-protect fault memerlukan transisi protection.

Perbedaan ini juga penting saat memasang page baru. UFFDIO_COPY_MODE_WP dapat mengisi missing page sambil mempertahankan mapping hasilnya dalam keadaan write-protected. Dengan begitu, tidak muncul celah saat page baru sudah writable tetapi tracking belum aktif.

Perilaku pada PTE yang belum populated memiliki detail tambahan bergantung pada tipe memori dan feature. Dokumentasi kernel saat ini mencantumkan UFFD_FEATURE_WP_UNPOPULATED untuk tracking write-protect pada anonymous memory yang belum populated. Kode yang bergantung pada perilaku tersebut harus menegosiasikan feature, bukan menganggap dukungan WP dasar sudah mencakupnya.

Synchronous WP membentuk titik ordering eksplisit

Dirty-page tracking kadang membutuhkan lebih dari dirty bit akhir. Komponen migrasi atau checkpointing dapat memerlukan titik yang tegas saat page berubah dari protected-and-accounted menjadi writable-after-accounting.

Synchronous userfaultfd WP menyediakan titik tersebut karena writer tidak dapat menyelesaikan protected store sebelum userspace menyelesaikan fault. Handler dapat mengaitkan page dengan epoch, bitmap, atau state transfer miliknya sebelum write dilepas.

Jaminan ini memiliki biaya. Setiap first write yang dicegat melibatkan page fault, event userspace, scheduling handler, dan operasi resolution. Mekanisme ini merupakan control primitive, bukan klaim bahwa mencegat setiap write berbiaya rendah.

Linux juga menyediakan asynchronous userfaultfd WP ketika UFFD_FEATURE_WP_ASYNC tersedia dan diaktifkan. Dalam mode tersebut, kernel secara otomatis menyelesaikan protected write dan tidak mengirim synchronous fault message. Varian ini menyediakan observasi dirty state dengan kontrak koordinasi berbeda; ia tidak menyediakan titik berhenti userspace yang sama sebelum write berjalan.

Delivery melalui file descriptor mengubah batas integrasi

Channel event berupa file descriptor, sehingga memory manager dapat mengintegrasikan write fault dengan poll() atau epoll() alih-alih menyalurkannya melalui process signal handler. Karakteristik ini sesuai dengan software yang sudah memakai event loop atau fault-handler thread khusus.

Namun, memory fault tidak berubah menjadi byte-stream I/O biasa. Descriptor membawa protokol yang ditentukan kernel, sedangkan memory mapping tetap mengikuti aturan virtual memory, feature negotiation, page alignment, dan lifetime registration. Aplikasi juga harus mengoordinasikan unregistration, perubahan mapping, dan penghentian handler agar tidak ada thread tertinggal menunggu fault yang tidak akan diselesaikan.

Batas arsitekturalnya sempit tetapi konkret: write protection userfaultfd mengubah write memori terpilih menjadi synchronization event yang dikendalikan dari userspace. Page-table protection menghentikan akses, descriptor melaporkannya, dan ioctl melepasnya. Urutan ini memberi software pengelola memori tempat untuk memasang transisi state tanpa mengganti address space proses atau memperlakukan setiap write sebagai exception berbasis signal.