Skip to content
  1. Oct 27, 2012
  2. Oct 10, 2012
    • Alex Elder's avatar
      rbd: activate v2 image support · 35152979
      Alex Elder authored
      
      
      Now that v2 images support is fully implemented, have
      rbd_dev_v2_probe() return 0 to indicate a successful probe.
      
      (Note that an image that implements layering will fail
      the probe early because of the feature chekc.)
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      35152979
    • Alex Elder's avatar
      rbd: implement feature checks · d889140c
      Alex Elder authored
      
      
      Version 2 images have two sets of feature bit fields.  The first
      indicates features possibly used by the image.  The second indicates
      features that the client *must* support in order to use the image.
      
      When an image (or snapshot) is first examined, we need to make sure
      that the local implementation supports the image's required
      features.  If not, fail the probe for the image.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      d889140c
    • Alex Elder's avatar
      rbd: define rbd_dev_v2_refresh() · 117973fb
      Alex Elder authored
      
      
      Define a new function rbd_dev_v2_refresh() to update/refresh the
      snapshot context for a format version 2 rbd image.  This function
      will update anything that is not fixed for the life of an rbd
      image--at the moment this is mainly the snapshot context and (for
      a base mapping) the size.
      
      Update rbd_refresh_header() so it selects which function to use
      based on the image format.
      
      Rename __rbd_refresh_header() to be rbd_dev_v1_refresh()
      to be consistent with the naming of its version 2 counterpart.
      Similarly rename rbd_refresh_header() to be rbd_dev_refresh().
      
      Unrelated--we use rbd_image_format_valid() here.  Delete the other
      use of it, which was primarily put in place to ensure that function
      was referenced at the time it was defined.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      117973fb
    • Alex Elder's avatar
      rbd: define rbd_update_mapping_size() · 9478554a
      Alex Elder authored
      
      
      Encapsulate the code that handles updating the size of a mapping
      after an rbd image has been refreshed.  This is done in anticipation
      of the next patch, which will make this common code for format 1 and
      2 images.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      9478554a
    • Alex Elder's avatar
      rbd: define common queue_con_delay() · 802c6d96
      Alex Elder authored
      
      
      This patch defines a single function, queue_con_delay() to call
      queue_delayed_work() for a connection.  It basically generalizes
      what was previously queue_con() by adding the delay argument.
      queue_con() is now a simple helper that passes 0 for its delay.
      queue_con_delay() returns 0 if it queued work or an errno if it
      did not for some reason.
      
      If con_work() finds the BACKOFF flag set for a connection, it now
      calls queue_con_delay() to handle arranging to start again after a
      delay.
      
      Note about connection reference counts:  con_work() only ever gets
      called as a work item function.  At the time that work is scheduled,
      a reference to the connection is acquired, and the corresponding
      con_work() call is then responsible for dropping that reference
      before it returns.
      
      Previously, the backoff handling inside con_work() silently handed
      off its reference to delayed work it scheduled.  Now that
      queue_con_delay() is used, a new reference is acquired for the
      newly-scheduled work, and the original reference is dropped by the
      con->ops->put() call at the end of the function.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarSage Weil <sage@inktank.com>
      802c6d96
    • Alex Elder's avatar
      rbd: let con_work() handle backoff · 8618e30b
      Alex Elder authored
      
      
      Both ceph_fault() and con_work() include handling for imposing a
      delay before doing further processing on a faulted connection.
      The latter is used only if ceph_fault() is unable to.
      
      Instead, just let con_work() always be responsible for implementing
      the delay.  After setting up the delay value, set the BACKOFF flag
      on the connection unconditionally and call queue_con() to ensure
      con_work() will get called to handle it.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarSage Weil <sage@inktank.com>
      8618e30b
    • Alex Elder's avatar
      rbd: reset BACKOFF if unable to re-queue · 588377d6
      Alex Elder authored
      
      
      If ceph_fault() is unable to queue work after a delay, it sets the
      BACKOFF connection flag so con_work() will attempt to do so.
      
      In con_work(), when BACKOFF is set, if queue_delayed_work() doesn't
      result in newly-queued work, it simply ignores this condition and
      proceeds as if no backoff delay were desired.  There are two
      problems with this--one of which is a bug.
      
      The first problem is simply that the intended behavior is to back
      off, and if we aren't able queue the work item to run after a delay
      we're not doing that.
      
      The only reason queue_delayed_work() won't queue work is if the
      provided work item is already queued.  In the messenger, this
      means that con_work() is already scheduled to be run again.  So
      if we simply set the BACKOFF flag again when this occurs, we know
      the next con_work() call will again attempt to hold off activity
      on the connection until after the delay.
      
      The second problem--the bug--is a leak of a reference count.  If
      queue_delayed_work() returns 0 in con_work(), con->ops->put() drops
      the connection reference held on entry to con_work().  However,
      processing is (was) allowed to continue, and at the end of the
      function a second con->ops->put() is called.
      
      This patch fixes both problems.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarSage Weil <sage@inktank.com>
      588377d6
  3. Oct 03, 2012
  4. Oct 02, 2012
    • Sage Weil's avatar
      rbd: BUG on invalid layout · 6cae3717
      Sage Weil authored
      
      
      This shouldn't actually be possible because the layout struct is
      constructed from the RBD header and validated then.
      
      [elder@inktank.com: converted BUG() call to equivalent rbd_assert()]
      
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      6cae3717
    • Sage Weil's avatar
      ceph: propagate layout error on osd request creation · 6816282d
      Sage Weil authored
      
      
      If we are creating an osd request and get an invalid layout, return
      an EINVAL to the caller.  We switch up the return to have an error
      code instead of NULL implying -ENOMEM.
      
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      6816282d
    • Sage Weil's avatar
      libceph: check for invalid mapping · d63b77f4
      Sage Weil authored
      
      
      If we encounter an invalid (e.g., zeroed) mapping, return an error
      and avoid a divide by zero.
      
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      Reviewed-by: default avatarAlex Elder <elder@inktank.com>
      d63b77f4
    • Wei Yongjun's avatar
      ceph: convert to use le32_add_cpu() · b905a7f8
      Wei Yongjun authored
      
      
      Convert cpu_to_le32(le32_to_cpu(E1) + E2) to use le32_add_cpu().
      
      dpatch engine is used to auto generate this patch.
      (https://github.com/weiyj/dpatch)
      
      Signed-off-by: default avatarWei Yongjun <yongjun_wei@trendmicro.com.cn>
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      b905a7f8
    • Yan, Zheng's avatar
      ceph: Fix oops when handling mdsmap that decreases max_mds · 3e8f43a0
      Yan, Zheng authored
      
      
      When i >= newmap->m_max_mds, ceph_mdsmap_get_addr(newmap, i) return
      NULL. Passing NULL to memcmp() triggers oops.
      
      Signed-off-by: default avatarYan, Zheng <zheng.z.yan@intel.com>
      Signed-off-by: default avatarSage Weil <sage@inktank.com>
      3e8f43a0
    • Alex Elder's avatar
      rbd: update remaining header fields for v2 · 6e14b1a6
      Alex Elder authored
      
      
      There are three fields that are not yet updated for format 2 rbd
      image headers:  the version of the header object; the encryption
      type; and the compression type.  There is no interface defined for
      fetching the latter two, so just initialize them explicitly to 0 for
      now.
      
      Change rbd_dev_v2_snap_context() so the caller can be supplied the
      version for the header object.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      6e14b1a6
    • Alex Elder's avatar
      rbd: get snapshot name for a v2 image · b8b1e2db
      Alex Elder authored
      
      
      Define rbd_dev_v2_snap_name() to fetch the name for a particular
      snapshot in a format 2 rbd image.
      
      Define rbd_dev_v2_snap_info() to to be a wrapper for getting the
      name, size, and features for a particular snapshot, using an
      interface that matches the equivalent function for version 1 images.
      
      Define rbd_dev_snap_info() wrapper function and use it to call the
      appropriate function for getting the snapshot name, size, and
      features, dependent on the rbd image format.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      b8b1e2db
    • Alex Elder's avatar
      rbd: get the snapshot context for a v2 image · 35d489f9
      Alex Elder authored
      
      
      Fetch the snapshot context for an rbd format 2 image by calling
      the "get_snapcontext" method on its header object.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      35d489f9
    • Alex Elder's avatar
      rbd: get image features for a v2 image · b1b5402a
      Alex Elder authored
      
      
      The features values for an rbd format 2 image are fetched from the
      server using a "get_features" method.  The same method is used for
      getting the features for a snapshot, so structure this addition with
      a generic helper routine that can get this information for either.
      
      The server will provide two 64-bit feature masks, one representing
      the features potentially in use for this image (or its snapshot),
      and one representing features that must be supported by the client
      in order to work with the image.
      
      For the time being, neither of these is really used so we keep
      things simple and just record the first feature vector.  Once we
      start using these feature masks, what we record and what we expose
      to the user will most likely change.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      b1b5402a
    • Alex Elder's avatar
      rbd: get the object prefix for a v2 rbd image · 1e130199
      Alex Elder authored
      
      
      The object prefix of an rbd format 2 image is fetched from the
      server using a "get_object_prefix" method.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      1e130199
    • Alex Elder's avatar
      rbd: add code to get the size of a v2 rbd image · 9d475de5
      Alex Elder authored
      
      
      The size of an rbd format 2 image is fetched from the server using a
      "get_size" method.  The same method is used for getting the size of
      a snapshot, so structure this addition with a generic helper routine
      that we can get this information for either.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      9d475de5
    • Alex Elder's avatar
      rbd: lay out header probe infrastructure · a30b71b9
      Alex Elder authored
      
      
      This defines a new function rbd_dev_probe() as a top-level
      function for populating detailed information about an rbd device.
      
      It first checks for the existence of a format 2 rbd image id object.
      If it exists, the image is assumed to be a format 2 rbd image, and
      another function rbd_dev_v2() is called to finish populating
      header data for that image.  If it does not exist, it is assumed to
      be an old (format 1) rbd image, and calls a similar function
      rbd_dev_v1() to populate its header information.
      
      A new field, rbd_dev->format, is defined to record which version
      of the rbd image format the device represents.  For a valid mapped
      rbd device it will have one of two values, 1 or 2.
      
      So far, the format 2 images are not really supported; this is
      laying out the infrastructure for fleshing out that support.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      a30b71b9
    • Alex Elder's avatar
      rbd: encapsulate code that gets snapshot info · cd892126
      Alex Elder authored
      
      
      Create a function that encapsulates looking up the name, size and
      features related to a given snapshot, which is indicated by its
      index in an rbd device's snapshot context array of snapshot ids.
      
      This interface will be used to hide differences between the format 1
      and format 2 images.
      
      At the moment this (looking up the name anyway) is slightly less
      efficient than what's done currently, but we may be able to optimize
      this a bit later on by cacheing the last lookup if it proves to be a
      problem.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      cd892126
    • Alex Elder's avatar
      rbd: add an rbd features field · 34b13184
      Alex Elder authored
      
      
      Record the features values for each rbd image and each of its
      snapshots.  This is really something that only becomes meaningful
      for version 2 images, so this is just putting in place code
      that will form common infrastructure.
      
      It may be useful to expand the sysfs entries--and therefore the
      information we maintain--for the image and for each snapshot.
      But I'm going to hold off doing that until we start making
      active use of the feature bits.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      34b13184
    • Alex Elder's avatar
      rbd: don't use index in __rbd_add_snap_dev() · c8d18425
      Alex Elder authored
      
      
      Pass the snapshot id and snapshot size rather than an index
      to __rbd_add_snap_dev() to specify values for a new snapshot.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      c8d18425
    • Alex Elder's avatar
      rbd: kill create_snap sysfs entry · 02cdb02c
      Alex Elder authored
      
      
      Josh proposed the following change, and I don't think I could
      explain it any better than he did:
      
          From: Josh Durgin <josh.durgin@inktank.com>
          Date: Tue, 24 Jul 2012 14:22:11 -0700
          To: ceph-devel <ceph-devel@vger.kernel.org>
          Message-ID: <500F1203.9050605@inktank.com>
      
          Right now the kernel still has one piece of rbd management
          duplicated from the rbd command line tool: snapshot creation.
          There's nothing special about snapshot creation that makes it
          advantageous to do from the kernel, so I'd like to remove the
          create_snap sysfs interface.  That is,
      	/sys/bus/rbd/devices/<id>/create_snap
          would be removed.
      
          Does anyone rely on the sysfs interface for creating rbd
          snapshots?  If so, how hard would it be to replace with:
      
      	rbd snap create pool/image@snap
      
          Is there any benefit to the sysfs interface that I'm missing?
      
          Josh
      
      This patch implements this proposal, removing the code that
      implements the "snap_create" sysfs interface for rbd images.
      As a result, quite a lot of other supporting code goes away.
      
      Suggested-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      02cdb02c
    • Alex Elder's avatar
      rbd: define rbd_dev_image_id() · 589d30e0
      Alex Elder authored
      
      
      New format 2 rbd images are permanently identified by a unique image
      id.  Each rbd image also has a name, but the name can be changed.
      A format 2 rbd image will have an object--whose name is based on the
      image name--which maps an image's name to its image id.
      
      Create a new function rbd_dev_image_id() that checks for the
      existence of the image id object, and if it's found, records the
      image id in the rbd_device structure.
      
      Create a new rbd device attribute (/sys/bus/rbd/<num>/image_id) that
      makes this information available.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      589d30e0
    • Alex Elder's avatar
      rbd: define some new format constants · 3bb59ad5
      Alex Elder authored
      
      
      Define constant symbols related to the rbd format 2 object names.
      This begins to bring this version of the "rbd_types.h" header
      more in line with the current user-space version of that file.
      Complete reconciliation of differences will be done at some
      point later, as a separate task.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      3bb59ad5
    • Alex Elder's avatar
      rbd: support data returned from OSD methods · f8d4de6e
      Alex Elder authored
      
      
      An OSD object method call can be made using rbd_req_sync_exec().
      Until now this has only been used for creating a new RBD snapshot,
      and that has only required sending data out, not receiving anything
      back from the OSD.
      
      We will now need to get data back from an OSD on a method call, so
      add parameters to rbd_req_sync_exec() that allow a buffer into which
      returned data should be placed to be specified, along with its size.
      
      Previously, rbd_req_sync_exec() passed a null pointer and zero
      size to rbd_req_sync_op(); change this so the new inbound buffer
      information is provided instead.
      
      Rename the "buf" and "len" parameters in rbd_req_sync_op() to
      make it more obvious they are describing inbound data.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      f8d4de6e
    • Alex Elder's avatar
      rbd: pass flags to rbd_req_sync_exec() · 3cb4a687
      Alex Elder authored
      
      
      In order to allow both read requests and write requests to be
      initiated using rbd_req_sync_exec(), add an OSD flags value
      which can be passed down to rbd_req_sync_op().  Rename the "data"
      and "len" parameters to be more clear that they represent data
      that is outbound.
      
      At this point, this function is still only used (and only works) for
      write requests.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      3cb4a687
    • Alex Elder's avatar
      rbd: set up watch before announcing disk · 3ee4001e
      Alex Elder authored
      
      
      We're ready to handle header object (refresh) events at the point we
      call rbd_bus_add_dev().  Set up the watch request on the rbd image
      header just after that, and after we've registered the devices for
      the snapshots for the initial snapshot context.  Do this before
      announce the disk as available for use.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      3ee4001e
    • Alex Elder's avatar
      rbd: set initial capacity in rbd_init_disk() · 12f02944
      Alex Elder authored
      
      
      Move the setting of the initial capacity for an rbd image mapping
      into rb_init_disk().
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      12f02944
    • Alex Elder's avatar
      rbd: drop dev registration check for new snap · 86ff77bb
      Alex Elder authored
      
      
      By the time rbd_dev_snaps_register() gets called during rbd device
      initialization, the main device will have already been registered.
      Similarly, a header refresh will only occur for an rbd device whose
      Linux device is registered.  There is therefore no need to verify
      the main device is registered when registering a snapshot device.
      
      For the time being, turn the check into a WARN_ON(), but it can
      eventually just go away.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      86ff77bb
    • Alex Elder's avatar
      rbd: call rbd_init_disk() sooner · 0f308a31
      Alex Elder authored
      
      
      Call rbd_init_disk() from rbd_add() as soon as we have the major
      device number for the mapping.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      0f308a31
    • Alex Elder's avatar
      rbd: defer setting device id · 85ae8926
      Alex Elder authored
      
      
      Hold off setting the device id and formatting the device name
      in rbd_add() until just before it's needed.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      85ae8926
    • Alex Elder's avatar
      rbd: read the header before registering device · 05fd6f6f
      Alex Elder authored
      
      
      Read the rbd header information and call rbd_dev_set_mapping()
      earlier--before registering the block device or setting up the sysfs
      entries for the image.  The sysfs entries provide users access to
      some information that's only available after doing the rbd header
      initialization, so this will make sure it's valid right away.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      05fd6f6f
    • Alex Elder's avatar
      rbd: call set_snap() before snap_devs_update() · 5ed16177
      Alex Elder authored
      
      
      rbd_header_set_snap() is a simple initialization routine for an rbd
      device's mapping.  It has to be called after the snapshot context
      for the rbd_dev has been updated, but can be done before snapshot
      devices have been registered.
      
      Change the name to rbd_dev_set_mapping() to better reflect its
      purpose, and call it a little sooner, before registering snapshot
      devices.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      5ed16177
    • Alex Elder's avatar
      rbd: defer registering snapshot devices · 304f6808
      Alex Elder authored
      
      
      When a new snapshot is found in an rbd device's updated snapshot
      context, __rbd_add_snap_dev() is called to create and insert an
      entry in the rbd devices list of snapshots.  In addition, a Linux
      device is registered to represent the snapshot.
      
      For version 2 rbd images, it will be undesirable to initialize the
      device right away.  So in anticipation of that, this patch separates
      the insertion of a snapshot entry in the snaps list from the
      creation of devices for those snapshots.
      
      To do this, create a new function rbd_dev_snaps_register() which
      traverses the list of snapshots and calls rbd_register_snap_dev()
      on any that have not yet been registered.
      
      Rename rbd_dev_snap_devs_update() to be rbd_dev_snaps_update()
      to better reflect that only the entry in the snaps list and not
      the snapshot's device is affected by the function.
      
      For now, call rbd_dev_snaps_register() immediately after each
      call to rbd_dev_snaps_update().
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      304f6808
    • Alex Elder's avatar
      rbd: assign header name later · 3fcf2581
      Alex Elder authored
      
      
      Move the assignment of the header name for an rbd image a bit later,
      outside rbd_add_parse_args() and into its caller.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      3fcf2581
    • Alex Elder's avatar
      rbd: use snaps list in rbd_snap_by_name() · e86924a8
      Alex Elder authored
      
      
      An rbd_dev structure maintains a list of current snapshots that have
      already been fully initialized.  The entries on the list have type
      struct rbd_snap, and each entry contains a copy of information
      that's found in the rbd_dev's snapshot context and header.
      
      The only caller of snap_by_name() is rbd_header_set_snap().  In that
      call site any positive return value (the index in the snapshot
      array) is ignored, so there's no need to return the index in
      the snapshot context's id array when it's found.
      
      rbd_header_set_snap() also has only one caller--rbd_add()--and that
      call is made after a call to rbd_dev_snap_devs_update().  Because
      the rbd_snap structures are initialized in that function, the
      current snapshot list can be used instead of the snapshot context to
      look up a snapshot's information by name.
      
      Change snap_by_name() so it uses the snapshot list rather than the
      rbd_dev's snapshot context in looking up snapshot information.
      Return 0 if it's found rather than the snapshot id.
      
      Signed-off-by: default avatarAlex Elder <elder@inktank.com>
      Reviewed-by: default avatarJosh Durgin <josh.durgin@inktank.com>
      e86924a8