Re: [PATCH 07/13] cifs: allow for different handling of received response

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

 



2010/12/10 Jeff Layton <jlayton@xxxxxxxxxx>:
> In order to incorporate async requests, we need to allow for a more
> general way to do things on receive, rather than just waking up a
> process.
>
> Turn the task pointer in the mid_q_entry into a callback function and a
> generic data pointer. When a response comes in, or the socket is
> reconnected, cifsd can call the callback function in order to wake up
> the process.
>
> The default is to just wake up the current process which should mean no
> change in behavior for existing code.
>
> Also, clean up the locking in cifs_reconnect. There doesn't seem to be
> any need to hold both the srv_mutex and GlobalMid_Lock when walking the
> list of mids.
>
> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> ---
>  fs/cifs/cifs_debug.c |    8 +++---
>  fs/cifs/cifsglob.h   |    7 +++++-
>  fs/cifs/connect.c    |   54 ++++++++++++++++++++++++++++---------------------
>  fs/cifs/transport.c  |   15 +++++++++++++-
>  4 files changed, 55 insertions(+), 29 deletions(-)
>
> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
> index bd76527..c81934f 100644
> --- a/fs/cifs/cifs_debug.c
> +++ b/fs/cifs/cifs_debug.c
> @@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
>        spin_lock(&GlobalMid_Lock);
>        list_for_each(tmp, &server->pending_mid_q) {
>                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
> -               cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
> +               cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
>                        mid_entry->midState,
>                        (int)mid_entry->command,
>                        mid_entry->pid,
> -                       mid_entry->tsk,
> +                       mid_entry->callback_data,
>                        mid_entry->mid);
>  #ifdef CONFIG_CIFS_STATS2
>                cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
> @@ -218,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
>                                mid_entry = list_entry(tmp3, struct mid_q_entry,
>                                        qhead);
>                                seq_printf(m, "\tState: %d com: %d pid:"
> -                                               " %d tsk: %p mid %d\n",
> +                                               " %d cbdata: %p mid %d\n",
>                                                mid_entry->midState,
>                                                (int)mid_entry->command,
>                                                mid_entry->pid,
> -                                               mid_entry->tsk,
> +                                               mid_entry->callback_data,
>                                                mid_entry->mid);
>                        }
>                        spin_unlock(&GlobalMid_Lock);
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index cf0dfda..cc43ada 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -511,6 +511,10 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
>
>  #endif
>
> +struct mid_q_entry;
> +
> +typedef void (mid_callback_t)(struct mid_q_entry *mid);
> +
>  /* one of these for every pending CIFS request to the server */
>  struct mid_q_entry {
>        struct list_head qhead; /* mids waiting on reply from this server */
> @@ -522,7 +526,8 @@ struct mid_q_entry {
>        unsigned long when_sent; /* time when smb send finished */
>        unsigned long when_received; /* when demux complete (taken off wire) */
>  #endif
> -       struct task_struct *tsk;        /* task waiting for response */
> +       mid_callback_t *callback; /* call completion callback */
> +       void *callback_data;      /* general purpose pointer for callback */
>        struct smb_hdr *resp_buf;       /* response buffer */
>        int midState;   /* wish this were enum but can not pass to wait_event */
>        __u8 command;   /* smb command code */
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 9fbe7c5..7e20ece 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -133,6 +133,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
>  {
>        int rc = 0;
>        struct list_head *tmp, *tmp2;
> +       struct list_head retry;
>        struct cifsSesInfo *ses;
>        struct cifsTconInfo *tcon;
>        struct mid_q_entry *mid_entry;
> @@ -152,6 +153,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
>
>        /* before reconnecting the tcp session, mark the smb session (uid)
>                and the tid bad so they are not used until reconnected */
> +       cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
>        spin_lock(&cifs_tcp_ses_lock);
>        list_for_each(tmp, &server->smb_ses_list) {
>                ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
> @@ -163,7 +165,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
>                }
>        }
>        spin_unlock(&cifs_tcp_ses_lock);
> +
>        /* do not want to be sending data on a socket we are freeing */
> +       cFYI(1, "%s: tearing down socket", __func__);
>        mutex_lock(&server->srv_mutex);
>        if (server->ssocket) {
>                cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
> @@ -180,22 +184,21 @@ cifs_reconnect(struct TCP_Server_Info *server)
>        kfree(server->session_key.response);
>        server->session_key.response = NULL;
>        server->session_key.len = 0;
> +       mutex_unlock(&server->srv_mutex);
>
> +       /*
> +        * move in-progress mids to a private list so that we can walk it later
> +        * without needing a lock. We'll mark them for retry after reconnect.
> +        */
> +       cFYI(1, "%s: moving mids to retry list", __func__);
> +       INIT_LIST_HEAD(&retry);
>        spin_lock(&GlobalMid_Lock);
> -       list_for_each(tmp, &server->pending_mid_q) {
> -               mid_entry = list_entry(tmp, struct
> -                                       mid_q_entry,
> -                                       qhead);
> -               if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
> -                               /* Mark other intransit requests as needing
> -                                  retry so we do not immediately mark the
> -                                  session bad again (ie after we reconnect
> -                                  below) as they timeout too */
> -                       mid_entry->midState = MID_RETRY_NEEDED;
> -               }
> +       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);
>        }
>        spin_unlock(&GlobalMid_Lock);
> -       mutex_unlock(&server->srv_mutex);
>
>        while ((server->tcpStatus != CifsExiting) &&
>               (server->tcpStatus != CifsGood)) {
> @@ -213,10 +216,17 @@ cifs_reconnect(struct TCP_Server_Info *server)
>                        if (server->tcpStatus != CifsExiting)
>                                server->tcpStatus = CifsGood;
>                        spin_unlock(&GlobalMid_Lock);
> -       /*              atomic_set(&server->inFlight,0);*/
> -                       wake_up(&server->response_q);
>                }
>        }
> +
> +       /* now, 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);
> +               mid_entry->midState = MID_RETRY_NEEDED;
> +               mid_entry->callback(mid_entry);
> +       }
> +
>        return rc;
>  }
>
> @@ -560,8 +570,7 @@ incomplete_rcv:
>                        continue;
>                }
>
> -
> -               task_to_wake = NULL;
> +               mid_entry = NULL;
>                spin_lock(&GlobalMid_Lock);
>                list_for_each(tmp, &server->pending_mid_q) {
>                        mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
> @@ -604,7 +613,6 @@ incomplete_rcv:
>                                mid_entry->resp_buf = smb_buffer;
>                                mid_entry->largeBuf = isLargeBuf;
>  multi_t2_fnd:
> -                               task_to_wake = mid_entry->tsk;
>                                mid_entry->midState = MID_RESPONSE_RECEIVED;
>  #ifdef CONFIG_CIFS_STATS2
>                                mid_entry->when_received = jiffies;
> @@ -615,9 +623,12 @@ multi_t2_fnd:
>                                server->lstrp = jiffies;
>                                break;
>                        }
> +                       mid_entry = NULL;
>                }
>                spin_unlock(&GlobalMid_Lock);
> -               if (task_to_wake) {
> +
> +               if (mid_entry != NULL) {
> +                       mid_entry->callback(mid_entry);
>                        /* Was previous buf put in mpx struct for multi-rsp? */
>                        if (!isMultiRsp) {
>                                /* smb buffer will be freed by user thread */
> @@ -626,7 +637,6 @@ multi_t2_fnd:
>                                else
>                                        smallbuf = NULL;
>                        }
> -                       wake_up_process(task_to_wake);
>                } else if (!is_valid_oplock_break(smb_buffer, server) &&
>                           !isMultiRsp) {
>                        cERROR(1, "No task to wake, unknown frame received! "
> @@ -707,11 +717,9 @@ multi_t2_fnd:
>                list_for_each(tmp, &server->pending_mid_q) {
>                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
>                        if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
> -                               cFYI(1, "Clearing Mid 0x%x - waking up ",
> +                               cFYI(1, "Clearing Mid 0x%x - issuing callback",
>                                         mid_entry->mid);
> -                               task_to_wake = mid_entry->tsk;
> -                               if (task_to_wake)
> -                                       wake_up_process(task_to_wake);
> +                               mid_entry->callback(mid_entry);
>                        }
>                }
>                spin_unlock(&GlobalMid_Lock);
> diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
> index 05ced17..79647db 100644
> --- a/fs/cifs/transport.c
> +++ b/fs/cifs/transport.c
> @@ -36,6 +36,12 @@
>
>  extern mempool_t *cifs_mid_poolp;
>
> +static void
> +wake_up_task(struct mid_q_entry *mid)
> +{
> +       wake_up_process(mid->callback_data);
> +}
> +
>  static struct mid_q_entry *
>  AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
>  {
> @@ -58,7 +64,13 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
>        /*      do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
>                /* when mid allocated can be before when sent */
>                temp->when_alloc = jiffies;
> -               temp->tsk = current;
> +
> +               /*
> +                * The default is for the mid to be synchronous, so the
> +                * default callback just wakes up the current task.
> +                */
> +               temp->callback = wake_up_task;
> +               temp->callback_data = current;
>        }
>
>        spin_lock(&GlobalMid_Lock);
> @@ -374,6 +386,7 @@ handle_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
>                }
>                mid->midState = MID_RETRY_NEEDED;
>        case MID_RETRY_NEEDED:
> +               list_move(&mid->qhead, &server->pending_mid_q);
>                rc = -EAGAIN;
>                break;
>        default:
> --
> 1.7.3.2
>

Very good idea to add default synchronous callback - it simplifies the
code greatly. Looks ok to me.

Reviewed-by:  Pavel Shilovsky <piastryyy@xxxxxxxxx>


-- 
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