Bagikan melalui


Menerapkan Rutinitas IoCompletion

Pada entri, rutinitas IoCompletion menerima penunjuk Konteks . Ketika rutin pengiriman memanggil IoSetCompletionRoutine, dapat memasok penunjuk Konteks. Penunjuk ini dapat mereferensikan informasi konteks apa pun yang ditentukan oleh driver yang diperlukan oleh rutinitas IoCompletion untuk memproses IRP. Area konteks tidak boleh dipaginasi karena rutinitas IoCompletion dapat dipanggil di IRQL = DISPATCH_LEVEL.

Pertimbangkan panduan implementasi berikut untuk rutinitas IoCompletion:

  • Rutinitas IoCompletion dapat memeriksa blok status I/O IRP untuk menentukan hasil operasi I/O.

  • Jika rutinitas pengiriman mengalokasikan IRP input dengan menggunakan IoAllocateIrp atau IoBuildAsynchronousFsdRequest, rutinitas IoCompletion harus memanggil IoFreeIrp untuk merilis IRP tersebut, sebaiknya sebelum menyelesaikan IRP asli.

    • Rutinitas IoCompletion harus melepaskan sumber daya per-IRP yang dialokasikan oleh rutinitas pengiriman untuk IRP yang dialokasikan oleh driver, sebaiknya sebelum membebaskan IRP yang bersangkutan.

      Misalnya, jika pengiriman rutin mengalokasikan MDL dengan IoAllocateMdl dan memanggil IoBuildPartialMdl untuk IRP transfer parsial yang dialokasikannya, rutinitas IoCompletion harus merilis MDL dengan IoFreeMdl. Jika mengalokasikan sumber daya untuk mempertahankan status tentang IRP asli, sumber daya tersebut harus bebas, sebaiknya sebelum memanggil IoCompleteRequest dengan IRP asli dan pasti sebelum mengembalikan kontrol.

      Secara umum, sebelum membebaskan atau menyelesaikan IRP, rutinitas IoCompletion harus membebaskan sumber daya per-IRP yang dialokasikan oleh rutinitas pengiriman. Jika tidak, driver harus mempertahankan informasi tentang sumber daya yang akan dibebaskan sebelum rutinitas IoCompletion-nya mengembalikan kontrol setelah menyelesaikan permintaan asli.

    • Jika rutinitas IoCompletion tidak dapat menyelesaikan IRP asli dengan STATUS_SUCCESS, itu harus mengatur blok status I/O di IRP asli ke nilai yang dikembalikan dalam IRP yang dialokasikan driver yang menyebabkan rutinitas IoCompletion gagal permintaan asli.

    • Jika rutinitas IoCompletion menyelesaikan permintaan asli dengan STATUS_PENDING, IoMarkIrpPending harus memanggil IoMarkIrpPending dengan IRP asli sebelum memanggil IoCompleteRequest.

    • Jika rutinitas IoCompletion harus memberikan kesalahan pada IRP asli dengan STATUS_XXX, itu dapat mencatat kesalahan. Namun, ini adalah tanggung jawab driver perangkat yang mendasar untuk mencatat kesalahan I/O perangkat apa pun yang terjadi, sehingga rutinitas IoCompletion biasanya tidak mencatat kesalahan.

    • Ketika rutin IoCompletion memproses dan membebaskan IRP yang dialokasikan oleh driver, ia harus mengembalikan kontrol dengan STATUS_MORE_PROCESSING_REQUIRED.

      Mengembalikan STATUS_MORE_PROCESSING_REQUIRED dari rutin IoCompletion menunda pemrosesan penyelesaian oleh manajer I/O untuk IRP yang dialokasikan dan dibebaskan oleh driver. Panggilan kedua ke IoCompleteRequest membuat manajer I/O melanjutkan pemanggilan rutin penyelesaian IRP, dimulai dengan rutinitas penyelesaian yang langsung berada di atas rutinitas yang mengembalikan STATUS_MORE_PROCESSING_REQUIRED.

  • Jika rutinitas IoCompletion menggunakan kembali IRP yang masuk untuk mengirim satu atau beberapa permintaan ke driver-driver yang lebih rendah, atau jika rutin mencoba kembali operasi yang gagal, maka itu harus memperbarui konteks apa pun yang dipertahankan oleh rutinitas IoCompletion tentang setiap penggunaan kembali atau upaya mencoba lagi IRP. Selanjutnya, dapat mengatur ulang lokasi tumpukan I/O driver yang berada di tingkat lebih rendah, memanggil IoSetCompletionRoutine dengan titik masuknya sendiri, dan memanggil IoCallDriver untuk IRP.

    • Rutinitas IoCompletion tidak boleh memanggil IoMarkIrpPending di setiap penggunaan kembali atau coba lagi IRP.

      Rutinitas pengiriman sudah menandai IRP asli sebagai tertunda. Hingga semua driver dalam rantai menyelesaikan IRP asli dengan IoCompleteRequest, itu tetap tertunda.

    • Sebelum mencoba kembali permintaan, rutinitas IoCompletion harus mengatur ulang blok status I/O dengan STATUS_SUCCESS untuk Status dan nol untuk Informasi, mungkin setelah menyimpan informasi kesalahan yang dikembalikan.

      Untuk setiap pengulangan, rutinitas IoCompletion biasanya mengurangi jumlah pengulangan yang diatur oleh rutinitas pengiriman. Biasanya, rutinitas IoCompletion harus memanggil IoCompleteRequest untuk menggagalkan IRP ketika beberapa percobaan ulang dalam jumlah terbatas gagal.

    • Rutinitas IoCompletion harus mengembalikan STATUS_MORE_PROCESSING_REQUIRED setelah memanggil IoSetCompletionRoutine dan IoCallDriver dengan IRP yang sedang digunakan kembali atau dicoba ulang.

      Mengembalikan STATUS_MORE_PROCESSING_REQUIRED dari rutin IoCompletion mencegah pemrosesan penyelesaian oleh manajer I/O terhadap IRP yang digunakan kembali atau dicoba kembali.

    • Jika rutinitas IoCompletion tidak dapat menyelesaikan IRP asli dengan STATUS_SUCCESS, maka rutinitas tersebut harus membiarkan blok status operasi I/O seperti yang dikembalikan oleh driver yang lebih rendah untuk operasi penggunaan kembali atau pengulangan yang menyebabkan rutinitas IoCompletion menggagalkan IRP.

    • Jika rutinitas IoCompletion akan menyelesaikan permintaan asli dengan STATUS_PENDING, ia harus memanggil IoMarkIrpPending dengan IRP asli sebelum memanggil IoCompleteRequest.

    • Jika rutinitas IoCompletion harus memberikan kesalahan pada IRP asli dengan STATUS_XXX, itu dapat mencatat kesalahan. Namun, ini adalah tanggung jawab driver perangkat yang mendasar untuk mencatat kesalahan I/O perangkat apa pun yang terjadi, sehingga rutinitas IoCompletion biasanya tidak mencatat kesalahan.

  • Setiap driver yang mengatur rutinitas IoCompletion dalam IRP dan kemudian meneruskan IRP ke driver bawah harus mengecek flag IRP->PendingReturned dalam rutinitas IoCompletion. Jika flag diatur, rutinitas IoCompletion harus memanggil IoMarkIrpPending dengan IRP. Namun, driver yang melewati IRP dan kemudian menunggu pada suatu peristiwa tidak boleh menandai IRP yang tertunda. Sebaliknya, rutinitas IoCompletion-nya harus memberi sinyal peristiwa dan mengembalikan STATUS_MORE_PROCESSING_REQUIRED.

  • Rutinitas IoCompletion harus merilis sumber daya apa pun yang dialokasikan oleh rutinitas pengiriman untuk memproses IRP asli, sebaiknya sebelum rutinitas IoCompletion memanggil IoCompleteRequest dengan IRP asli dan pasti sebelum rutinitas IoCompletion mengembalikan kontrol setelah menyelesaikan IRP asli.

Jika ada driver tingkat yang lebih tinggi yang mengatur rutinitas IoCompletion-nya di IRP asli, rutinitas IoCompletion driver tersebut tidak dipanggil sampai rutinitas IoCompletion dari semua driver tingkat bawah telah dipanggil.

Menyediakan Peningkatan Prioritas pada Panggilan ke IoCompleteRequest

Jika driver perangkat tingkat terendah dapat menyelesaikan IRP dalam rutinitas penanganannya, driver ini memanggil IoCompleteRequest dengan PriorityBoost IO_NO_INCREMENT. Tidak ada peningkatan prioritas run-time yang diperlukan karena driver dapat mengasumsikan bahwa pemohon asli tidak menunggu operasi I/O-nya selesai.

Jika tidak, driver tingkat terendah menyediakan nilai yang ditentukan sistem dan sesuai jenis perangkat yang meningkatkan prioritas run-time pemohon untuk mengimbangi waktu yang ditunggu pemohon atas permintaan I/O perangkat tersebut. Lihat Wdm.h atau Ntddk.h untuk nilai peningkatan.

Driver tingkat yang lebih tinggi menerapkan PriorityBoost yang sama dengan driver perangkat yang mendasar masing-masing saat mereka memanggil IoCompleteRequest.

Efek Panggilan IoCompleteRequest

Ketika driver memanggil IoCompleteRequest, manajer I/O mengisi lokasi tumpukan I/O driver tersebut dengan nol sebelum memanggil driver tingkat lebih tinggi berikutnya, jika ada, yang menyiapkan rutinitas IoCompletion yang akan dipanggil untuk IRP.

Rutinitas IoCompletion driver tingkat lebih tinggi hanya dapat memeriksa blok status I/O IRP untuk menentukan bagaimana semua driver yang lebih rendah menangani permintaan.

Pemanggil IoCompleteRequest tidak boleh mencoba mengakses IRP yang baru saja selesai. Upaya seperti itu adalah kesalahan pemrograman yang menyebabkan crash sistem.