# Practical Enhancement of User Experience in NVMe SSDs
## 3 Redesign of the Multi-Queue Block I/O Layer to Improve User Experience
In the original kernel (Figure 2), an I/O request issued by T\({}_{\text{U}}\) should wait until all I/O requests pending in the SWQ, HWQ, and SQ are processed. On the other hand, in our proposed scheme, the I/O request does not need to wait in SWQ\({}_{2}^{\text{NU}}\), as it uses SWQ\({}_{2}^{\text{U}}\) dedicated for user-centric tasks. In addition, unlike the original kernel, it is migrated to HWQ\({}_{1}\) and SQ\({}_{1}\) instead of HWQ\({}_{2}\) and SQ\({}_{2}\) as SQ\({}_{1}\) has the least number of pending I/O requests. Consequently, the I/O request can be processed swiftly, compared to other I/O requests. Figure 2: Traditional I/O processing for user-centric task (T\({}_{\text{U}}\)) and non-user-centric task (T\({}_{\text{NU}}\)). As our scheme basically tries to process I/O requests issued by user-oriented tasks first, there will be concerns that I/O requests issued by non-user-oriented tasks might suffer from starvation if the SSD is heavily loaded. I/O requests from a user-centric task find and go to the HWQ and SQ with the shortest queue length each time, so I/O requests from non-user-centric tasks can go to other queues instead. In addition, as all SQs are dispatched in a round-robin or weighted round-robin way, pending I/O requests from non-user-centric tasks can be processed sometime. In summary, when the SSD drive is overburdened, especially, even if the user-centric task issues the I/O requests infinitely, the I/O requests issued by non-user-centric tasks may wait for a long time, but there would be no infinite waiting situation. Details of the operations in our modified multi-queue block I/O layer are shown in Figure 4. After an I/O request from task running on n-th CPU reaches the block I/O layer, a bio that is a data structure for describing a single I/O operation is changed to a new request (r\({}_{\text{n}}\)), or it is merged to already existing requests. The block I/O layer then determines whether r\({}_{\text{n}}\) is requested by user-centric processes. If it is, an x-th SQ (SQ\({}_{\text{X}}\)) that contains the smallest number of pending I/O requests is selected as a target SQ to insert an NVMe I/O command for r\({}_{\text{n}}\) instead of the initially mapped SQ. This quick selection of the target SQ\({}_{\text{X}}\) is achieved because the current kernel determines SWQ, HWQ, and SQ for r\({}_{\text{n}}\) at this level by default. Subsequently, r\({}_{\text{n}}\) is enqueued to the HWQ\({}_{\text{X}}\) mapped to the SQ\({}_{\text{X}}\) via n-th SWQ for user-centric processes (SWQ\({}_{\text{n}}^{\text{U}}\)). After dequeuing from HWQ\({}_{\text{X}}\), in the level of the NVMe device driver, r\({}_{\text{n}}\) is changed as a format of the NVMe I/O command and enqueued to the SQ\({}_{\text{X}}\) if it is not full. The NVMe device driver finally notifies the insertion by updating a doorbell for the SQ\({}_{\text{X}}\). If r\({}_{\text{n}}\) is requested by non-user-centric processes, it is enqueued to SWQ\({}_{\text{n}}^{\text{NU}}\). Before enqueuing r\({}_{\text{n}}\) to the HWQ\({}_{\text{n}}\), it is confirmed whether there are pending I/O requests in the SWQ for the user-centric processes, SWQ\({}_{\text{n}}^{\text{U}}\). If they exist, the I/O requests located in SWQ\({}_{\text{n}}^{\text{U}}\) are first dequeued from the SWQ and enqueued to HWQ\({}_{\text{n}}\) to be processed before I/O requests from the non-user-centric processes. Owing to these various approaches, the modified block I/O layer can process I/O requests issued by the user-centric processes faster. Figure 3: Proposed I/O processing for user-centric task (T\({}_{\text{U}}\)) and non-user-centric task (T\({}_{\text{NU}}\)).