feeling_lonely
feeling_lonely

Reputation: 6883

Proper way to lock the queue in a block device driver while serving requests

I am trying to write a device driver for a network attached hard disk. and I am wondering what is the proper way to lock/unlock the requests queue and where?

To clarify:

  1. I created a queue using the blk_init_queue and passed to that function the request handler function and a lock (i.e. semaphore) that I created.
  2. My request handler function looks like this:

    struct request *req;
    int ret;
    while ((req = blk_fetch_request(q)) != NULL) {
         ret = rb_transfer(req);
    }
    
  3. My rb_transfer starts a new kernel thread to handle the request.

  4. Once the request is handled and the data transfer is done, blk_end_request_cur is called on that request.

Now, my question is how to protect access to the request queue in the loop above? and in the driver in general?

I tried something like this:

struct request *req;
int ret;
while ((req = blk_fetch_request(q)) != NULL) {
     spin_lock(&lock);
     ret = rb_transfer(req);
     spin_unlock(&lock);
}

But this failed and caused a kernel lock up.

Any other ideas?

Upvotes: 3

Views: 842

Answers (1)

Vivek S
Vivek S

Reputation: 1261

The request_fn that you pass to blk_init_queue is called by holding the spinlock passed as the second argument and interrupts disabled. Hence, you can safely assume that no parallel threads are running that are executing this request_fn. However, if you create a parallel thread that processes this request, then synchronizing access to the requests in those threads are entirely your responsibility.

The request_fn is called by __blk_run_queue_uncond which is inturn called by functions __blk_run_queue and blk_execute_rq_nowait . If you search for functions calling __blk_run_queue in the linux kernel, you can see that all of them do so by holding the q->queue_lock which is the spinlock passed to function blk_init_queue.

Upvotes: 3

Related Questions