@@ -111,6 +111,7 @@ enum sg_rq_state { /* N.B. sg_rq_state_arr assumes SG_RS_AWAIT_RCV==2 */
#define SG_FRQ_DIO_IN_USE 3 /* false->indirect_IO,mmap; 1->dio */
#define SG_FRQ_NO_US_XFER 4 /* no user space transfer of data */
#define SG_FRQ_DEACT_ORPHAN 7 /* not keeping orphan so de-activate */
+#define SG_FRQ_RECEIVING 8 /* guard against multiple receivers */
#define SG_FRQ_BLK_PUT_REQ 9 /* set when blk_put_request() called */
/* Bit positions (flags) for sg_fd::ffd_bm bitmask follow */
@@ -1325,6 +1326,7 @@ sg_ctl_ioreceive(struct file *filp, struct sg_fd *sfp, void __user *p)
SG_LOG(3, sfp, "%s: non_block(+IMMED)=%d\n", __func__, non_block);
/* read in part of v3 or v4 header for pack_id or tag based find */
id = pack_id;
+try_again:
srp = sg_find_srp_by_id(sfp, id);
if (!srp) { /* nothing available so wait on packet or */
if (unlikely(SG_IS_DETACHING(sdp)))
@@ -1339,6 +1341,10 @@ sg_ctl_ioreceive(struct file *filp, struct sg_fd *sfp, void __user *p)
if (res)
return res; /* signal --> -ERESTARTSYS */
} /* now srp should be valid */
+ if (test_and_set_bit(SG_FRQ_RECEIVING, srp->frq_bm)) {
+ cpu_relax();
+ goto try_again;
+ }
return sg_receive_v4(sfp, srp, p, h4p);
}
@@ -1375,7 +1381,7 @@ sg_ctl_ioreceive_v3(struct file *filp, struct sg_fd *sfp, void __user *p)
if (test_bit(SG_FFD_FORCE_PACKID, sfp->ffd_bm))
pack_id = h3p->pack_id;
-
+try_again:
srp = sg_find_srp_by_id(sfp, pack_id);
if (!srp) { /* nothing available so wait on packet or */
if (unlikely(SG_IS_DETACHING(sdp)))
@@ -1390,6 +1396,10 @@ sg_ctl_ioreceive_v3(struct file *filp, struct sg_fd *sfp, void __user *p)
if (unlikely(res))
return res; /* signal --> -ERESTARTSYS */
} /* now srp should be valid */
+ if (test_and_set_bit(SG_FRQ_RECEIVING, srp->frq_bm)) {
+ cpu_relax();
+ goto try_again;
+ }
return sg_receive_v3(sfp, srp, p);
}
@@ -1541,6 +1551,7 @@ sg_read(struct file *filp, char __user *p, size_t count, loff_t *ppos)
want_id = h2p->pack_id;
}
}
+try_again:
srp = sg_find_srp_by_id(sfp, want_id);
if (!srp) { /* nothing available so wait on packet to arrive or */
if (unlikely(SG_IS_DETACHING(sdp)))
@@ -1556,6 +1567,10 @@ sg_read(struct file *filp, char __user *p, size_t count, loff_t *ppos)
return ret;
/* otherwise srp should be valid */
}
+ if (test_and_set_bit(SG_FRQ_RECEIVING, srp->frq_bm)) {
+ cpu_relax();
+ goto try_again;
+ }
if (srp->s_hdr3.interface_id == '\0') {
ret = sg_read_v1v2(p, (int)count, sfp, srp);
} else {
@@ -3549,6 +3564,7 @@ sg_deact_request(struct sg_fd *sfp, struct sg_request *srp)
return;
sbp = srp->sense_bp;
srp->sense_bp = NULL;
+ srp->frq_bm[0] = 0;
sg_rq_state_chg(srp, 0, SG_RS_INACTIVE, true /* force */, __func__);
/* maybe orphaned req, thus never read */
if (sbp)
If two threads call ioctl(SG_IORECEIVE) [or read()] on the same file descriptor there is a potential race on the same request response. Use atomic bit operations to make sure only one thread gets each request response. [The other thread will either get another request response or nothing.] Signed-off-by: Douglas Gilbert <dgilbert@interlog.com> --- drivers/scsi/sg.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)