1. 02 May, 2013 40 commits
    • Alex Elder's avatar
      libceph: no outbound zero data · 61fcdc97
      Alex Elder authored
      There is handling in write_partial_message_data() for the case where
      only the length of--and no other information about--the data to be
      sent has been specified.  It uses the zero page as the source of
      data to send in this case.
      
      This case doesn't occur.  All message senders set up a page array,
      pagelist, or bio describing the data to be sent.  So eliminate the
      block of code that handles this (but check and issue a warning for
      now, just in case it happens for some reason).
      
      This resolves:
          http://tracker.ceph.com/issues/4426Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      61fcdc97
    • Alex Elder's avatar
      libceph: use cursor for inbound data pages · 878efabd
      Alex Elder authored
      The cursor code for a page array selects the right page, page
      offset, and length to use for a ceph_tcp_recvpage() call, so
      we can use it to replace a block in read_partial_message_pages().
      
      This partially resolves:
          http://tracker.ceph.com/issues/4428Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      878efabd
    • Alex Elder's avatar
      libceph: kill ceph message bio_iter, bio_seg · 6518be47
      Alex Elder authored
      The bio_iter and bio_seg fields in a message are no longer used, we
      use the cursor instead.  So get rid of them and the functions that
      operate on them them.
      
      This is related to:
          http://tracker.ceph.com/issues/4428Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      6518be47
    • Alex Elder's avatar
      libceph: use cursor for bio reads · 463207aa
      Alex Elder authored
      Replace the use of the information in con->in_msg_pos for incoming
      bio data.  The old in_msg_pos and the new cursor mechanism do
      basically the same thing, just slightly differently.
      
      The main functional difference is that in_msg_pos keeps track of the
      length of the complete bio list, and assumed it was fully consumed
      when that many bytes had been transferred.  The cursor does not assume
      a length, it simply consumes all bytes in the bio list.  Because the
      only user of bio data is the rbd client, and because the length of a
      bio list provided by rbd client always matches the number of bytes
      in the list, both ways of tracking length are equivalent.
      
      In addition, for in_msg_pos the initial bio vector is selected as
      the initial value of the bio->bi_idx, while the cursor assumes this
      is zero.  Again, the rbd client always passes 0 as the initial index
      so the effect is the same.
      
      Other than that, they basically match:
          in_msg_pos      cursor
          ----------      ------
          bio_iter        bio
          bio_seg         vec_index
          page_pos        page_offset
      
      The in_msg_pos field is initialized by a call to init_bio_iter().
      The bio cursor is initialized by ceph_msg_data_cursor_init().
      Both now happen in the same spot, in prepare_message_data().
      
      The in_msg_pos field is advanced by a call to in_msg_pos_next(),
      which updates page_pos and calls iter_bio_next() to move to the next
      bio vector, or to the next bio in the list.  The cursor is advanced
      by ceph_msg_data_advance().  That isn't currently happening so
      add a call to that in in_msg_pos_next().
      
      Finally, the next piece of data to use for a read is determined
      by a bunch of lines in read_partial_message_bio().  Those can be
      replaced by an equivalent ceph_msg_data_bio_next() call.
      
      This partially resolves:
          http://tracker.ceph.com/issues/4428Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      463207aa
    • Alex Elder's avatar
      libceph: record residual bytes for all message data types · 25aff7c5
      Alex Elder authored
      All of the data types can use this, not just the page array.  Until
      now, only the bio type doesn't have it available, and only the
      initiator of the request (the rbd client) is able to supply the
      length of the full request without re-scanning the bio list.  Change
      the cursor init routines so the length is supplied based on the
      message header "data_len" field, and use that length to intiialize
      the "resid" field of the cursor.
      
      In addition, change the way "last_piece" is defined so it is based
      on the residual number of bytes in the original request.  This is
      necessary (at least for bio messages) because it is possible for
      a read request to succeed without consuming all of the space
      available in the data buffer.
      
      This resolves:
          http://tracker.ceph.com/issues/4427Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      25aff7c5
    • Alex Elder's avatar
      libceph: drop pages parameter · 28a89dde
      Alex Elder authored
      The value passed for "pages" in read_partial_message_pages() is
      always the pages pointer from the incoming message, which can be
      derived inside that function.  So just get rid of the parameter.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      28a89dde
    • Alex Elder's avatar
      libceph: initialize data fields on last msg put · 888334f9
      Alex Elder authored
      When the last reference to a ceph message is dropped,
      ceph_msg_last_put() is called to clean things up.
      
      For "normal" messages (allocated via ceph_msg_new() rather than
      being allocated from a memory pool) it's sufficient to just release
      resources.  But for a mempool-allocated message we actually have to
      re-initialize the data fields in the message back to initial state
      so they're ready to go in the event the message gets reused.
      
      Some of this was already done; this fleshes it out so it's done
      more completely.
      
      This resolves:
          http://tracker.ceph.com/issues/4540Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      888334f9
    • Alex Elder's avatar
      libceph: send queued requests when starting new one · 7e2766a1
      Alex Elder authored
      An osd expects the transaction ids of arriving request messages from
      a given client to a given osd to increase monotonically.  So the osd
      client needs to send its requests in ascending tid order.
      
      The transaction id for a request is set at the time it is
      registered, in __register_request().  This is also where the request
      gets placed at the end of the osd client's unsent messages list.
      
      At the end of ceph_osdc_start_request(), the request message for a
      newly-mapped osd request is supplied to the messenger to be sent
      (via __send_request()).  If any other messages were present in the
      osd client's unsent list at that point they would be sent *after*
      this new request message.
      
      Because those unsent messages have already been registered, their
      tids would be lower than the newly-mapped request message, and
      sending that message first can violate the tid ordering rule.
      
      Rather than sending the new request only, send all queued requests
      (including the new one) at that point in ceph_osdc_start_request().
      This ensures the tid ordering property is preserved.
      
      With this in place, all messages should now be sent in tid order
      regardless of whether they're being sent for the first time or
      re-sent as a result of a call to osd_reset().
      
      This resolves:
          http://tracker.ceph.com/issues/4392Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-off-by: default avatarSage Weil <sage@inktank.com>
      7e2766a1
    • Alex Elder's avatar
      libceph: keep request lists in tid order · ad885927
      Alex Elder authored
      In __map_request(), when adding a request to an osd client's unsent
      list, add it to the tail rather than the head.  That way the newest
      entries (with the highest tid value) will be last.
      
      Maintain an osd's request list in order of increasing tid also.
      
      Finally--to be consistent--maintain an osd client's "notarget" list
      in that order as well.
      
      This partially resolves:
          http://tracker.ceph.com/issues/4392Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-off-by: default avatarSage Weil <sage@inktank.com>
      ad885927
    • Alex Elder's avatar
      libceph: requeue only sent requests when kicking · e02493c0
      Alex Elder authored
      The osd expects incoming requests for a given object from a given
      client to arrive in order, with the tid for each request being
      greater than the tid for requests that have already arrived.  This
      patch fixes two places the osd client might not maintain that
      ordering.
      
      For the osd client, the connection fault method is osd_reset().
      That function calls __reset_osd() to close and re-open the
      connection, then calls __kick_osd_requests() to cause all
      outstanding requests for the affected osd to be re-sent after
      the connection has been re-established.
      
      When an osd is reset, any in-flight messages will need to be
      re-sent.  An osd client maintains distinct lists for unsent and
      in-flight messages.  Meanwhile, an osd maintains a single list of
      all its requests (both sent and un-sent).  (Each message is linked
      into two lists--one for the osd client and one list for the osd.)
      
      To process an osd "kick" operation, the request list for the *osd*
      is traversed, and each request is moved off whichever osd *client*
      list it was on (unsent or sent) and placed onto the osd client's
      unsent list.  (It remains where it is on the osd's request list.)
      
      When that is done, osd_reset() calls __send_queued() to cause each
      of the osd client's unsent messages to be sent.
      
      OK, with that background...
      
      As the osd request list is traversed each request is prepended to
      the osd client's unsent list in the order they're seen.  The effect
      of this is to reverse the order of these requests as they are put
      (back) onto the unsent list.
      
      Instead, build up a list of only the requests for an osd that have
      already been sent (by checking their r_sent flag values).  Once an
      unsent request is found, stop examining requests and prepend the
      requests that need re-sending to the osd client's unsent list.
      
      Preserve the original order of requests in the process (previously
      re-queued requests were reversed in this process).  Because they
      have already been sent, they will have lower tids than any request
      already present on the unsent list.
      
      Just below that, traverse the linger list in forward order as
      before, but add them to the *tail* of the list rather than the head.
      These requests get re-registered, and in the process are give a new
      (higher) tid, so the should go at the end.
      
      This partially resolves:
          http://tracker.ceph.com/issues/4392Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-off-by: default avatarSage Weil <sage@inktank.com>
      e02493c0
    • Alex Elder's avatar
      libceph: no more kick_requests() race · 92451b49
      Alex Elder authored
      Since we no longer drop the request mutex between registering and
      mapping an osd request in ceph_osdc_start_request(), there is no
      chance of a race with kick_requests().
      
      We can now therefore map and send the new request unconditionally
      (but we'll issue a warning should it ever occur).
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-off-by: default avatarSage Weil <sage@inktank.com>
      92451b49
    • Alex Elder's avatar
      libceph: slightly defer registering osd request · dc4b870c
      Alex Elder authored
      One of the first things ceph_osdc_start_request() does is register
      the request.  It then acquires the osd client's map semaphore and
      request mutex and proceeds to map and send the request.
      
      There is no reason the request has to be registered before acquiring
      the map semaphore.  So hold off doing so until after the map
      semaphore is held.
      
      Since register_request() is nothing more than a wrapper around
      __register_request(), call the latter function instead, after
      acquiring the request mutex.
      
      That leaves register_request() unused, so get rid of it.
      
      This partially resolves:
          http://tracker.ceph.com/issues/4392Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-off-by: default avatarSage Weil <sage@inktank.com>
      dc4b870c
    • Sage Weil's avatar
      libceph: wrap auth methods in a mutex · e9966076
      Sage Weil authored
      The auth code is called from a variety of contexts, include the mon_client
      (protected by the monc's mutex) and the messenger callbacks (currently
      protected by nothing).  Avoid chaos by protecting all auth state with a
      mutex.  Nothing is blocking, so this should be simple and lightweight.
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      e9966076
    • Sage Weil's avatar
      libceph: wrap auth ops in wrapper functions · 27859f97
      Sage Weil authored
      Use wrapper functions that check whether the auth op exists so that callers
      do not need a bunch of conditional checks.  Simplifies the external
      interface.
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      27859f97
    • Sage Weil's avatar
      libceph: add update_authorizer auth method · 0bed9b5c
      Sage Weil authored
      Currently the messenger calls out to a get_authorizer con op, which will
      create a new authorizer if it doesn't yet have one.  In the meantime, when
      we rotate our service keys, the authorizer doesn't get updated.  Eventually
      it will be rejected by the server on a new connection attempt and get
      invalidated, and we will then rebuild a new authorizer, but this is not
      ideal.
      
      Instead, if we do have an authorizer, call a new update_authorizer op that
      will verify that the current authorizer is using the latest secret.  If it
      is not, we will build a new one that does.  This avoids the transient
      failure.
      
      This fixes one of the sorry sequence of events for bug
      
      	http://tracker.ceph.com/issues/4282Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      0bed9b5c
    • Sage Weil's avatar
      libceph: fix authorizer invalidation · 4b8e8b5d
      Sage Weil authored
      We were invalidating the authorizer by removing the ticket handler
      entirely.  This was effective in inducing us to request a new authorizer,
      but in the meantime it mean that any authorizer we generated would get a
      new and initialized handler with secret_id=0, which would always be
      rejected by the server side with a confusing error message:
      
       auth: could not find secret_id=0
       cephx: verify_authorizer could not get service secret for service osd secret_id=0
      
      Instead, simply clear the validity field.  This will still induce the auth
      code to request a new secret, but will let us continue to use the old
      ticket in the meantime.  The messenger code will probably continue to fail,
      but the exponential backoff will kick in, and eventually the we will get a
      new (hopefully more valid) ticket from the mon and be able to continue.
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      4b8e8b5d
    • Sage Weil's avatar
      libceph: clear messenger auth_retry flag when we authenticate · 20e55c4c
      Sage Weil authored
      We maintain a counter of failed auth attempts to allow us to retry once
      before failing.  However, if the second attempt succeeds, the flag isn't
      cleared, which makes us think auth failed again later when the connection
      resets for other reasons (like a socket error).
      
      This is one part of the sorry sequence of events in bug
      
      	http://tracker.ceph.com/issues/4282Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      20e55c4c
    • Sage Weil's avatar
      libceph: implement RECONNECT_SEQ feature · 3a23083b
      Sage Weil authored
      This is an old protocol extension that allows the client and server to
      avoid resending old messages after a reconnect (following a socket error).
      Instead, the exchange their sequence numbers during the handshake.  This
      avoids sending a bunch of useless data over the socket.
      
      It has been supported in the server code since v0.22 (Sep 2010).
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      3a23083b
    • Henry C Chang's avatar
      ceph: fix buffer pointer advance in ceph_sync_write · 022f3e2e
      Henry C Chang authored
      We should advance the user data pointer by _len_ instead of _written_.
      _len_ is the data length written in each iteration while _written_ is the
      accumulated data length we have writtent out.
      Signed-off-by: default avatarHenry C Chang <henry.cy.chang@gmail.com>
      Reviewed-by: default avatarGreg Farnum <greg@inktank.com>
      Tested-by: default avatarSage Weil <sage@inktank.com>
      022f3e2e
    • Yan, Zheng's avatar
      ceph: use i_release_count to indicate dir's completeness · 2f276c51
      Yan, Zheng authored
      Current ceph code tracks directory's completeness in two places.
      ceph_readdir() checks i_release_count to decide if it can set the
      I_COMPLETE flag in i_ceph_flags. All other places check the I_COMPLETE
      flag. This indirection introduces locking complexity.
      
      This patch adds a new variable i_complete_count to ceph_inode_info.
      Set i_release_count's value to it when marking a directory complete.
      By comparing the two variables, we know if a directory is complete
      Signed-off-by: default avatarYan, Zheng <zheng.z.yan@intel.com>
      2f276c51
    • Alex Elder's avatar
      libceph: more cleanup of write_partial_msg_pages() · 8a166d05
      Alex Elder authored
      Basically all cases in write_partial_msg_pages() use the cursor, and
      as a result we can simplify that function quite a bit.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      8a166d05
    • Alex Elder's avatar
      libceph: kill message trail · 9d2a06c2
      Alex Elder authored
      The wart that is the ceph message trail can now be removed, because
      its only user was the osd client, and the previous patch made that
      no longer the case.
      
      The result allows write_partial_msg_pages() to be simplified
      considerably.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      9d2a06c2
    • Alex Elder's avatar
      libceph: kill osd request r_trail · 95e072eb
      Alex Elder authored
      The osd trail is a pagelist, used only for a CALL osd operation
      to hold the class and method names, along with any input data for
      the call.
      
      It is only currently used by the rbd client, and when it's used it
      is the only bit of outbound data in the osd request.  Since we
      already support (non-trail) pagelist data in a message, we can
      just save this outbound CALL data in the "normal" pagelist rather
      than the trail, and get rid of the trail entirely.
      
      The existing pagelist support depends on the pagelist being
      dynamically allocated, and ownership of it is passed to the
      messenger once it's been attached to a message.  (That is to say,
      the messenger releases and frees the pagelist when it's done with
      it).  That means we need to dynamically allocate the pagelist also.
      
      Note that we simply assert that the allocation of a pagelist
      structure succeeds.  Appending to a pagelist might require a dynamic
      allocation, so we're already assuming we won't run into trouble
      doing so (we're just ignore any failures--and that should be fixed
      at some point).
      
      This resolves:
          http://tracker.ceph.com/issues/4407Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      95e072eb
    • Alex Elder's avatar
      libceph: have osd requests support pagelist data · 9a5e6d09
      Alex Elder authored
      Add support for recording a ceph pagelist as data associated with an
      osd request.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      9a5e6d09
    • Alex Elder's avatar
      libceph: let osd ops determine request data length · 175face2
      Alex Elder authored
      The length of outgoing data in an osd request is dependent on the
      osd ops that are embedded in that request.  Each op is encoded into
      a request message using osd_req_encode_op(), so that should be used
      to determine the amount of outgoing data implied by the op as it
      is encoded.
      
      Have osd_req_encode_op() return the number of bytes of outgoing data
      implied by the op being encoded, and accumulate and use that in
      ceph_osdc_build_request().
      
      As a result, ceph_osdc_build_request() no longer requires its "len"
      parameter, so get rid of it.
      
      Using the sum of the op lengths rather than the length provided is
      a valid change because:
          - The only callers of osd ceph_osdc_build_request() are
            rbd and the osd client (in ceph_osdc_new_request() on
            behalf of the file system).
          - When rbd calls it, the length provided is only non-zero for
            write requests, and in that case the single op has the
            same length value as what was passed here.
          - When called from ceph_osdc_new_request(), (it's not all that
            easy to see, but) the length passed is also always the same
            as the extent length encoded in its (single) write op if
            present.
      
      This resolves:
          http://tracker.ceph.com/issues/4406Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      175face2
    • Alex Elder's avatar
      libceph: implement pages array cursor · e766d7b5
      Alex Elder authored
      Implement and use cursor routines for page array message data items
      for outbound message data.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      e766d7b5
    • Alex Elder's avatar
      libceph: implement bio message data item cursor · 6aaa4511
      Alex Elder authored
      Implement and use cursor routines for bio message data items for
      outbound message data.
      
      (See the previous commit for reasoning in support of the changes
      in out_msg_pos_next().)
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      6aaa4511
    • Alex Elder's avatar
      libceph: use data cursor for message pagelist · 7fe1e5e5
      Alex Elder authored
      Switch to using the message cursor for the (non-trail) outgoing
      pagelist data item in a message if present.
      
      Notes on the logic changes in out_msg_pos_next():
          - only the mds client uses a ceph pagelist for message data;
          - if the mds client ever uses a pagelist, it never uses a page
            array (or anything else, for that matter) for data in the same
            message;
          - only the osd client uses the trail portion of a message data,
            and when it does, it never uses any other data fields for
            outgoing data in the same message; and finally
          - only the rbd client uses bio message data (never pagelist).
      
      Therefore out_msg_pos_next() can assume:
          - if we're in the trail portion of a message, the message data
            pagelist, data, and bio can be ignored; and
          - if there is a page list, there will never be any a bio or page
            array data, and vice-versa.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      7fe1e5e5
    • Alex Elder's avatar
      libceph: prepare for other message data item types · dd236fcb
      Alex Elder authored
      This just inserts some infrastructure in preparation for handling
      other types of ceph message data items.  No functional changes,
      just trying to simplify review by separating out some noise.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      dd236fcb
    • Alex Elder's avatar
      libceph: start defining message data cursor · fe38a2b6
      Alex Elder authored
      This patch lays out the foundation for using generic routines to
      manage processing items of message data.
      
      For simplicity, we'll start with just the trail portion of a
      message, because it stands alone and is only present for outgoing
      data.
      
      First some basic concepts.  We'll use the term "data item" to
      represent one of the ceph_msg_data structures associated with a
      message.  There are currently four of those, with single-letter
      field names p, l, b, and t.  A data item is further broken into
      "pieces" which always lie in a single page.  A data item will
      include a "cursor" that will track state as the memory defined by
      the item is consumed by sending data from or receiving data into it.
      
      We define three routines to manipulate a data item's cursor: the
      "init" routine; the "next" routine; and the "advance" routine.  The
      "init" routine initializes the cursor so it points at the beginning
      of the first piece in the item.  The "next" routine returns the
      page, page offset, and length (limited by both the page and item
      size) of the next unconsumed piece in the item.  It also indicates
      to the caller whether the piece being returned is the last one in
      the data item.
      
      The "advance" routine consumes the requested number of bytes in the
      item (advancing the cursor).  This is used to record the number of
      bytes from the current piece that were actually sent or received by
      the network code.  It returns an indication of whether the result
      means the current piece has been fully consumed.  This is used by
      the message send code to determine whether it should calculate the
      CRC for the next piece processed.
      
      The trail of a message is implemented as a ceph pagelist.  The
      routines defined for it will be usable for non-trail pagelist data
      as well.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      fe38a2b6
    • Alex Elder's avatar
      libceph: abstract message data · 43794509
      Alex Elder authored
      Group the types of message data into an abstract structure with a
      type indicator and a union containing fields appropriate to the
      type of data it represents.  Use this to represent the pages,
      pagelist, bio, and trail in a ceph message.
      
      Verify message data is of type NONE in ceph_msg_data_set_*()
      routines.  Since information about message data of type NONE really
      should not be interpreted, get rid of the other assertions in those
      functions.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      43794509
    • Alex Elder's avatar
      libceph: be explicit about message data representation · f9e15777
      Alex Elder authored
      A ceph message has a data payload portion.  The memory for that data
      (either the source of data to send or the location to place data
      that is received) is specified in several ways.  The ceph_msg
      structure includes fields for all of those ways, but this
      mispresents the fact that not all of them are used at a time.
      
      Specifically, the data in a message can be in:
          - an array of pages
          - a list of pages
          - a list of Linux bios
          - a second list of pages (the "trail")
      (The two page lists are currently only ever used for outgoing data.)
      
      Impose more structure on the ceph message, making the grouping of
      some of these fields explicit.  Shorten the name of the
      "page_alignment" field.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      f9e15777
    • Alex Elder's avatar
      libceph: define ceph_msg_has_*() data macros · 97fb1c7f
      Alex Elder authored
      Define and use macros ceph_msg_has_*() to determine whether to
      operate on the pages, pagelist, bio, and trail fields of a message.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      97fb1c7f
    • Alex Elder's avatar
      libceph: define and use ceph_crc32c_page() · 35b62808
      Alex Elder authored
      Factor out a common block of code that updates a CRC calculation
      over a range of data in a page.
      
      This and the preceding patches are related to:
          http://tracker.ceph.com/issues/4403Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      35b62808
    • Alex Elder's avatar
      libceph: define and use ceph_tcp_recvpage() · afb3d90e
      Alex Elder authored
      Define a new function ceph_tcp_recvpage() that behaves in a way
      comparable to ceph_tcp_sendpage().
      
      Rearrange the code in both read_partial_message_pages() and
      read_partial_message_bio() so they have matching structure,
      (similar to what's in write_partial_msg_pages()), and use
      this new function.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      afb3d90e
    • Alex Elder's avatar
      libceph: encapsulate reading message data · 34d2d200
      Alex Elder authored
      Pull the code that reads the data portion into a message into
      a separate function read_partial_msg_data().
      
      Rename write_partial_msg_pages() to be write_partial_message_data()
      to match its read counterpart, and to reflect its more generic
      purpose.
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      34d2d200
    • Alex Elder's avatar
      libceph: small write_partial_msg_pages() refactor · e387d525
      Alex Elder authored
      Define local variables page_offset and length to represent the range
      of bytes within a page that will be sent by ceph_tcp_sendpage() in
      write_partial_msg_pages().
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      e387d525
    • Alex Elder's avatar
      libceph: consolidate message prep code · 78625051
      Alex Elder authored
      In prepare_write_message_data(), various fields are initialized in
      preparation for writing message data out.  Meanwhile, in
      read_partial_message(), there is essentially the same block of code,
      operating on message variables associated with an incoming message.
      
      Generalize prepare_write_message_data() so it works for both
      incoming and outcoming messages, and use it in both spots.  The
      did_page_crc is not used for input (so it's harmless to initialize
      it).
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      78625051
    • Alex Elder's avatar
      libceph: use local variables for message positions · bae6acd9
      Alex Elder authored
      There are several places where a message's out_msg_pos or in_msg_pos
      field is used repeatedly within a function.  Use a local pointer
      variable for this purpose to unclutter the code.
      
      This and the upcoming cleanup patches are related to:
          http://tracker.ceph.com/issues/4403Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      bae6acd9
    • Alex Elder's avatar
      libceph: don't clear bio_iter in prepare_write_message() · 98a03708
      Alex Elder authored
      At one time it was necessary to clear a message's bio_iter field to
      avoid a bad pointer dereference in write_partial_msg_pages().
      
      That no longer seems to be the case.  Here's why.
      
      The message's bio fields represent (in this case) outgoing data.
      Between where the bio_iter is made NULL in prepare_write_message()
      and the call in that function to prepare_message_data(), the
      bio fields are never used.
      
      In prepare_message_data(), init-bio_iter() is called, and the result
      of that overwrites the value in the message's bio_iter field.
      
      Because it gets overwritten anyway, there is no need to set it to
      NULL.  So don't do it.
      
      This resolves:
          http://tracker.ceph.com/issues/4402Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      98a03708