From: "David C. Hansen" <haveblue@us.ibm.com>
To: Peter.Pregler@risc.uni-linz.ac.at
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH] broken locking in CPiA driver
Date: Mon, 10 Sep 2001 16:06:39 -0700 [thread overview]
Message-ID: <3B9D477F.CABAFD79@us.ibm.com> (raw)
This patch fixes a locking issue with the CPiA driver, and cleans up the
locking. There is a potential race condition in cpia_pp_detach(). The
REMOVE_FROM_LIST macro uses the BKL to provide protection for the
cam_list. However, the BKL is not held during the whole for loop, only
during the macro.
This patch does several things:
1. rename REMOVE_FROM_LIST and ADD_TO_LIST to cpia_remove_from_list and
cpia_add_to_list, respectively
2. make them "static inline" functions instead of #define macros. (take
a look at this, they probably should be functions)
3. add one static spinlock cam_list_lock_{pp|usb} for each of the pp
and usb drivers to replace BKL
4. do locking around all cam_list references to replace BKL locking
from the macros
5. fix race condition
6. initialize cam_list to NULL in pp driver, just like the usb driver.
--
David C. Hansen
haveblue@us.ibm.com
IBM LTC Base/OS Group
(503)578-4080
--- ../clean/linux/drivers/media/video/cpia_pp.c Fri Mar 2 11:12:10
2001
+++ linux/drivers/media/video/cpia_pp.c Mon Sep 10 16:02:42 2001
@@ -158,6 +158,7 @@
};
static struct cam_data *cam_list;
+static spinlock_t cam_list_lock_pp;
#ifdef _CPIA_DEBUG_
#define DEB_PORT(port) { \
@@ -582,7 +583,9 @@
kfree(cam);
return -ENXIO;
}
- ADD_TO_LIST(cam_list, cpia);
+ spin_lock( &cam_list_lock_pp );
+ cpia_add_to_list(cam_list, cpia);
+ spin_unlock( &cam_list_lock_pp );
return 0;
}
@@ -591,11 +594,12 @@
{
struct cam_data *cpia;
+ spin_lock( &cam_list_lock_pp );
for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
struct pp_cam_entry *cam = cpia->lowlevel_data;
if (cam && cam->port->number == port->number) {
- REMOVE_FROM_LIST(cpia);
-
+ cpia_remove_from_list(cpia);
+ spin_unlock( &cam_list_lock_pp );
cpia_unregister_camera(cpia);
if(cam->open_count > 0) {
@@ -606,9 +610,10 @@
kfree(cam);
cpia->lowlevel_data = NULL;
- break;
+ return;
}
}
+ spin_unlock( &cam_list_lock_pp );
}
static void cpia_pp_attach (struct parport *port)
@@ -660,6 +665,9 @@
LOG ("unable to register with parport\n");
return -EIO;
}
+
+ cam_list = NULL;
+ spinlock_init( cam_list_lock_pp );
return 0;
}
--- ../clean/linux/drivers/media/video/cpia_usb.c Mon Feb 19 10:18:18
2001
+++ linux/drivers/media/video/cpia_usb.c Mon Sep 10 15:19:19 2001
@@ -104,6 +104,7 @@
};
static struct cam_data *cam_list;
+static spinlock_t cam_list_lock_usb;
static void cpia_usb_complete(struct urb *urb)
{
@@ -536,7 +537,9 @@
goto fail_all;
}
- ADD_TO_LIST(cam_list, cam);
+ spin_lock( &cam_list_lock_usb );
+ cpia_add_to_list(cam_list, cam);
+ spin_unlock( &cam_list_lock_usb );
return cam;
@@ -579,8 +582,10 @@
struct cam_data *cam = (struct cam_data *) ptr;
struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data;
- REMOVE_FROM_LIST(cam);
-
+ spin_lock( &cam_list_lock_usb );
+ cpia_remove_from_list(cam);
+ spin_unlock( &cam_list_lock_usb );
+
/* Don't even try to reset the altsetting if we're disconnected */
cpia_usb_free_resources(ucpia, 0);
@@ -620,7 +625,7 @@
static int __init usb_cpia_init(void)
{
cam_list = NULL;
-
+ spin_lock_init(&cam_list_lock_usb);
return usb_register(&cpia_driver);
}
--- ../clean/linux/drivers/media/video/cpia.h Fri Mar 2 11:12:10 2001
+++ linux/drivers/media/video/cpia.h Mon Sep 10 15:24:03 2001
@@ -393,27 +393,24 @@
(p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
(p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
-#define ADD_TO_LIST(l, drv) \
- {\
- lock_kernel();\
- (drv)->next = l;\
- (drv)->previous = &(l);\
- (l) = drv;\
- unlock_kernel();\
- } while(0)
+static inline void cpia_add_to_list(struct cam_data* l, struct
cam_data* drv)
+{
+ drv->next = l;
+ drv->previous = &l;
+ l = drv;
+}
-#define REMOVE_FROM_LIST(drv) \
- {\
- if ((drv)->previous != NULL) {\
- lock_kernel();\
- if ((drv)->next != NULL)\
- (drv)->next->previous = (drv)->previous;\
- *((drv)->previous) = (drv)->next;\
- (drv)->previous = NULL;\
- (drv)->next = NULL;\
- unlock_kernel();\
- }\
- } while (0)
+
+static inline void cpia_remove_from_list(struct cam_data* drv)
+{
+ if (drv->previous != NULL) {
+ if (drv->next != NULL)
+ drv->next->previous = drv->previous;
+ *(drv->previous) = drv->next;
+ drv->previous = NULL;
+ drv->next = NULL;
+ }
+}
#endif /* __KERNEL__ */
next reply other threads:[~2001-09-10 23:07 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-09-10 23:06 David C. Hansen [this message]
2001-09-11 0:16 ` [PATCH] broken locking in CPiA driver Johannes Erdfelt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3B9D477F.CABAFD79@us.ibm.com \
--to=haveblue@us.ibm.com \
--cc=Peter.Pregler@risc.uni-linz.ac.at \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox