On 10/19/18 2:24 AM, Douglas Gilbert wrote:

> +     if (sfp->tot_fd_thresh)
> +             sfp->sum_fd_dlens += align_sz;
>
What lock protects sfp->sum_fd_dlens?


>  /*
> @@ -2216,38 +2401,85 @@ sg_add_request(struct sg_fd *sfp)
>   * data length exceeds rem_sgat_thresh then the data (or sgat) is
>   * cleared and the request is appended to the tail of the free list.
>   */
> -static int
> +static void
>  sg_remove_request(struct sg_fd *sfp, struct sg_request *srp)
>  {
> +     bool reserve;
>       unsigned long iflags;
> -     int res = 0;
> +     const char *cp = "head";
> +     char b[64];
>  
> -     if (!sfp || !srp || list_empty(&sfp->rq_list))
> -             return res;
> +     if (WARN_ON(!sfp || !srp))
> +             return;
>       write_lock_irqsave(&sfp->rq_list_lock, iflags);
> -     if (!list_empty(&srp->entry)) {
> -             list_del(&srp->entry);
> -             srp->parentfp = NULL;
> -             res = 1;
> -     }
> +     spin_lock(&srp->rq_entry_lck);
> +     /*
> +      * N.B. sg_request object not de-allocated (freed). The contents of
> +      * rq_list and rq_free_list lists are de-allocated (freed) when the
> +      * owning file descriptor is closed. The free list acts as a LIFO.
> +      * This can improve the chance of a cache hit when request is re-used.
> +      */
> +     reserve = (sfp->reserve_srp == srp);
> +     if (reserve || srp->data.dlen <= sfp->rem_sgat_thresh) {
> +             list_del(&srp->rq_entry);
> +             if (srp->data.dlen > 0)
> +                     list_add(&srp->free_entry, &sfp->rq_free_list);
> +             else {
> +                     list_add_tail(&srp->free_entry, &sfp->rq_free_list);
> +                     cp = "tail";
> +             }
> +             snprintf(b, sizeof(b), "%ssrp=0x%p move to fl %s",
> +                      (reserve ? "reserve " : ""), srp, cp);
> +     } else {
> +             srp->rq_state = SG_RQ_BUSY;
> +             list_del(&srp->rq_entry);
> +             spin_unlock(&srp->rq_entry_lck);
> +             write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
> +             if (sfp->sum_fd_dlens) {
> +                     u32 uv = srp->data.dlen;
> +
> +                     if (uv <= sfp->sum_fd_dlens)
> +                             sfp->sum_fd_dlens -= uv;
> +                     else {
> +                             SG_LOG(2, sfp->parentdp,
> +                                    "%s: logic error this dlen > %s\n",
> +                                    __func__, "sum_fd_dlens");
> +                             sfp->sum_fd_dlens = 0;
> +                     }
> +             }
> +             sg_remove_sgat(srp);
> +             /* don't kfree(srp), move clear request to tail of fl */
> +             write_lock_irqsave(&sfp->rq_list_lock, iflags);
> +             spin_lock(&srp->rq_entry_lck);
> +             list_add_tail(&srp->free_entry, &sfp->rq_free_list);
> +             snprintf(b, sizeof(b), "clear sgat srp=0x%p move to fl tail",
> +                      srp);
> +     }
>
>
Here again, no lock protecting sfp->sum_fd_dlens.

Incidentally, I have been using my own home-grown target-mode SCSI
system for the past 16 years, but now I am starting to look into
switching to SCST.  I was just reading about their "SGV cache":

http://scst.sourceforge.net/scst_pg.html

It looks like it serves a similar purpose to what you are trying to
accomplish with recycling the indirect I/O buffers between different
requests.  Perhaps you can borrow some inspiration from them (or even
some code).

Tony Battersby
Cybernetics

Reply via email to