From: Vaughan Cao <vaughan.cao@oracle.com>
To: joern@logfs.org
Cc: dgilbert@interlog.com, JBottomley@parallels.com,
linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org,
vaughan.cao@oracle.com
Subject: [PATCH v5 1/4] [SCSI] sg: use rwsem to solve race during exclusive open
Date: Mon, 22 Jul 2013 12:40:30 +0800 [thread overview]
Message-ID: <1374468033-8947-2-git-send-email-vaughan.cao@oracle.com> (raw)
In-Reply-To: <1374468033-8947-1-git-send-email-vaughan.cao@oracle.com>
A race condition may happen if two threads are both trying to open the same sg
with O_EXCL simultaneously. It's possible that they both find fsds list is
empty and get_exclude(sdp) returns 0, then they both call set_exclude() and
break out from wait_event_interruptible and resume open.
Now use rwsem to protect this process. Exclusive open gets write lock and
others get read lock. The lock will be held until file descriptor is closed.
This also leads 'exclude' only a status rather than a check mark.
Signed-off-by: Vaughan Cao <vaughan.cao@oracle.com>
---
drivers/scsi/sg.c | 77 ++++++++++++++++++++++++++++++-------------------------
1 file changed, 42 insertions(+), 35 deletions(-)
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 25b5455..edc395a 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -168,11 +168,11 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
typedef struct sg_device { /* holds the state of each scsi generic device */
struct scsi_device *device;
- wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
u32 index; /* device index number */
/* sfds is protected by sg_index_lock */
struct list_head sfds;
+ struct rw_semaphore o_sem; /* exclude open should hold this rwsem */
volatile char detached; /* 0->attached, 1->detached pending removal */
/* exclude protected by sg_open_exclusive_lock */
char exclude; /* opened for exclusive access */
@@ -293,35 +293,35 @@ sg_open(struct inode *inode, struct file *filp)
goto error_out;
}
- if (flags & O_EXCL) {
- if (O_RDONLY == (flags & O_ACCMODE)) {
- retval = -EPERM; /* Can't lock it with read only access */
- goto error_out;
- }
- if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
- retval = -EBUSY;
- goto error_out;
- }
- res = wait_event_interruptible(sdp->o_excl_wait,
- ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
- if (res) {
- retval = res; /* -ERESTARTSYS because signal hit process */
- goto error_out;
- }
- } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */
- if (flags & O_NONBLOCK) {
- retval = -EBUSY;
- goto error_out;
- }
- res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
- if (res) {
- retval = res; /* -ERESTARTSYS because signal hit process */
- goto error_out;
+ if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE))) {
+ retval = -EPERM; /* Can't lock it with read only access */
+ goto error_out;
+ }
+ if (flags & O_NONBLOCK) {
+ if (flags & O_EXCL) {
+ if (!down_write_trylock(&sdp->o_sem)) {
+ retval = -EBUSY;
+ goto error_out;
+ }
+ } else {
+ if (!down_read_trylock(&sdp->o_sem)) {
+ retval = -EBUSY;
+ goto error_out;
+ }
}
+ } else {
+ if (flags & O_EXCL)
+ down_write(&sdp->o_sem);
+ else
+ down_read(&sdp->o_sem);
}
+ /* Since write lock is held, no need to check sfd_list */
+ if (flags & O_EXCL)
+ set_exclude(sdp, 1);
+
if (sdp->detached) {
retval = -ENODEV;
- goto error_out;
+ goto sem_out;
}
if (sfds_list_empty(sdp)) { /* no existing opens on this device */
sdp->sgdebug = 0;
@@ -331,16 +331,19 @@ sg_open(struct inode *inode, struct file *filp)
if ((sfp = sg_add_sfp(sdp, dev)))
filp->private_data = sfp;
else {
- if (flags & O_EXCL) {
- set_exclude(sdp, 0); /* undo if error */
- wake_up_interruptible(&sdp->o_excl_wait);
- }
retval = -ENOMEM;
- goto error_out;
+ goto sem_out;
}
retval = 0;
-error_out:
+
if (retval) {
+sem_out:
+ if (flags & O_EXCL) {
+ set_exclude(sdp, 0); /* undo if error */
+ up_write(&sdp->o_sem);
+ } else
+ up_read(&sdp->o_sem);
+error_out:
scsi_autopm_put_device(sdp->device);
sdp_put:
scsi_device_put(sdp->device);
@@ -357,13 +360,18 @@ sg_release(struct inode *inode, struct file *filp)
{
Sg_device *sdp;
Sg_fd *sfp;
+ int excl;
if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
+ excl = get_exclude(sdp);
set_exclude(sdp, 0);
- wake_up_interruptible(&sdp->o_excl_wait);
+ if (excl)
+ up_write(&sdp->o_sem);
+ else
+ up_read(&sdp->o_sem);
scsi_autopm_put_device(sdp->device);
kref_put(&sfp->f_ref, sg_remove_sfp);
@@ -1415,7 +1423,7 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
sdp->disk = disk;
sdp->device = scsidp;
INIT_LIST_HEAD(&sdp->sfds);
- init_waitqueue_head(&sdp->o_excl_wait);
+ init_rwsem(&sdp->o_sem);
sdp->sg_tablesize = queue_max_segments(q);
sdp->index = k;
kref_init(&sdp->d_ref);
@@ -2140,7 +2148,6 @@ static void sg_remove_sfp(struct kref *kref)
write_lock_irqsave(&sg_index_lock, iflags);
list_del(&sfp->sfd_siblings);
write_unlock_irqrestore(&sg_index_lock, iflags);
- wake_up_interruptible(&sdp->o_excl_wait);
INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
schedule_work(&sfp->ew.work);
--
1.7.11.7
next prev parent reply other threads:[~2013-07-22 4:40 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-05 9:18 [PATCH] sg: atomize check and set sdp->exclude in sg_open vaughan
2013-06-05 13:27 ` Jörn Engel
2013-06-05 16:16 ` vaughan
2013-06-05 15:41 ` Jörn Engel
2013-06-06 7:19 ` vaughan
2013-06-06 7:29 ` vaughan
2013-06-17 13:10 ` [PATCH v2 1/1] [SCSI] sg: fix race condition when do exclusive open vaughan
2013-06-26 1:37 ` vaughan
2013-07-05 1:59 ` vaughan
2013-07-05 17:39 ` Jörn Engel
2013-07-06 17:24 ` vaughan
2013-07-07 19:53 ` [PATCH v3 " vaughan
2013-07-15 20:37 ` Jörn Engel
2013-07-17 15:34 ` [PATCH v4 0/4] [SCSI] sg: fix race condition in sg_open Vaughan Cao
2013-07-17 15:34 ` [PATCH v4 1/4] [SCSI] sg: use rwsem to solve race during exclusive open Vaughan Cao
2013-07-19 21:19 ` Jörn Engel
2013-07-17 15:34 ` [PATCH v4 2/4] [SCSI] sg: no need sg_open_exclusive_lock Vaughan Cao
2013-07-19 21:19 ` Jörn Engel
2013-07-17 15:34 ` [PATCH v4 3/4] [SCSI] sg: checking sdp->detached isn't protected when open Vaughan Cao
2013-07-19 21:24 ` Jörn Engel
2013-07-22 3:39 ` [PATCH v5 " Vaughan Cao
[not found] ` <CAMvaAQnFy0WiXHaNtAB1KPLK-7yj1AHh=_Pw4MBm0=_ecpoAoQ@mail.gmail.com>
2013-07-22 16:52 ` [PATCH v4 " Jörn Engel
2013-07-17 15:34 ` [PATCH v4 4/4] [SCSI] sg: push file descriptor list locking down to per-device locking Vaughan Cao
2013-07-19 21:26 ` Jörn Engel
2013-07-22 3:41 ` [PATCH v5 " Vaughan Cao
2013-07-22 4:40 ` [PATCH v5 0/4] [SCSI] sg: fix race condition in sg_open Vaughan Cao
2013-07-22 4:40 ` Vaughan Cao [this message]
2013-08-28 4:00 ` [PATCH v5 1/4] [SCSI] sg: use rwsem to solve race during exclusive open James Bottomley
2013-08-28 10:07 ` [PATCH v6 0/4][SCSI] sg: fix race condition in sg_open Vaughan Cao
2013-08-28 10:07 ` [PATCH v6 1/4] sg: use rwsem to solve race during exclusive open Vaughan Cao
2013-08-28 10:26 ` James Bottomley
2013-08-29 2:00 ` [PATCH v7 0/4][SCSI] sg: fix race condition in sg_open Vaughan Cao
2013-08-29 2:00 ` [PATCH v7 1/4] sg: use rwsem to solve race during exclusive open Vaughan Cao
2013-08-29 2:00 ` [PATCH v7 2/4] sg: no need sg_open_exclusive_lock Vaughan Cao
2013-08-29 2:00 ` [PATCH v7 3/4] sg: checking sdp->detached isn't protected when open Vaughan Cao
2013-08-29 2:00 ` [PATCH v7 4/4] sg: push file descriptor list locking down to per-device locking Vaughan Cao
2013-08-28 10:07 ` [PATCH v6 2/4] sg: no need sg_open_exclusive_lock Vaughan Cao
2013-08-28 10:07 ` [PATCH v6 3/4] sg: checking sdp->detached isn't protected when open Vaughan Cao
2013-08-28 10:07 ` [PATCH v6 4/4] sg: push file descriptor list locking down to per-device locking Vaughan Cao
2013-07-22 4:40 ` [PATCH v5 2/4] [SCSI] sg: no need sg_open_exclusive_lock Vaughan Cao
2013-07-22 4:40 ` [PATCH v5 3/4] [SCSI] sg: checking sdp->detached isn't protected when open Vaughan Cao
2013-07-22 4:40 ` [PATCH v5 4/4] [SCSI] sg: push file descriptor list locking down to per-device locking Vaughan Cao
2013-07-22 17:03 ` [PATCH v5 0/4] [SCSI] sg: fix race condition in sg_open Jörn Engel
2013-07-25 15:32 ` vaughan
2013-07-25 20:33 ` Douglas Gilbert
2013-07-31 4:40 ` vaughan
2013-08-01 5:01 ` Douglas Gilbert
2013-08-03 5:25 ` Douglas Gilbert
2013-08-05 2:19 ` vaughan
2013-08-05 20:52 ` Douglas Gilbert
2013-08-13 2:46 ` vaughan
2013-08-13 3:16 ` Douglas Gilbert
2013-08-27 8:16 ` vaughan
2013-08-27 13:13 ` Douglas Gilbert
2013-08-28 1:50 ` vaughan
2013-07-15 17:25 ` [PATCH v2 1/1] [SCSI] sg: fix race condition when do exclusive open Jörn Engel
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=1374468033-8947-2-git-send-email-vaughan.cao@oracle.com \
--to=vaughan.cao@oracle.com \
--cc=JBottomley@parallels.com \
--cc=dgilbert@interlog.com \
--cc=joern@logfs.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@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;
as well as URLs for NNTP newsgroup(s).