On 14-06-13 05:03 AM, Christoph Hellwig wrote:
Hi Doug, this looks generally good to me, but I don't think open_cnt and exclude have to use atomic_t, as they are only ever modified under open_rel_lock. Can you take a look at the version below? This changes open_cnt to an int, exclude to a bool, removes the open_cnt underflow check that the VFS takes care for, and streamlines the open path a little bit:
As a follow-up attached is a first cut of replacing the locks around sg_request::done with an atomic. It assumes the patch from Christoph earlier in this thread. The interesting part is the removal of the write lock in the completion part of the SG_IO ioctl. Testing ongoing. Doug Gilbert
--- a/drivers/scsi/sg.c 2014-06-13 09:39:54.962003585 -0400 +++ b/drivers/scsi/sg.c 2014-06-13 13:11:49.796632281 -0400 @@ -138,7 +138,7 @@ typedef struct sg_request { /* SG_MAX_QU char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ /* done protected by rq_list_lock */ - char done; /* 0->before bh, 1->before read, 2->read */ + atomic_t done; /* 0->before bh, 1->before read, 2->read */ struct request *rq; struct bio *bio; struct execute_work ew; @@ -809,17 +809,6 @@ sg_common_write(Sg_fd * sfp, Sg_request return 0; } -static int srp_done(Sg_fd *sfp, Sg_request *srp) -{ - unsigned long flags; - int ret; - - read_lock_irqsave(&sfp->rq_list_lock, flags); - ret = srp->done; - read_unlock_irqrestore(&sfp->rq_list_lock, flags); - return ret; -} - static long sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { @@ -851,16 +840,17 @@ sg_ioctl(struct file *filp, unsigned int if (result < 0) return result; result = wait_event_interruptible(sfp->read_wait, - (srp_done(sfp, srp) || atomic_read(&sdp->detaching))); + (atomic_read(&srp->done) || + atomic_read(&sdp->detaching))); if (atomic_read(&sdp->detaching)) return -ENODEV; - write_lock_irq(&sfp->rq_list_lock); - if (srp->done) { - srp->done = 2; - write_unlock_irq(&sfp->rq_list_lock); + if (likely(atomic_add_unless(&srp->done, 1, 0))) { + /* srp->done bumped from 1 to 2 which is expected */ result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp); return (result < 0) ? result : 0; } + /* here if srp->done was 0, abnormal */ + write_lock_irq(&sfp->rq_list_lock); srp->orphan = 1; write_unlock_irq(&sfp->rq_list_lock); return result; /* -ERESTARTSYS because signal hit process */ @@ -932,7 +922,8 @@ sg_ioctl(struct file *filp, unsigned int return -EFAULT; read_lock_irqsave(&sfp->rq_list_lock, iflags); for (srp = sfp->headrp; srp; srp = srp->nextrp) { - if ((1 == srp->done) && (!srp->sg_io_owned)) { + if ((1 == atomic_read(&srp->done)) && + (!srp->sg_io_owned)) { read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __put_user(srp->header.pack_id, ip); @@ -945,7 +936,8 @@ sg_ioctl(struct file *filp, unsigned int case SG_GET_NUM_WAITING: read_lock_irqsave(&sfp->rq_list_lock, iflags); for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) { - if ((1 == srp->done) && (!srp->sg_io_owned)) + if ((1 == atomic_read(&srp->done)) && + (!srp->sg_io_owned)) ++val; } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); @@ -1015,12 +1007,13 @@ sg_ioctl(struct file *filp, unsigned int ++val, srp = srp ? srp->nextrp : srp) { memset(&rinfo[val], 0, SZ_SG_REQ_INFO); if (srp) { - rinfo[val].req_state = srp->done + 1; + rinfo[val].req_state = + atomic_read(&srp->done) + 1; rinfo[val].problem = - srp->header.masked_status & - srp->header.host_status & - srp->header.driver_status; - if (srp->done) + srp->header.masked_status & + srp->header.host_status & + srp->header.driver_status; + if (atomic_read(&srp->done)) rinfo[val].duration = srp->header.duration; else { @@ -1173,7 +1166,8 @@ sg_poll(struct file *filp, poll_table * read_lock_irqsave(&sfp->rq_list_lock, iflags); for (srp = sfp->headrp; srp; srp = srp->nextrp) { /* if any read waiting, flag it */ - if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned)) + if ((0 == res) && (1 == atomic_read(&srp->done)) && + (!srp->sg_io_owned)) res = POLLIN | POLLRDNORM; ++count; } @@ -1303,7 +1297,7 @@ sg_rq_end_io(struct request *rq, int upt char *sense; int result, resid, done = 1; - if (WARN_ON(srp->done != 0)) + if (WARN_ON(atomic_read(&srp->done) != 0)) return; sfp = srp->parentfp; @@ -1318,8 +1312,8 @@ sg_rq_end_io(struct request *rq, int upt result = rq->errors; resid = rq->resid_len; - SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", - sdp->disk->disk_name, srp->header.pack_id, result)); + SCSI_LOG_TIMEOUT(4, printk("%s: %s, pack_id=%d, res=0x%x\n", + __func__, sdp->disk->disk_name, srp->header.pack_id, result)); srp->header.resid = resid; ms = jiffies_to_msecs(jiffies); srp->header.duration = (ms > srp->header.duration) ? @@ -1358,7 +1352,7 @@ sg_rq_end_io(struct request *rq, int upt else done = 0; } - srp->done = done; + atomic_set(&srp->done, done); write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (likely(done)) { @@ -1999,9 +1993,10 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id) write_lock_irqsave(&sfp->rq_list_lock, iflags); for (resp = sfp->headrp; resp; resp = resp->nextrp) { /* look for requests that are ready + not SG_IO owned */ - if ((1 == resp->done) && (!resp->sg_io_owned) && + if ((1 == atomic_read(&resp->done)) && (!resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { - resp->done = 2; /* guard against other readers */ + /* guard against other readers */ + atomic_set(&resp->done, 2); break; } } @@ -2047,6 +2042,7 @@ sg_add_request(Sg_fd * sfp) if (resp) { resp->nextrp = NULL; resp->header.duration = jiffies_to_msecs(jiffies); + atomic_set(&resp->done, 0); } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp; @@ -2556,7 +2552,7 @@ static int sg_proc_seq_show_devstrs(stru /* must be called while holding sg_index_lock */ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) { - int k, m, new_interface, blen, usg; + int k, m, new_interface, blen, usg, done; Sg_request *srp; Sg_fd *fp; const sg_io_hdr_t *hp; @@ -2596,12 +2592,12 @@ static void sg_proc_debug_helper(struct seq_puts(s, cp); blen = srp->data.bufflen; usg = srp->data.k_use_sg; - seq_puts(s, srp->done ? - ((1 == srp->done) ? "rcv:" : "fin:") - : "act:"); + done = atomic_read(&srp->done); + seq_puts(s, done ? ((1 == done) ? "rcv:" : "fin:") + : "act:"); seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); - if (srp->done) + if (done) seq_printf(s, " dur=%d", hp->duration); else { ms = jiffies_to_msecs(jiffies);