Skip to contentSkip to conversation

drivers: staging: most: Locking question

DISCUSSION mhornung.linux at gmail.com 2 participants 2 messages Jul 18, 2016

lore
Share & tools
lore
#0 lore raw

Hello,

I have some questions about the locking techniques used inside file drivers/staging/most/hdm-usb/hdm_usb.c.

The one and only call to function free_anchored_buffers is locked by a Mutex:

----------------------------------------------------------------------------

    	...
        mutex_lock(&mdev->io_mutex);
	free_anchored_buffers(mdev, channel);
	if (mdev->padding_active[channel])
		mdev->padding_active[channel] = false;

        if (mdev->conf[channel].data_type == MOST_CH_ASYNC) {
	        del_timer_sync(&mdev->link_stat_timer);
		cancel_work_sync(&mdev->poll_work_obj);
	}
	mutex_unlock(&mdev->io_mutex);
	...						

----------------------------------------------------------------------------

Then, inside function free_anchored_buffers, they use a (from my point of view) somewhat complex spinlock variant:

----------------------------------------------------------------------------
static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel)

{
	struct mbo *mbo;
	struct buf_anchor *anchor, *tmp;
	unsigned long flags;

	spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags);
	list_for_each_entry_safe(anchor, tmp, &mdev->anchor_list[channel],
				 list) {
		struct urb *urb = anchor->urb;

		spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags);
		if (likely(urb)) {
			mbo = urb->context;
			if (!irqs_disabled()) {
				usb_kill_urb(urb);
			} else {
				usb_unlink_urb(urb);
				wait_for_completion(&anchor->urb_compl);
			}
			if ((mbo) && (mbo->complete)) {
				mbo->status = MBO_E_CLOSE;
				mbo->processed_length = 0;
				mbo->complete(mbo);
			}
			usb_free_urb(urb);
		}
		spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags);
		list_del(&anchor->list);
		cancel_work_sync(&anchor->clear_work_obj);
		kfree(anchor);
	}
	spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags);
}

----------------------------------------------------------------------------

To my questions:

#1: What is the intention of locking a whole function with a Mutex and then
using spinlocks inside the function? Wouldn't it be sufficient to use one locking technique?
#2: Why is the spinlock not just locking the whole list_for_each_entry part or

    just the list_del(&anchor->list)?

Thank you very much in advance.

With best regards

Michael

#1 lore raw
Quoted 4 lines · mhornung.linux at gmail.com

Hello,

I have some questions about the locking techniques used inside file drivers/staging/most/hdm-usb/hdm_usb.c.

Eeek, never use anything from drivers/staging/ as a good example of anything. Please, that code is in staging for a good reason, only worry about code outside of drivers/staging/ for good examples.

Quoted 58 lines

The one and only call to function free_anchored_buffers is locked by a Mutex:

----------------------------------------------------------------------------

    	...
        mutex_lock(&mdev->io_mutex);
	free_anchored_buffers(mdev, channel);
	if (mdev->padding_active[channel])
		mdev->padding_active[channel] = false;

        if (mdev->conf[channel].data_type == MOST_CH_ASYNC) {
	        del_timer_sync(&mdev->link_stat_timer);
		cancel_work_sync(&mdev->poll_work_obj);
	}
	mutex_unlock(&mdev->io_mutex);
	...						

----------------------------------------------------------------------------

Then, inside function free_anchored_buffers, they use a (from my point of view) somewhat complex spinlock variant:

----------------------------------------------------------------------------
static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel)

{
	struct mbo *mbo;
	struct buf_anchor *anchor, *tmp;
	unsigned long flags;

	spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags);
	list_for_each_entry_safe(anchor, tmp, &mdev->anchor_list[channel],
				 list) {
		struct urb *urb = anchor->urb;

		spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags);
		if (likely(urb)) {
			mbo = urb->context;
			if (!irqs_disabled()) {
				usb_kill_urb(urb);
			} else {
				usb_unlink_urb(urb);
				wait_for_completion(&anchor->urb_compl);
			}
			if ((mbo) && (mbo->complete)) {
				mbo->status = MBO_E_CLOSE;
				mbo->processed_length = 0;
				mbo->complete(mbo);
			}
			usb_free_urb(urb);
		}
		spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags);
		list_del(&anchor->list);
		cancel_work_sync(&anchor->clear_work_obj);
		kfree(anchor);
	}
	spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags);
}

----------------------------------------------------------------------------

Quoted 7 lines

To my questions:

#1: What is the intention of locking a whole function with a Mutex and then
using spinlocks inside the function? Wouldn't it be sufficient to use one locking technique?
#2: Why is the spinlock not just locking the whole list_for_each_entry part or

    just the list_del(&anchor->list)?

Why not ask the authors and maintainers of these files? They would be the best to answer them, don't you think?

thanks,

greg k-h