"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/rpc/rpc-lib/src/rpc-clnt-ping.c" (16 Sep 2020, 9829 Bytes) of package /linux/misc/glusterfs-8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rpc-clnt-ping.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
    3   This file is part of GlusterFS.
    4 
    5   This file is licensed to you under your choice of the GNU Lesser
    6   General Public License, version 3 or any later version (LGPLv3 or
    7   later), or the GNU General Public License, version 2 (GPLv2), in all
    8   cases as published by the Free Software Foundation.
    9 */
   10 
   11 #include "rpc-clnt.h"
   12 #include "rpc-clnt-ping.h"
   13 #include <glusterfs/byte-order.h>
   14 #include "xdr-rpcclnt.h"
   15 #include "rpc-transport.h"
   16 #include "protocol-common.h"
   17 #include <glusterfs/mem-pool.h>
   18 #include "xdr-rpc.h"
   19 #include "rpc-common-xdr.h"
   20 #include <glusterfs/timespec.h>
   21 
   22 char *clnt_ping_procs[GF_DUMP_MAXVALUE] = {
   23     [GF_DUMP_PING] = "NULL",
   24 };
   25 struct rpc_clnt_program clnt_ping_prog = {
   26     .progname = "GF-DUMP",
   27     .prognum = GLUSTER_DUMP_PROGRAM,
   28     .progver = GLUSTER_DUMP_VERSION,
   29     .procnames = clnt_ping_procs,
   30 };
   31 
   32 struct ping_local {
   33     struct rpc_clnt *rpc;
   34     struct timespec submit_time;
   35 };
   36 
   37 /* Must be called under conn->lock */
   38 static int
   39 __rpc_clnt_rearm_ping_timer(struct rpc_clnt *rpc, gf_timer_cbk_t cbk)
   40 {
   41     rpc_clnt_connection_t *conn = &rpc->conn;
   42     rpc_transport_t *trans = conn->trans;
   43     struct timespec timeout = {
   44         0,
   45     };
   46     gf_timer_t *timer = NULL;
   47 
   48     if (conn->ping_timer) {
   49         gf_log_callingfn("", GF_LOG_CRITICAL,
   50                          "%s: ping timer event already scheduled",
   51                          conn->trans->peerinfo.identifier);
   52         return -1;
   53     }
   54 
   55     timeout.tv_sec = conn->ping_timeout;
   56     timeout.tv_nsec = 0;
   57 
   58     rpc_clnt_ref(rpc);
   59     timer = gf_timer_call_after(rpc->ctx, timeout, cbk, (void *)rpc);
   60     if (timer == NULL) {
   61         gf_log(trans->name, GF_LOG_WARNING, "unable to setup ping timer");
   62 
   63         /* This unref can't be the last. We just took a ref few lines
   64          * above. So this can be performed under conn->lock. */
   65         rpc_clnt_unref(rpc);
   66         conn->ping_started = 0;
   67         return -1;
   68     }
   69 
   70     conn->ping_timer = timer;
   71     conn->ping_started = 1;
   72     return 0;
   73 }
   74 
   75 /* Must be called under conn->lock */
   76 int
   77 rpc_clnt_remove_ping_timer_locked(struct rpc_clnt *rpc)
   78 {
   79     rpc_clnt_connection_t *conn = &rpc->conn;
   80     gf_timer_t *timer = NULL;
   81 
   82     if (conn->ping_timer) {
   83         timer = conn->ping_timer;
   84         conn->ping_timer = NULL;
   85         gf_timer_call_cancel(rpc->ctx, timer);
   86         conn->ping_started = 0;
   87         return 1;
   88     }
   89 
   90     /* This is to account for rpc_clnt_disable that might have set
   91      *  conn->trans to NULL. */
   92     if (conn->trans)
   93         gf_log_callingfn("", GF_LOG_DEBUG,
   94                          "%s: ping timer event "
   95                          "already removed",
   96                          conn->trans->peerinfo.identifier);
   97 
   98     return 0;
   99 }
  100 
  101 static void
  102 rpc_clnt_start_ping(void *rpc_ptr);
  103 
  104 void
  105 rpc_clnt_ping_timer_expired(void *rpc_ptr)
  106 {
  107     struct rpc_clnt *rpc = NULL;
  108     rpc_transport_t *trans = NULL;
  109     rpc_clnt_connection_t *conn = NULL;
  110     int disconnect = 0;
  111     struct timespec current = {
  112         0,
  113     };
  114     int unref = 0;
  115 
  116     rpc = (struct rpc_clnt *)rpc_ptr;
  117     conn = &rpc->conn;
  118     trans = conn->trans;
  119 
  120     if (!trans) {
  121         gf_log("ping-timer", GF_LOG_WARNING, "transport not initialized");
  122         goto out;
  123     }
  124 
  125     clock_gettime(CLOCK_REALTIME, &current);
  126     pthread_mutex_lock(&conn->lock);
  127     {
  128         unref = rpc_clnt_remove_ping_timer_locked(rpc);
  129 
  130         if (((current.tv_sec - conn->last_received.tv_sec) <
  131              conn->ping_timeout) ||
  132             ((current.tv_sec - conn->last_sent.tv_sec) < conn->ping_timeout)) {
  133             gf_log(trans->name, GF_LOG_TRACE,
  134                    "ping timer expired but transport activity "
  135                    "detected - not bailing transport");
  136             if (__rpc_clnt_rearm_ping_timer(rpc, rpc_clnt_ping_timer_expired) ==
  137                 -1) {
  138                 gf_log(trans->name, GF_LOG_WARNING,
  139                        "unable to setup ping timer");
  140             }
  141         } else {
  142             conn->ping_started = 0;
  143             disconnect = 1;
  144         }
  145     }
  146     pthread_mutex_unlock(&conn->lock);
  147 
  148     if (unref)
  149         rpc_clnt_unref(rpc);
  150 
  151     if (disconnect) {
  152         gf_log(trans->name, GF_LOG_CRITICAL,
  153                "server %s has not responded in the last %d "
  154                "seconds, disconnecting.",
  155                trans->peerinfo.identifier, conn->ping_timeout);
  156 
  157         rpc_transport_disconnect(conn->trans, _gf_false);
  158     }
  159 
  160 out:
  161     return;
  162 }
  163 
  164 int
  165 rpc_clnt_ping_cbk(struct rpc_req *req, struct iovec *iov, int count,
  166                   void *myframe)
  167 {
  168     struct ping_local *local = NULL;
  169     xlator_t *this = NULL;
  170     rpc_clnt_connection_t *conn = NULL;
  171     call_frame_t *frame = NULL;
  172     int unref = 0;
  173     gf_boolean_t call_notify = _gf_false;
  174 
  175     struct timespec now;
  176     struct timespec delta;
  177     int64_t latency_msec = 0;
  178     int ret = 0;
  179 
  180     if (!myframe) {
  181         gf_log(THIS->name, GF_LOG_WARNING, "frame with the request is NULL");
  182         goto out;
  183     }
  184 
  185     frame = myframe;
  186     this = frame->this;
  187     local = frame->local;
  188     conn = &local->rpc->conn;
  189 
  190     timespec_now(&now);
  191     timespec_sub(&local->submit_time, &now, &delta);
  192     latency_msec = delta.tv_sec * 1000 + delta.tv_nsec / 1000000;
  193 
  194     gf_log(THIS->name, GF_LOG_DEBUG, "Ping latency is %" PRIu64 "ms",
  195            latency_msec);
  196     call_notify = _gf_true;
  197 
  198     pthread_mutex_lock(&conn->lock);
  199     {
  200         unref = rpc_clnt_remove_ping_timer_locked(local->rpc);
  201         if (req->rpc_status == -1) {
  202             conn->ping_started = 0;
  203             pthread_mutex_unlock(&conn->lock);
  204             if (unref) {
  205                 gf_log(this->name, GF_LOG_WARNING,
  206                        "socket or ib related error");
  207 
  208             } else {
  209                 /* timer expired and transport bailed out */
  210                 gf_log(this->name, GF_LOG_WARNING, "socket disconnected");
  211             }
  212             goto after_unlock;
  213         }
  214 
  215         if (__rpc_clnt_rearm_ping_timer(local->rpc, rpc_clnt_start_ping) ==
  216             -1) {
  217             /* unlock before logging error */
  218             pthread_mutex_unlock(&conn->lock);
  219             gf_log(this->name, GF_LOG_WARNING, "failed to set the ping timer");
  220         } else {
  221             /* just unlock the mutex */
  222             pthread_mutex_unlock(&conn->lock);
  223         }
  224     }
  225 after_unlock:
  226     if (call_notify) {
  227         ret = local->rpc->notifyfn(local->rpc, this, RPC_CLNT_PING,
  228                                    (void *)(uintptr_t)latency_msec);
  229         if (ret) {
  230             gf_log(this->name, GF_LOG_WARNING, "RPC_CLNT_PING notify failed");
  231         }
  232     }
  233 out:
  234     if (unref)
  235         rpc_clnt_unref(local->rpc);
  236 
  237     if (frame) {
  238         GF_FREE(frame->local);
  239         frame->local = NULL;
  240         STACK_DESTROY(frame->root);
  241     }
  242     return 0;
  243 }
  244 
  245 int
  246 rpc_clnt_ping(struct rpc_clnt *rpc)
  247 {
  248     call_frame_t *frame = NULL;
  249     int32_t ret = -1;
  250     rpc_clnt_connection_t *conn = NULL;
  251     struct ping_local *local = NULL;
  252 
  253     conn = &rpc->conn;
  254     local = GF_MALLOC(sizeof(struct ping_local), gf_common_ping_local_t);
  255     if (!local)
  256         return ret;
  257     frame = create_frame(THIS, THIS->ctx->pool);
  258     if (!frame) {
  259         GF_FREE(local);
  260         return ret;
  261     }
  262 
  263     local->rpc = rpc;
  264     timespec_now(&local->submit_time);
  265     frame->local = local;
  266 
  267     ret = rpc_clnt_submit(rpc, &clnt_ping_prog, GF_DUMP_PING, rpc_clnt_ping_cbk,
  268                           NULL, 0, NULL, 0, NULL, frame, NULL, 0, NULL, 0,
  269                           NULL);
  270     if (ret) {
  271         /* FIXME: should we free the frame here? Methinks so! */
  272         gf_log(THIS->name, GF_LOG_ERROR, "failed to start ping timer");
  273     } else {
  274         /* ping successfully queued in list of saved frames
  275          * for the connection*/
  276         pthread_mutex_lock(&conn->lock);
  277         conn->pingcnt++;
  278         pthread_mutex_unlock(&conn->lock);
  279     }
  280 
  281     return ret;
  282 }
  283 
  284 static void
  285 rpc_clnt_start_ping(void *rpc_ptr)
  286 {
  287     struct rpc_clnt *rpc = NULL;
  288     rpc_clnt_connection_t *conn = NULL;
  289     int frame_count = 0;
  290     int unref = 0;
  291 
  292     rpc = (struct rpc_clnt *)rpc_ptr;
  293     conn = &rpc->conn;
  294 
  295     if (conn->ping_timeout == 0) {
  296         gf_log(THIS->name, GF_LOG_DEBUG,
  297                "ping timeout is 0,"
  298                " returning");
  299         return;
  300     }
  301 
  302     pthread_mutex_lock(&conn->lock);
  303     {
  304         unref = rpc_clnt_remove_ping_timer_locked(rpc);
  305 
  306         if (conn->saved_frames) {
  307             GF_ASSERT(conn->saved_frames->count >= 0);
  308             /* treat the case where conn->saved_frames is NULL
  309                as no pending frames */
  310             frame_count = conn->saved_frames->count;
  311         }
  312 
  313         if ((frame_count == 0) || !conn->connected) {
  314             gf_log(THIS->name, GF_LOG_DEBUG,
  315                    "returning as transport is already disconnected"
  316                    " OR there are no frames (%d || %d)",
  317                    !conn->connected, frame_count);
  318 
  319             pthread_mutex_unlock(&conn->lock);
  320             if (unref)
  321                 rpc_clnt_unref(rpc);
  322             return;
  323         }
  324 
  325         if (__rpc_clnt_rearm_ping_timer(rpc, rpc_clnt_ping_timer_expired) ==
  326             -1) {
  327             gf_log(THIS->name, GF_LOG_WARNING, "unable to setup ping timer");
  328             pthread_mutex_unlock(&conn->lock);
  329             if (unref)
  330                 rpc_clnt_unref(rpc);
  331             return;
  332         }
  333     }
  334     pthread_mutex_unlock(&conn->lock);
  335     if (unref)
  336         rpc_clnt_unref(rpc);
  337 
  338     rpc_clnt_ping(rpc);
  339 }
  340 
  341 void
  342 rpc_clnt_check_and_start_ping(struct rpc_clnt *rpc)
  343 {
  344     char start_ping = 0;
  345 
  346     pthread_mutex_lock(&rpc->conn.lock);
  347     {
  348         if (!rpc->conn.ping_started)
  349             start_ping = 1;
  350     }
  351     pthread_mutex_unlock(&rpc->conn.lock);
  352 
  353     if (start_ping)
  354         rpc_clnt_start_ping((void *)rpc);
  355 
  356     return;
  357 }