Re: [PATCH 08/13] cifs: handle cancelled requests better

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2010/12/10 Jeff Layton <jlayton@xxxxxxxxxx>:
> Currently, when a request is cancelled via signal, we delete the mid
> immediately. If the request was already transmitted however, the client
> is still likely to receive a response. When it does, it won't recognize
> it however and will pop a printk.
>
> It's also a little dangerous to just delete the mid entry like this. We
> may end up reusing that mid. If we do then we could potentially get the
> response from the first request confused with the later one.
>
> Prevent the reuse of mids by marking them as cancelled and keeping them
> on the pending_mid_q list. If the reply comes in, we'll delete it from
> the list then. If it never comes, then we'll delete it at reconnect
> or when cifsd comes down.
>
> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> ---
>  fs/cifs/cifsglob.h  |    2 +-
>  fs/cifs/cifsproto.h |    1 +
>  fs/cifs/connect.c   |   44 +++++++++++++++++++++++++++++++++++++-------
>  fs/cifs/transport.c |   30 ++++++++++++++++++++++--------
>  4 files changed, 61 insertions(+), 16 deletions(-)
>
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index cc43ada..fb75f04 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -621,7 +621,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
>  #define   MID_REQUEST_SUBMITTED 2
>  #define   MID_RESPONSE_RECEIVED 4
>  #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
> -#define   MID_NO_RESP_NEEDED 0x10
> +#define   MID_REQUEST_CANCELLED 0x10 /* discard any reply */
>
>  /* Types of response buffer returned from SendReceive2 */
>  #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
> index fe77e69..a8fc606 100644
> --- a/fs/cifs/cifsproto.h
> +++ b/fs/cifs/cifsproto.h
> @@ -61,6 +61,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
>                const char *fullpath, const struct dfs_info3_param *ref,
>                char **devname);
>  /* extern void renew_parental_timestamps(struct dentry *direntry);*/
> +extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
>  extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
>                        struct smb_hdr * /* input */ ,
>                        struct smb_hdr * /* out */ ,
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 7e20ece..0feb592 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -133,7 +133,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
>  {
>        int rc = 0;
>        struct list_head *tmp, *tmp2;
> -       struct list_head retry;
> +       struct list_head retry, dispose;
>        struct cifsSesInfo *ses;
>        struct cifsTconInfo *tcon;
>        struct mid_q_entry *mid_entry;
> @@ -192,14 +192,23 @@ cifs_reconnect(struct TCP_Server_Info *server)
>         */
>        cFYI(1, "%s: moving mids to retry list", __func__);
>        INIT_LIST_HEAD(&retry);
> +       INIT_LIST_HEAD(&dispose);
>        spin_lock(&GlobalMid_Lock);
>        list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
>                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
>                if (mid_entry->midState == MID_REQUEST_SUBMITTED)
>                        list_move(tmp, &retry);
> +               else if (mid_entry->midState == MID_REQUEST_CANCELLED)
> +                       list_move(tmp, &dispose);
>        }
>        spin_unlock(&GlobalMid_Lock);
>
> +       /* now walk private dispose list and delete entries */
> +       list_for_each_safe(tmp, tmp2, &dispose) {
> +               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
> +               DeleteMidQEntry(mid_entry);
> +       }
> +
>        while ((server->tcpStatus != CifsExiting) &&
>               (server->tcpStatus != CifsGood)) {
>                try_to_freeze();
> @@ -219,7 +228,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
>                }
>        }
>
> -       /* now, issue callback for all mids in flight */
> +       /* issue callback for all mids in flight */
>        list_for_each_safe(tmp, tmp2, &retry) {
>                list_del_init(tmp);
>                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
> @@ -575,9 +584,13 @@ incomplete_rcv:
>                list_for_each(tmp, &server->pending_mid_q) {
>                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
>
> -                       if ((mid_entry->mid == smb_buffer->Mid) &&
> -                           (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
> -                           (mid_entry->command == smb_buffer->Command)) {
> +                       if (mid_entry->mid != smb_buffer->Mid)
> +                               goto next_mid;
> +                       if (mid_entry->command != smb_buffer->Command)
> +                               goto next_mid;
> +                       if (mid_entry->midState == MID_REQUEST_CANCELLED)
> +                               break;
> +                       if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
>                                if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
>                                        /* We have a multipart transact2 resp */
>                                        isMultiRsp = true;
> @@ -623,11 +636,16 @@ multi_t2_fnd:
>                                server->lstrp = jiffies;
>                                break;
>                        }
> +next_mid:
>                        mid_entry = NULL;
>                }
>                spin_unlock(&GlobalMid_Lock);
>
>                if (mid_entry != NULL) {
> +                       if (mid_entry->midState == MID_REQUEST_CANCELLED) {
> +                               DeleteMidQEntry(mid_entry);
> +                               continue;
> +                       }
>                        mid_entry->callback(mid_entry);
>                        /* Was previous buf put in mpx struct for multi-rsp? */
>                        if (!isMultiRsp) {
> @@ -704,6 +722,9 @@ multi_t2_fnd:
>                }
>                spin_unlock(&cifs_tcp_ses_lock);
>        } else {
> +               struct mid_q_entry *tmp_mid;
> +               struct list_head dispose;
> +
>                /* although we can not zero the server struct pointer yet,
>                since there are active requests which may depnd on them,
>                mark the corresponding SMB sessions as exiting too */
> @@ -713,17 +734,26 @@ multi_t2_fnd:
>                        ses->status = CifsExiting;
>                }
>
> +               INIT_LIST_HEAD(&dispose);
>                spin_lock(&GlobalMid_Lock);
> -               list_for_each(tmp, &server->pending_mid_q) {
> -               mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
> +               list_for_each_entry_safe(mid_entry, tmp_mid,
> +                                        &server->pending_mid_q, qhead) {
>                        if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
>                                cFYI(1, "Clearing Mid 0x%x - issuing callback",
>                                         mid_entry->mid);
>                                mid_entry->callback(mid_entry);
> +                       } else if (mid_entry->midState == MID_REQUEST_CANCELLED) {
> +                               cFYI(1, "Clearing Mid 0x%x - Cancelled",
> +                                       mid_entry->mid);
> +                               list_move(&mid_entry->qhead, &dispose);

Why do we need another list here? It seems to me that we can simply
delete cancelled mid.

>                        }
>                }
>                spin_unlock(&GlobalMid_Lock);
>                spin_unlock(&cifs_tcp_ses_lock);
> +
> +               /* now delete all of the cancelled mids */
> +               list_for_each_entry_safe(mid_entry, tmp_mid, &dispose, qhead)
> +                       DeleteMidQEntry(mid_entry);
>                /* 1/8th of sec is more than enough time for them to exit */
>                msleep(125);
>        }
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 79647db..97a1170 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -81,7 +81,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
>        return temp;
>  }
>
> -static void
> +void
>  DeleteMidQEntry(struct mid_q_entry *midEntry)
>  {
>  #ifdef CONFIG_CIFS_STATS2
> @@ -480,8 +480,13 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
>                goto out;
>
>        rc = wait_for_response(ses->server, midQ);
> -       if (rc != 0)
> -               goto out;
> +       if (rc != 0) {
> +               /* no longer considered to be "in-flight" */
> +               midQ->midState = MID_REQUEST_CANCELLED;
> +               atomic_dec(&ses->server->inFlight);
> +               wake_up(&ses->server->request_q);
> +               return rc;
> +       }
>
>        rc = handle_mid_result(midQ, ses->server);
>        if (rc != 0)
> @@ -623,8 +628,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
>                goto out;
>
>        rc = wait_for_response(ses->server, midQ);
> -       if (rc != 0)
> -               goto out;
> +       if (rc != 0) {
> +               /* no longer considered to be "in-flight" */
> +               midQ->midState = MID_REQUEST_CANCELLED;
> +               atomic_dec(&ses->server->inFlight);
> +               wake_up(&ses->server->request_q);
> +               return rc;
> +       }
>
>        rc = handle_mid_result(midQ, ses->server);
>        if (rc != 0)
> @@ -842,10 +852,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
>                        }
>                }
>
> -               if (wait_for_response(ses->server, midQ) == 0) {
> -                       /* We got the response - restart system call. */
> -                       rstart = 1;
> +               rc = wait_for_response(ses->server, midQ);
> +               if (rc) {
> +                       midQ->midState = MID_REQUEST_CANCELLED;
> +                       return rc;
>                }
> +
> +               /* We got the response - restart system call. */
> +               rstart = 1;
>        }
>
>        rc = handle_mid_result(midQ, ses->server);
> --
> 1.7.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Best regards,
Pavel Shilovsky.
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux