linux-scsi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Hannes Reinecke <hare@suse.de>
To: dgilbert@interlog.com, linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com
Subject: Re: [PATCH v5 20/23] sg: introduce request state machine
Date: Thu, 24 Oct 2019 07:51:30 +0200	[thread overview]
Message-ID: <35ac1ffc-bab1-321e-cbab-7d7e9569f4a6@suse.de> (raw)
In-Reply-To: <9360e6da-39da-15bb-d9e8-cf881b936e8d@interlog.com>

On 10/24/19 6:24 AM, Douglas Gilbert wrote:
> On 2019-10-18 6:25 a.m., Hannes Reinecke wrote:
>> On 10/8/19 9:50 AM, Douglas Gilbert wrote:
>>> The introduced request state machine is not wired in so that
>>> the size of one of the following patches is reduced. Bit
>>> operation defines for the request and file descriptor level
>>> are also introduced. Minor rework og sg_rd_append() function.
>>>
>>> Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
>>> ---
>>>   drivers/scsi/sg.c | 237 ++++++++++++++++++++++++++++++++++------------
>>>   1 file changed, 175 insertions(+), 62 deletions(-)
>>>
>>> diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
>>> index 5b560f720993..4e6f6fb2a54e 100644
>>> --- a/drivers/scsi/sg.c
>>> +++ b/drivers/scsi/sg.c
>>> @@ -75,7 +75,43 @@ static char *sg_version_date = "20190606";
>>>   #define uptr64(val) ((void __user *)(uintptr_t)(val))
>>>   #define cuptr64(val) ((const void __user *)(uintptr_t)(val))
>>>   +/* Following enum contains the states of sg_request::rq_st */
>>> +enum sg_rq_state {
>>> +    SG_RS_INACTIVE = 0,    /* request not in use (e.g. on fl) */
>>> +    SG_RS_INFLIGHT,        /* active: cmd/req issued, no response
>>> yet */
>>> +    SG_RS_AWAIT_RD,        /* response received, awaiting read */
>>> +    SG_RS_DONE_RD,        /* read is ongoing or done */
>>> +    SG_RS_BUSY,        /* temporary state should rarely be seen */
>>> +};
>>> +
>>> +#define SG_TIME_UNIT_MS 0    /* milliseconds */
>>> +#define SG_DEF_TIME_UNIT SG_TIME_UNIT_MS
>>>   #define SG_DEFAULT_TIMEOUT mult_frac(SG_DEFAULT_TIMEOUT_USER, HZ,
>>> USER_HZ)
>>> +#define SG_FD_Q_AT_HEAD 0
>>> +#define SG_DEFAULT_Q_AT SG_FD_Q_AT_HEAD /* for backward
>>> compatibility */
>>> +#define SG_FL_MMAP_DIRECT (SG_FLAG_MMAP_IO | SG_FLAG_DIRECT_IO)
>>> +
>>> +/* Only take lower 4 bits of driver byte, all host byte and sense
>>> byte */
>>> +#define SG_ML_RESULT_MSK 0x0fff00ff    /* mid-level's 32 bit result
>>> value */
>>> +
>>> +#define SG_PACK_ID_WILDCARD (-1)
>>> +
>>> +#define SG_ADD_RQ_MAX_RETRIES 40    /* to stop infinite _trylock(s) */
>>> +
>>> +/* Bit positions (flags) for sg_request::frq_bm bitmask follow */
>>> +#define SG_FRQ_IS_ORPHAN    1    /* owner of request gone */
>>> +#define SG_FRQ_SYNC_INVOC    2    /* synchronous (blocking)
>>> invocation */
>>> +#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_BLK_PUT_REQ    9    /* set when blk_put_request()
>>> called */
>>> +
>>> +/* Bit positions (flags) for sg_fd::ffd_bm bitmask follow */
>>> +#define SG_FFD_FORCE_PACKID    0    /* receive only given
>>> pack_id/tag */
>>> +#define SG_FFD_CMD_Q        1    /* clear: only 1 active req per fd */
>>> +#define SG_FFD_KEEP_ORPHAN    2    /* policy for this fd */
>>> +#define SG_FFD_MMAP_CALLED    3    /* mmap(2) system call made on fd */
>>> +#define SG_FFD_Q_AT_TAIL    5    /* set: queue reqs at tail of blk q */
>>>     /* Bit positions (flags) for sg_device::fdev_bm bitmask follow */
>>>   #define SG_FDEV_EXCLUDE        0    /* have fd open with O_EXCL */
>>> @@ -83,12 +119,11 @@ static char *sg_version_date = "20190606";
>>>   #define SG_FDEV_LOG_SENSE    2    /* set by ioctl(SG_SET_DEBUG) */
>>>     int sg_big_buff = SG_DEF_RESERVED_SIZE;
>>> -/* N.B. This variable is readable and writeable via
>>> -   /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a
>>> buffer
>>> -   of this size (or less if there is not enough memory) will be
>>> reserved
>>> -   for use by this file descriptor. [Deprecated usage: this variable
>>> is also
>>> -   readable via /proc/sys/kernel/sg-big-buff if the sg driver is
>>> built into
>>> -   the kernel (i.e. it is not a module).] */
>>> +/*
>>> + * This variable is accessible via /proc/scsi/sg/def_reserved_size .
>>> Each
>>> + * time sg_open() is called a sg_request of this size (or less if
>>> there is
>>> + * not enough memory) will be reserved for use by this file descriptor.
>>> + */
>>>   static int def_reserved_size = -1;    /* picks up init parameter */
>>>   static int sg_allow_dio = SG_ALLOW_DIO_DEF;
>>>   @@ -132,6 +167,7 @@ struct sg_request {    /* SG_MAX_QUEUE requests
>>> outstanding per file */
>>>       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 rq_st;        /* request state, holds a enum
>>> sg_rq_state */
>>>       struct request *rq;    /* released in sg_rq_end_io(), bio kept */
>>>       struct bio *bio;    /* kept until this req -->SG_RS_INACTIVE */
>>>       struct execute_work ew_orph;    /* harvest orphan request */
>>> @@ -208,10 +244,15 @@ static void sg_unlink_reserve(struct sg_fd
>>> *sfp, struct sg_request *srp);
>>>   static struct sg_fd *sg_add_sfp(struct sg_device *sdp);
>>>   static void sg_remove_sfp(struct kref *);
>>>   static struct sg_request *sg_add_request(struct sg_fd *sfp);
>>> -static int sg_deact_request(struct sg_fd *sfp, struct sg_request *srp);
>>> +static void sg_deact_request(struct sg_fd *sfp, struct sg_request
>>> *srp);
>>>   static struct sg_device *sg_get_dev(int dev);
>>>   static void sg_device_destroy(struct kref *kref);
>>>   static void sg_calc_sgat_param(struct sg_device *sdp);
>>> +static const char *sg_rq_st_str(enum sg_rq_state rq_st, bool long_str);
>>> +static void sg_rep_rq_state_fail(struct sg_fd *sfp,
>>> +                 enum sg_rq_state exp_old_st,
>>> +                 enum sg_rq_state want_st,
>>> +                 enum sg_rq_state act_old_st);
>>>     #define SZ_SG_HEADER ((int)sizeof(struct sg_header))    /* v1 and
>>> v2 header */
>>>   #define SZ_SG_IO_HDR ((int)sizeof(struct sg_io_hdr))    /* v3
>>> header */
>>> @@ -219,6 +260,8 @@ static void sg_calc_sgat_param(struct sg_device
>>> *sdp);
>>>     #define SG_IS_DETACHING(sdp) test_bit(SG_FDEV_DETACHING,
>>> (sdp)->fdev_bm)
>>>   #define SG_HAVE_EXCLUDE(sdp) test_bit(SG_FDEV_EXCLUDE, (sdp)->fdev_bm)
>>> +#define SG_RS_ACTIVE(srp) (atomic_read(&(srp)->rq_st) !=
>>> SG_RS_INACTIVE)
>>> +#define SG_RS_AWAIT_READ(srp) (atomic_read(&(srp)->rq_st) ==
>>> SG_RS_AWAIT_RD)
>>>     /*
>>>    * Kernel needs to be built with CONFIG_SCSI_LOGGING to see log
>>> messages.
>>> @@ -382,15 +425,6 @@ sg_open(struct inode *inode, struct file *filp)
>>>       res = sg_allow_if_err_recovery(sdp, non_block);
>>>       if (res)
>>>           goto error_out;
>>> -    /* scsi_block_when_processing_errors() may block so bypass
>>> -     * check if O_NONBLOCK. Permits SCSI commands to be issued
>>> -     * during error recovery. Tread carefully. */
>>> -    if (!((op_flags & O_NONBLOCK) ||
>>> -          scsi_block_when_processing_errors(sdp->device))) {
>>> -        res = -ENXIO;
>>> -        /* we are in error recovery for this device */
>>> -        goto error_out;
>>> -    }
>>>         mutex_lock(&sdp->open_rel_lock);
>>>       if (op_flags & O_NONBLOCK) {
>>> @@ -494,12 +528,12 @@ sg_write(struct file *filp, const char __user
>>> *p, size_t count, loff_t *ppos)
>>>       struct sg_device *sdp;
>>>       struct sg_fd *sfp;
>>>       struct sg_request *srp;
>>> +    u8 cmnd[SG_MAX_CDB_SIZE];
>>>       struct sg_header ov2hdr;
>>>       struct sg_io_hdr v3hdr;
>>>       struct sg_header *ohp = &ov2hdr;
>>>       struct sg_io_hdr *h3p = &v3hdr;
>>>       struct sg_comm_wr_t cwr;
>>> -    u8 cmnd[SG_MAX_CDB_SIZE];
>>>         res = sg_check_file_access(filp, __func__);
>>>       if (res)
>>> @@ -748,11 +782,25 @@ sg_common_write(struct sg_fd *sfp, struct
>>> sg_comm_wr_t *cwrp)
>>>       return 0;
>>>   }
>>>   +static inline int
>>> +sg_rstate_chg(struct sg_request *srp, enum sg_rq_state old_st,
>>> +          enum sg_rq_state new_st)
>>> +{
>>> +    enum sg_rq_state act_old_st = (enum sg_rq_state)
>>> +                atomic_cmpxchg(&srp->rq_st, old_st, new_st);
>>> +
>>> +    if (act_old_st == old_st)
>>> +        return 0;       /* implies new_st --> srp->rq_st */
>>> +    else if (IS_ENABLED(CONFIG_SCSI_LOGGING))
>>> +        sg_rep_rq_state_fail(srp->parentfp, old_st, new_st,
>>> +                     act_old_st);
>>> +    return -EPROTOTYPE;
>>> +}
>>>   
>> -EPROTOTYPE?
>> Now there someone has read POSIX ... why not simply -EINVAL as one would
>> expect?
> 
> I expect EINVAL from very shallow errors, like sanity checks by
> ioctl(SG_IOSUBMIT) or write(2) before they issue a command/request to the
> lower levels.
> 
> This however is a lot more interesting. It is potentially two readers in
> a race, and if the race is close, the loser gets this error. Depending on
> the context, the user will either see this error, or EBUSY. There is an
> inherent race in the read/receive side of all AIO designs, as far as I
> can determine. Such a race is advised against in my documentation, but
> if a user, accidentally or otherwise, generates that race, then IMO
> the driver needs to handle it. By "handle it" I don't mean trying to help
> such users, I mean to protect the driver and the kernel behind it.
> 
> A later patch (46/62 currently) adds a 28 entry table of errno values
> with their meaning if returned by this driver:
> ....
>    EPROTOTYPE    atomic state change failed unexpectedly
> ....
> 
Ah, right. Fine.

Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      Teamlead Storage & Networking
hare@suse.de			                  +49 911 74053 688
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 247165 (AG München), GF: Felix Imendörffer

  reply	other threads:[~2019-10-24  5:51 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-08  7:49 [PATCH v5 00/23] sg: add v4 interface Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 01/23] sg: move functions around Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 02/23] sg: remove typedefs, type+formatting cleanup Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 03/23] sg: sg_log and is_enabled Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 04/23] sg: rework sg_poll(), minor changes Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 05/23] sg: bitops in sg_device Douglas Gilbert
2019-10-18 10:05   ` Hannes Reinecke
2019-10-21 13:22     ` Douglas Gilbert
2019-10-21 13:38       ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 06/23] sg: make open count an atomic Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 07/23] sg: move header to uapi section Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 08/23] sg: speed sg_poll and sg_get_num_waiting Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 09/23] sg: sg_allow_if_err_recovery and renames Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 10/23] sg: remove access_ok functions Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 11/23] sg: improve naming Douglas Gilbert
2019-10-18 10:06   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 12/23] sg: change rwlock to spinlock Douglas Gilbert
2019-10-18 10:09   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 13/23] sg: ioctl handling Douglas Gilbert
2019-10-18 10:12   ` Hannes Reinecke
2019-10-24  2:47     ` Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 14/23] sg: split sg_read Douglas Gilbert
2019-10-18 10:15   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 15/23] sg: sg_common_write add structure for arguments Douglas Gilbert
2019-10-18 10:16   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 16/23] sg: rework sg_vma_fault Douglas Gilbert
2019-10-18 10:17   ` Hannes Reinecke
2019-10-24  3:07     ` Douglas Gilbert
2019-10-08  7:50 ` [PATCH v5 17/23] sg: rework sg_mmap Douglas Gilbert
2019-10-18 10:18   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 18/23] sg: replace sg_allow_access Douglas Gilbert
2019-10-18 10:20   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 19/23] sg: rework scatter gather handling Douglas Gilbert
2019-10-18 10:22   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 20/23] sg: introduce request state machine Douglas Gilbert
2019-10-18 10:25   ` Hannes Reinecke
2019-10-24  4:24     ` Douglas Gilbert
2019-10-24  5:51       ` Hannes Reinecke [this message]
2019-10-08  7:50 ` [PATCH v5 21/23] sg: sg_find_srp_by_id Douglas Gilbert
2019-10-18 10:27   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 22/23] sg: sg_fill_request_element Douglas Gilbert
2019-10-18 10:29   ` Hannes Reinecke
2019-10-08  7:50 ` [PATCH v5 23/23] sg: printk change %p to %pK Douglas Gilbert

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=35ac1ffc-bab1-321e-cbab-7d7e9569f4a6@suse.de \
    --to=hare@suse.de \
    --cc=dgilbert@interlog.com \
    --cc=jejb@linux.vnet.ibm.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    /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).