linux/drivers/block/rbd.c


/*
   rbd.c -- Export ceph rados objects as a Linux block device


   based on drivers/block/osdblk.c:

   Copyright 2009 Red Hat, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.



   For usage instructions, please refer to:

                 Documentation/ABI/testing/sysfs-bus-rbd

 */

#include <linux/ceph/libceph.h>
#include <linux/ceph/osd_client.h>
#include <linux/ceph/mon_client.h>
#include <linux/ceph/cls_lock_client.h>
#include <linux/ceph/striper.h>
#include <linux/ceph/decode.h>
#include <linux/fs_parser.h>
#include <linux/bsearch.h>

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/blk-mq.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/idr.h>
#include <linux/workqueue.h>

#include "rbd_types.h"

#define RBD_DEBUG

/*
 * Increment the given counter and return its updated value.
 * If the counter is already 0 it will not be incremented.
 * If the counter is already at its maximum value returns
 * -EINVAL without updating it.
 */
static int atomic_inc_return_safe(atomic_t *v)
{}

/* Decrement the counter.  Return the resulting value, or -EINVAL */
static int atomic_dec_return_safe(atomic_t *v)
{}

#define RBD_DRV_NAME

#define RBD_MINORS_PER_MAJOR
#define RBD_SINGLE_MAJOR_PART_SHIFT

#define RBD_MAX_PARENT_CHAIN_LEN

#define RBD_SNAP_DEV_NAME_PREFIX
#define RBD_MAX_SNAP_NAME_LEN

#define RBD_MAX_SNAP_COUNT

#define RBD_SNAP_HEAD_NAME

#define BAD_SNAP_INDEX

/* This allows a single page to hold an image name sent by OSD */
#define RBD_IMAGE_NAME_LEN_MAX
#define RBD_IMAGE_ID_LEN_MAX

#define RBD_OBJ_PREFIX_LEN_MAX

#define RBD_NOTIFY_TIMEOUT
#define RBD_RETRY_DELAY

/* Feature bits */

#define RBD_FEATURE_LAYERING
#define RBD_FEATURE_STRIPINGV2
#define RBD_FEATURE_EXCLUSIVE_LOCK
#define RBD_FEATURE_OBJECT_MAP
#define RBD_FEATURE_FAST_DIFF
#define RBD_FEATURE_DEEP_FLATTEN
#define RBD_FEATURE_DATA_POOL
#define RBD_FEATURE_OPERATIONS

#define RBD_FEATURES_ALL

/* Features supported by this (client software) implementation. */

#define RBD_FEATURES_SUPPORTED

/*
 * An RBD device name will be "rbd#", where the "rbd" comes from
 * RBD_DRV_NAME above, and # is a unique integer identifier.
 */
#define DEV_NAME_LEN

/*
 * block device image metadata (in-memory version)
 */
struct rbd_image_header {};

/*
 * An rbd image specification.
 *
 * The tuple (pool_id, image_id, snap_id) is sufficient to uniquely
 * identify an image.  Each rbd_dev structure includes a pointer to
 * an rbd_spec structure that encapsulates this identity.
 *
 * Each of the id's in an rbd_spec has an associated name.  For a
 * user-mapped image, the names are supplied and the id's associated
 * with them are looked up.  For a layered image, a parent image is
 * defined by the tuple, and the names are looked up.
 *
 * An rbd_dev structure contains a parent_spec pointer which is
 * non-null if the image it represents is a child in a layered
 * image.  This pointer will refer to the rbd_spec structure used
 * by the parent rbd_dev for its own identity (i.e., the structure
 * is shared between the parent and child).
 *
 * Since these structures are populated once, during the discovery
 * phase of image construction, they are effectively immutable so
 * we make no effort to synchronize access to them.
 *
 * Note that code herein does not assume the image name is known (it
 * could be a null pointer).
 */
struct rbd_spec {};

/*
 * an instance of the client.  multiple devices may share an rbd client.
 */
struct rbd_client {};

struct pending_result {};

struct rbd_img_request;

enum obj_request_type {};

enum obj_operation_type {};

#define RBD_OBJ_FLAG_DELETION
#define RBD_OBJ_FLAG_COPYUP_ENABLED
#define RBD_OBJ_FLAG_COPYUP_ZEROS
#define RBD_OBJ_FLAG_MAY_EXIST
#define RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT

enum rbd_obj_read_state {};

/*
 * Writes go through the following state machine to deal with
 * layering:
 *
 *            . . . . . RBD_OBJ_WRITE_GUARD. . . . . . . . . . . . . .
 *            .                 |                                    .
 *            .                 v                                    .
 *            .    RBD_OBJ_WRITE_READ_FROM_PARENT. . .               .
 *            .                 |                    .               .
 *            .                 v                    v (deep-copyup  .
 *    (image  .   RBD_OBJ_WRITE_COPYUP_EMPTY_SNAPC   .  not needed)  .
 * flattened) v                 |                    .               .
 *            .                 v                    .               .
 *            . . . .RBD_OBJ_WRITE_COPYUP_OPS. . . . .      (copyup  .
 *                              |                        not needed) v
 *                              v                                    .
 *                            done . . . . . . . . . . . . . . . . . .
 *                              ^
 *                              |
 *                     RBD_OBJ_WRITE_FLAT
 *
 * Writes start in RBD_OBJ_WRITE_GUARD or _FLAT, depending on whether
 * assert_exists guard is needed or not (in some cases it's not needed
 * even if there is a parent).
 */
enum rbd_obj_write_state {};

enum rbd_obj_copyup_state {};

struct rbd_obj_request {};

enum img_req_flags {};

enum rbd_img_state {};

struct rbd_img_request {};

#define for_each_obj_request(ireq, oreq)
#define for_each_obj_request_safe(ireq, oreq, n)

enum rbd_watch_state {};

enum rbd_lock_state {};

/* WatchNotify::ClientId */
struct rbd_client_id {};

struct rbd_mapping {};

/*
 * a single device
 */
struct rbd_device {};

/*
 * Flag bits for rbd_dev->flags:
 * - REMOVING (which is coupled with rbd_dev->open_count) is protected
 *   by rbd_dev->lock
 */
enum rbd_dev_flags {};

static DEFINE_MUTEX(client_mutex);	/* Serialize client creation */

static LIST_HEAD(rbd_dev_list);    /* devices */
static DEFINE_SPINLOCK(rbd_dev_list_lock);

static LIST_HEAD(rbd_client_list);		/* clients */
static DEFINE_SPINLOCK(rbd_client_list_lock);

/* Slab caches for frequently-allocated structures */

static struct kmem_cache	*rbd_img_request_cache;
static struct kmem_cache	*rbd_obj_request_cache;

static int rbd_major;
static DEFINE_IDA(rbd_dev_id_ida);

static struct workqueue_struct *rbd_wq;

static struct ceph_snap_context rbd_empty_snapc =;

/*
 * single-major requires >= 0.75 version of userspace rbd utility.
 */
static bool single_major =;
module_param(single_major, bool, 0444);
MODULE_PARM_DESC();

static ssize_t add_store(const struct bus_type *bus, const char *buf, size_t count);
static ssize_t remove_store(const struct bus_type *bus, const char *buf,
			    size_t count);
static ssize_t add_single_major_store(const struct bus_type *bus, const char *buf,
				      size_t count);
static ssize_t remove_single_major_store(const struct bus_type *bus, const char *buf,
					 size_t count);
static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth);

static int rbd_dev_id_to_minor(int dev_id)
{}

static int minor_to_rbd_dev_id(int minor)
{}

static bool rbd_is_ro(struct rbd_device *rbd_dev)
{}

static bool rbd_is_snap(struct rbd_device *rbd_dev)
{}

static bool __rbd_is_lock_owner(struct rbd_device *rbd_dev)
{}

static bool rbd_is_lock_owner(struct rbd_device *rbd_dev)
{}

static ssize_t supported_features_show(const struct bus_type *bus, char *buf)
{}

static BUS_ATTR_WO(add);
static BUS_ATTR_WO(remove);
static BUS_ATTR_WO(add_single_major);
static BUS_ATTR_WO(remove_single_major);
static BUS_ATTR_RO(supported_features);

static struct attribute *rbd_bus_attrs[] =;

static umode_t rbd_bus_is_visible(struct kobject *kobj,
				  struct attribute *attr, int index)
{}

static const struct attribute_group rbd_bus_group =;
__ATTRIBUTE_GROUPS();

static const struct bus_type rbd_bus_type =;

static void rbd_root_dev_release(struct device *dev)
{}

static struct device rbd_root_dev =;

static __printf(2, 3)
void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
{}

#ifdef RBD_DEBUG
#define rbd_assert(expr)
#else /* !RBD_DEBUG */
#define rbd_assert
#endif /* !RBD_DEBUG */

static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);

static int rbd_dev_refresh(struct rbd_device *rbd_dev);
static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
				     struct rbd_image_header *header);
static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
					u64 snap_id);
static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
				u8 *order, u64 *snap_size);
static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev);

static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result);
static void rbd_img_handle_request(struct rbd_img_request *img_req, int result);

/*
 * Return true if nothing else is pending.
 */
static bool pending_result_dec(struct pending_result *pending, int *result)
{}

static int rbd_open(struct gendisk *disk, blk_mode_t mode)
{}

static void rbd_release(struct gendisk *disk)
{}

static const struct block_device_operations rbd_bd_ops =;

/*
 * Initialize an rbd client instance.  Success or not, this function
 * consumes ceph_opts.  Caller holds client_mutex.
 */
static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
{}

static struct rbd_client *__rbd_get_client(struct rbd_client *rbdc)
{}

/*
 * Find a ceph client with specific addr and configuration.  If
 * found, bump its reference count.
 */
static struct rbd_client *rbd_client_find(struct ceph_options *ceph_opts)
{}

/*
 * (Per device) rbd map options
 */
enum {};

enum {};

static const struct constant_table rbd_param_compression_hint[] =;

static const struct fs_parameter_spec rbd_parameters[] =;

struct rbd_options {};

#define RBD_QUEUE_DEPTH_DEFAULT
#define RBD_ALLOC_SIZE_DEFAULT
#define RBD_LOCK_TIMEOUT_DEFAULT
#define RBD_READ_ONLY_DEFAULT
#define RBD_LOCK_ON_READ_DEFAULT
#define RBD_EXCLUSIVE_DEFAULT
#define RBD_TRIM_DEFAULT

struct rbd_parse_opts_ctx {};

static char* obj_op_name(enum obj_operation_type op_type)
{}

/*
 * Destroy ceph client
 *
 * Caller must hold rbd_client_list_lock.
 */
static void rbd_client_release(struct kref *kref)
{}

/*
 * Drop reference to ceph client node. If it's not referenced anymore, release
 * it.
 */
static void rbd_put_client(struct rbd_client *rbdc)
{}

/*
 * Get a ceph client with specific addr and configuration, if one does
 * not exist create it.  Either way, ceph_opts is consumed by this
 * function.
 */
static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
{}

static bool rbd_image_format_valid(u32 image_format)
{}

static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
{}

/*
 * returns the size of an object in the image
 */
static u32 rbd_obj_bytes(struct rbd_image_header *header)
{}

static void rbd_init_layout(struct rbd_device *rbd_dev)
{}

static void rbd_image_header_cleanup(struct rbd_image_header *header)
{}

/*
 * Fill an rbd image header with information from the given format 1
 * on-disk header.
 */
static int rbd_header_from_disk(struct rbd_image_header *header,
				struct rbd_image_header_ondisk *ondisk,
				bool first_time)
{}

static const char *_rbd_dev_v1_snap_name(struct rbd_device *rbd_dev, u32 which)
{}

/*
 * Snapshot id comparison function for use with qsort()/bsearch().
 * Note that result is for snapshots in *descending* order.
 */
static int snapid_compare_reverse(const void *s1, const void *s2)
{}

/*
 * Search a snapshot context to see if the given snapshot id is
 * present.
 *
 * Returns the position of the snapshot id in the array if it's found,
 * or BAD_SNAP_INDEX otherwise.
 *
 * Note: The snapshot array is in kept sorted (by the osd) in
 * reverse order, highest snapshot id first.
 */
static u32 rbd_dev_snap_index(struct rbd_device *rbd_dev, u64 snap_id)
{}

static const char *rbd_dev_v1_snap_name(struct rbd_device *rbd_dev,
					u64 snap_id)
{}

static const char *rbd_snap_name(struct rbd_device *rbd_dev, u64 snap_id)
{}

static int rbd_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
				u64 *snap_size)
{}

static int rbd_dev_mapping_set(struct rbd_device *rbd_dev)
{}

static void rbd_dev_mapping_clear(struct rbd_device *rbd_dev)
{}

static void zero_bios(struct ceph_bio_iter *bio_pos, u32 off, u32 bytes)
{}

static void zero_bvecs(struct ceph_bvec_iter *bvec_pos, u32 off, u32 bytes)
{}

/*
 * Zero a range in @obj_req data buffer defined by a bio (list) or
 * (private) bio_vec array.
 *
 * @off is relative to the start of the data buffer.
 */
static void rbd_obj_zero_range(struct rbd_obj_request *obj_req, u32 off,
			       u32 bytes)
{}

static void rbd_obj_request_destroy(struct kref *kref);
static void rbd_obj_request_put(struct rbd_obj_request *obj_request)
{}

static inline void rbd_img_obj_request_add(struct rbd_img_request *img_request,
					struct rbd_obj_request *obj_request)
{}

static inline void rbd_img_obj_request_del(struct rbd_img_request *img_request,
					struct rbd_obj_request *obj_request)
{}

static void rbd_osd_submit(struct ceph_osd_request *osd_req)
{}

/*
 * The default/initial value for all image request flags is 0.  Each
 * is conditionally set to 1 at image request initialization time
 * and currently never change thereafter.
 */
static void img_request_layered_set(struct rbd_img_request *img_request)
{}

static bool img_request_layered_test(struct rbd_img_request *img_request)
{}

static bool rbd_obj_is_entire(struct rbd_obj_request *obj_req)
{}

static bool rbd_obj_is_tail(struct rbd_obj_request *obj_req)
{}

/*
 * Must be called after rbd_obj_calc_img_extents().
 */
static void rbd_obj_set_copyup_enabled(struct rbd_obj_request *obj_req)
{}

static u64 rbd_obj_img_extents_bytes(struct rbd_obj_request *obj_req)
{}

static bool rbd_img_is_write(struct rbd_img_request *img_req)
{}

static void rbd_osd_req_callback(struct ceph_osd_request *osd_req)
{}

static void rbd_osd_format_read(struct ceph_osd_request *osd_req)
{}

static void rbd_osd_format_write(struct ceph_osd_request *osd_req)
{}

static struct ceph_osd_request *
__rbd_obj_add_osd_request(struct rbd_obj_request *obj_req,
			  struct ceph_snap_context *snapc, int num_ops)
{}

static struct ceph_osd_request *
rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
{}

static struct rbd_obj_request *rbd_obj_request_create(void)
{}

static void rbd_obj_request_destroy(struct kref *kref)
{}

/* It's OK to call this for a device with no parent */

static void rbd_spec_put(struct rbd_spec *spec);
static void rbd_dev_unparent(struct rbd_device *rbd_dev)
{}

/*
 * Parent image reference counting is used to determine when an
 * image's parent fields can be safely torn down--after there are no
 * more in-flight requests to the parent image.  When the last
 * reference is dropped, cleaning them up is safe.
 */
static void rbd_dev_parent_put(struct rbd_device *rbd_dev)
{}

/*
 * If an image has a non-zero parent overlap, get a reference to its
 * parent.
 *
 * Returns true if the rbd device has a parent with a non-zero
 * overlap and a reference for it was successfully taken, or
 * false otherwise.
 */
static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
{}

static void rbd_img_request_init(struct rbd_img_request *img_request,
				 struct rbd_device *rbd_dev,
				 enum obj_operation_type op_type)
{}

/*
 * Only snap_id is captured here, for reads.  For writes, snapshot
 * context is captured in rbd_img_object_requests() after exclusive
 * lock is ensured to be held.
 */
static void rbd_img_capture_header(struct rbd_img_request *img_req)
{}

static void rbd_img_request_destroy(struct rbd_img_request *img_request)
{}

#define BITS_PER_OBJ
#define OBJS_PER_BYTE
#define OBJ_MASK

static void __rbd_object_map_index(struct rbd_device *rbd_dev, u64 objno,
				   u64 *index, u8 *shift)
{}

static u8 __rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
{}

static void __rbd_object_map_set(struct rbd_device *rbd_dev, u64 objno, u8 val)
{}

static u8 rbd_object_map_get(struct rbd_device *rbd_dev, u64 objno)
{}

static bool use_object_map(struct rbd_device *rbd_dev)
{}

static bool rbd_object_map_may_exist(struct rbd_device *rbd_dev, u64 objno)
{}

static void rbd_object_map_name(struct rbd_device *rbd_dev, u64 snap_id,
				struct ceph_object_id *oid)
{}

static int rbd_object_map_lock(struct rbd_device *rbd_dev)
{}

static void rbd_object_map_unlock(struct rbd_device *rbd_dev)
{}

static int decode_object_map_header(void **p, void *end, u64 *object_map_size)
{}

static int __rbd_object_map_load(struct rbd_device *rbd_dev)
{}

static void rbd_object_map_free(struct rbd_device *rbd_dev)
{}

static int rbd_object_map_load(struct rbd_device *rbd_dev)
{}

static int rbd_object_map_open(struct rbd_device *rbd_dev)
{}

static void rbd_object_map_close(struct rbd_device *rbd_dev)
{}

/*
 * This function needs snap_id (or more precisely just something to
 * distinguish between HEAD and snapshot object maps), new_state and
 * current_state that were passed to rbd_object_map_update().
 *
 * To avoid allocating and stashing a context we piggyback on the OSD
 * request.  A HEAD update has two ops (assert_locked).  For new_state
 * and current_state we decode our own object_map_update op, encoded in
 * rbd_cls_object_map_update().
 */
static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
					struct ceph_osd_request *osd_req)
{}

static void rbd_object_map_callback(struct ceph_osd_request *osd_req)
{}

static bool update_needed(struct rbd_device *rbd_dev, u64 objno, u8 new_state)
{}

static int rbd_cls_object_map_update(struct ceph_osd_request *req,
				     int which, u64 objno, u8 new_state,
				     const u8 *current_state)
{}

/*
 * Return:
 *   0 - object map update sent
 *   1 - object map update isn't needed
 *  <0 - error
 */
static int rbd_object_map_update(struct rbd_obj_request *obj_req, u64 snap_id,
				 u8 new_state, const u8 *current_state)
{}

static void prune_extents(struct ceph_file_extent *img_extents,
			  u32 *num_img_extents, u64 overlap)
{}

/*
 * Determine the byte range(s) covered by either just the object extent
 * or the entire object in the parent image.
 */
static int rbd_obj_calc_img_extents(struct rbd_obj_request *obj_req,
				    bool entire)
{}

static void rbd_osd_setup_data(struct ceph_osd_request *osd_req, int which)
{}

static int rbd_osd_setup_stat(struct ceph_osd_request *osd_req, int which)
{}

static int rbd_osd_setup_copyup(struct ceph_osd_request *osd_req, int which,
				u32 bytes)
{}

static int rbd_obj_init_read(struct rbd_obj_request *obj_req)
{}

static void __rbd_osd_setup_write_ops(struct ceph_osd_request *osd_req,
				      int which)
{}

static int rbd_obj_init_write(struct rbd_obj_request *obj_req)
{}

static u16 truncate_or_zero_opcode(struct rbd_obj_request *obj_req)
{}

static void __rbd_osd_setup_discard_ops(struct ceph_osd_request *osd_req,
					int which)
{}

static int rbd_obj_init_discard(struct rbd_obj_request *obj_req)
{}

static void __rbd_osd_setup_zeroout_ops(struct ceph_osd_request *osd_req,
					int which)
{}

static int rbd_obj_init_zeroout(struct rbd_obj_request *obj_req)
{}

static int count_write_ops(struct rbd_obj_request *obj_req)
{}

static void rbd_osd_setup_write_ops(struct ceph_osd_request *osd_req,
				    int which)
{}

/*
 * Prune the list of object requests (adjust offset and/or length, drop
 * redundant requests).  Prepare object request state machines and image
 * request state machine for execution.
 */
static int __rbd_img_fill_request(struct rbd_img_request *img_req)
{}

rbd_img_fill_iter;

struct rbd_img_fill_ctx {};

static struct ceph_object_extent *alloc_object_extent(void *arg)
{}

/*
 * While su != os && sc == 1 is technically not fancy (it's the same
 * layout as su == os && sc == 1), we can't use the nocopy path for it
 * because ->set_pos_fn() should be called only once per object.
 * ceph_file_to_extents() invokes action_fn once per stripe unit, so
 * treat su != os && sc == 1 as fancy.
 */
static bool rbd_layout_is_fancy(struct ceph_file_layout *l)
{}

static int rbd_img_fill_request_nocopy(struct rbd_img_request *img_req,
				       struct ceph_file_extent *img_extents,
				       u32 num_img_extents,
				       struct rbd_img_fill_ctx *fctx)
{}

/*
 * Map a list of image extents to a list of object extents, create the
 * corresponding object requests (normally each to a different object,
 * but not always) and add them to @img_req.  For each object request,
 * set up its data descriptor to point to the corresponding chunk(s) of
 * @fctx->pos data buffer.
 *
 * Because ceph_file_to_extents() will merge adjacent object extents
 * together, each object request's data descriptor may point to multiple
 * different chunks of @fctx->pos data buffer.
 *
 * @fctx->pos data buffer is assumed to be large enough.
 */
static int rbd_img_fill_request(struct rbd_img_request *img_req,
				struct ceph_file_extent *img_extents,
				u32 num_img_extents,
				struct rbd_img_fill_ctx *fctx)
{}

static int rbd_img_fill_nodata(struct rbd_img_request *img_req,
			       u64 off, u64 len)
{}

static void set_bio_pos(struct ceph_object_extent *ex, u32 bytes, void *arg)
{}

static void count_bio_bvecs(struct ceph_object_extent *ex, u32 bytes, void *arg)
{}

static void copy_bio_bvecs(struct ceph_object_extent *ex, u32 bytes, void *arg)
{}

static int __rbd_img_fill_from_bio(struct rbd_img_request *img_req,
				   struct ceph_file_extent *img_extents,
				   u32 num_img_extents,
				   struct ceph_bio_iter *bio_pos)
{}

static int rbd_img_fill_from_bio(struct rbd_img_request *img_req,
				 u64 off, u64 len, struct bio *bio)
{}

static void set_bvec_pos(struct ceph_object_extent *ex, u32 bytes, void *arg)
{}

static void count_bvecs(struct ceph_object_extent *ex, u32 bytes, void *arg)
{}

static void copy_bvecs(struct ceph_object_extent *ex, u32 bytes, void *arg)
{}

static int __rbd_img_fill_from_bvecs(struct rbd_img_request *img_req,
				     struct ceph_file_extent *img_extents,
				     u32 num_img_extents,
				     struct ceph_bvec_iter *bvec_pos)
{}

static int rbd_img_fill_from_bvecs(struct rbd_img_request *img_req,
				   struct ceph_file_extent *img_extents,
				   u32 num_img_extents,
				   struct bio_vec *bvecs)
{}

static void rbd_img_handle_request_work(struct work_struct *work)
{}

static void rbd_img_schedule(struct rbd_img_request *img_req, int result)
{}

static bool rbd_obj_may_exist(struct rbd_obj_request *obj_req)
{}

static int rbd_obj_read_object(struct rbd_obj_request *obj_req)
{}

static int rbd_obj_read_from_parent(struct rbd_obj_request *obj_req)
{}

static bool rbd_obj_advance_read(struct rbd_obj_request *obj_req, int *result)
{}

static bool rbd_obj_write_is_noop(struct rbd_obj_request *obj_req)
{}

/*
 * Return:
 *   0 - object map update sent
 *   1 - object map update isn't needed
 *  <0 - error
 */
static int rbd_obj_write_pre_object_map(struct rbd_obj_request *obj_req)
{}

static int rbd_obj_write_object(struct rbd_obj_request *obj_req)
{}

/*
 * copyup_bvecs pages are never highmem pages
 */
static bool is_zero_bvecs(struct bio_vec *bvecs, u32 bytes)
{}

#define MODS_ONLY

static int rbd_obj_copyup_empty_snapc(struct rbd_obj_request *obj_req,
				      u32 bytes)
{}

static int rbd_obj_copyup_current_snapc(struct rbd_obj_request *obj_req,
					u32 bytes)
{}

static int setup_copyup_bvecs(struct rbd_obj_request *obj_req, u64 obj_overlap)
{}

/*
 * The target object doesn't exist.  Read the data for the entire
 * target object up to the overlap point (if any) from the parent,
 * so we can use it for a copyup.
 */
static int rbd_obj_copyup_read_parent(struct rbd_obj_request *obj_req)
{}

static void rbd_obj_copyup_object_maps(struct rbd_obj_request *obj_req)
{}

static void rbd_obj_copyup_write_object(struct rbd_obj_request *obj_req)
{}

static bool rbd_obj_advance_copyup(struct rbd_obj_request *obj_req, int *result)
{}

/*
 * Return:
 *   0 - object map update sent
 *   1 - object map update isn't needed
 *  <0 - error
 */
static int rbd_obj_write_post_object_map(struct rbd_obj_request *obj_req)
{}

static bool rbd_obj_advance_write(struct rbd_obj_request *obj_req, int *result)
{}

/*
 * Return true if @obj_req is completed.
 */
static bool __rbd_obj_handle_request(struct rbd_obj_request *obj_req,
				     int *result)
{}

/*
 * This is open-coded in rbd_img_handle_request() to avoid parent chain
 * recursion.
 */
static void rbd_obj_handle_request(struct rbd_obj_request *obj_req, int result)
{}

static bool need_exclusive_lock(struct rbd_img_request *img_req)
{}

static bool rbd_lock_add_request(struct rbd_img_request *img_req)
{}

static void rbd_lock_del_request(struct rbd_img_request *img_req)
{}

static int rbd_img_exclusive_lock(struct rbd_img_request *img_req)
{}

static void rbd_img_object_requests(struct rbd_img_request *img_req)
{}

static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
{}

/*
 * Return true if @img_req is completed.
 */
static bool __rbd_img_handle_request(struct rbd_img_request *img_req,
				     int *result)
{}

static void rbd_img_handle_request(struct rbd_img_request *img_req, int result)
{}

static const struct rbd_client_id rbd_empty_cid;

static bool rbd_cid_equal(const struct rbd_client_id *lhs,
			  const struct rbd_client_id *rhs)
{}

static struct rbd_client_id rbd_get_cid(struct rbd_device *rbd_dev)
{}

/*
 * lock_rwsem must be held for write
 */
static void rbd_set_owner_cid(struct rbd_device *rbd_dev,
			      const struct rbd_client_id *cid)
{}

static void format_lock_cookie(struct rbd_device *rbd_dev, char *buf)
{}

static void __rbd_lock(struct rbd_device *rbd_dev, const char *cookie)
{}

/*
 * lock_rwsem must be held for write
 */
static int rbd_lock(struct rbd_device *rbd_dev)
{}

/*
 * lock_rwsem must be held for write
 */
static void rbd_unlock(struct rbd_device *rbd_dev)
{}

static int __rbd_notify_op_lock(struct rbd_device *rbd_dev,
				enum rbd_notify_op notify_op,
				struct page ***preply_pages,
				size_t *preply_len)
{}

static void rbd_notify_op_lock(struct rbd_device *rbd_dev,
			       enum rbd_notify_op notify_op)
{}

static void rbd_notify_acquired_lock(struct work_struct *work)
{}

static void rbd_notify_released_lock(struct work_struct *work)
{}

static int rbd_request_lock(struct rbd_device *rbd_dev)
{}

/*
 * Either image request state machine(s) or rbd_add_acquire_lock()
 * (i.e. "rbd map").
 */
static void wake_lock_waiters(struct rbd_device *rbd_dev, int result)
{}

static bool locker_equal(const struct ceph_locker *lhs,
			 const struct ceph_locker *rhs)
{}

static void free_locker(struct ceph_locker *locker)
{}

static struct ceph_locker *get_lock_owner_info(struct rbd_device *rbd_dev)
{}

static int find_watcher(struct rbd_device *rbd_dev,
			const struct ceph_locker *locker)
{}

/*
 * lock_rwsem must be held for write
 */
static int rbd_try_lock(struct rbd_device *rbd_dev)
{}

static int rbd_post_acquire_action(struct rbd_device *rbd_dev)
{}

/*
 * Return:
 *   0 - lock acquired
 *   1 - caller should call rbd_request_lock()
 *  <0 - error
 */
static int rbd_try_acquire_lock(struct rbd_device *rbd_dev)
{}

static void rbd_acquire_lock(struct work_struct *work)
{}

static bool rbd_quiesce_lock(struct rbd_device *rbd_dev)
{}

static void rbd_pre_release_action(struct rbd_device *rbd_dev)
{}

static void __rbd_release_lock(struct rbd_device *rbd_dev)
{}

/*
 * lock_rwsem must be held for write
 */
static void rbd_release_lock(struct rbd_device *rbd_dev)
{}

static void rbd_release_lock_work(struct work_struct *work)
{}

static void maybe_kick_acquire(struct rbd_device *rbd_dev)
{}

static void rbd_handle_acquired_lock(struct rbd_device *rbd_dev, u8 struct_v,
				     void **p)
{}

static void rbd_handle_released_lock(struct rbd_device *rbd_dev, u8 struct_v,
				     void **p)
{}

/*
 * Returns result for ResponseMessage to be encoded (<= 0), or 1 if no
 * ResponseMessage is needed.
 */
static int rbd_handle_request_lock(struct rbd_device *rbd_dev, u8 struct_v,
				   void **p)
{}

static void __rbd_acknowledge_notify(struct rbd_device *rbd_dev,
				     u64 notify_id, u64 cookie, s32 *result)
{}

static void rbd_acknowledge_notify(struct rbd_device *rbd_dev, u64 notify_id,
				   u64 cookie)
{}

static void rbd_acknowledge_notify_result(struct rbd_device *rbd_dev,
					  u64 notify_id, u64 cookie, s32 result)
{}

static void rbd_watch_cb(void *arg, u64 notify_id, u64 cookie,
			 u64 notifier_id, void *data, size_t data_len)
{}

static void __rbd_unregister_watch(struct rbd_device *rbd_dev);

static void rbd_watch_errcb(void *arg, u64 cookie, int err)
{}

/*
 * watch_mutex must be locked
 */
static int __rbd_register_watch(struct rbd_device *rbd_dev)
{}

/*
 * watch_mutex must be locked
 */
static void __rbd_unregister_watch(struct rbd_device *rbd_dev)
{}

static int rbd_register_watch(struct rbd_device *rbd_dev)
{}

static void cancel_tasks_sync(struct rbd_device *rbd_dev)
{}

/*
 * header_rwsem must not be held to avoid a deadlock with
 * rbd_dev_refresh() when flushing notifies.
 */
static void rbd_unregister_watch(struct rbd_device *rbd_dev)
{}

/*
 * lock_rwsem must be held for write
 */
static void rbd_reacquire_lock(struct rbd_device *rbd_dev)
{}

static void rbd_reregister_watch(struct work_struct *work)
{}

/*
 * Synchronous osd object method call.  Returns the number of bytes
 * returned in the outbound buffer, or a negative error code.
 */
static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
			     struct ceph_object_id *oid,
			     struct ceph_object_locator *oloc,
			     const char *method_name,
			     const void *outbound,
			     size_t outbound_size,
			     void *inbound,
			     size_t inbound_size)
{}

static void rbd_queue_workfn(struct work_struct *work)
{}

static blk_status_t rbd_queue_rq(struct blk_mq_hw_ctx *hctx,
		const struct blk_mq_queue_data *bd)
{}

static void rbd_free_disk(struct rbd_device *rbd_dev)
{}

static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
			     struct ceph_object_id *oid,
			     struct ceph_object_locator *oloc,
			     void *buf, int buf_len)

{}

/*
 * Read the complete header for the given rbd device.  On successful
 * return, the rbd_dev->header field will contain up-to-date
 * information about the image.
 */
static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev,
				  struct rbd_image_header *header,
				  bool first_time)
{}

static void rbd_dev_update_size(struct rbd_device *rbd_dev)
{}

static const struct blk_mq_ops rbd_mq_ops =;

static int rbd_init_disk(struct rbd_device *rbd_dev)
{}

/*
  sysfs
*/

static struct rbd_device *dev_to_rbd_dev(struct device *dev)
{}

static ssize_t rbd_size_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_features_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_major_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_minor_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_client_addr_show(struct device *dev,
				    struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_client_id_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_cluster_fsid_show(struct device *dev,
				     struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_config_info_show(struct device *dev,
				    struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_pool_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_pool_id_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_pool_ns_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_name_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

static ssize_t rbd_image_id_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

/*
 * Shows the name of the currently-mapped snapshot (or
 * RBD_SNAP_HEAD_NAME for the base image).
 */
static ssize_t rbd_snap_show(struct device *dev,
			     struct device_attribute *attr,
			     char *buf)
{}

static ssize_t rbd_snap_id_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{}

/*
 * For a v2 image, shows the chain of parent images, separated by empty
 * lines.  For v1 images or if there is no parent, shows "(no parent
 * image)".
 */
static ssize_t rbd_parent_show(struct device *dev,
			       struct device_attribute *attr,
			       char *buf)
{}

static ssize_t rbd_image_refresh(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf,
				 size_t size)
{}

static DEVICE_ATTR(size, 0444, rbd_size_show, NULL);
static DEVICE_ATTR(features, 0444, rbd_features_show, NULL);
static DEVICE_ATTR(major, 0444, rbd_major_show, NULL);
static DEVICE_ATTR(minor, 0444, rbd_minor_show, NULL);
static DEVICE_ATTR(client_addr, 0444, rbd_client_addr_show, NULL);
static DEVICE_ATTR(client_id, 0444, rbd_client_id_show, NULL);
static DEVICE_ATTR(cluster_fsid, 0444, rbd_cluster_fsid_show, NULL);
static DEVICE_ATTR(config_info, 0400, rbd_config_info_show, NULL);
static DEVICE_ATTR(pool, 0444, rbd_pool_show, NULL);
static DEVICE_ATTR(pool_id, 0444, rbd_pool_id_show, NULL);
static DEVICE_ATTR(pool_ns, 0444, rbd_pool_ns_show, NULL);
static DEVICE_ATTR(name, 0444, rbd_name_show, NULL);
static DEVICE_ATTR(image_id, 0444, rbd_image_id_show, NULL);
static DEVICE_ATTR(refresh, 0200, NULL, rbd_image_refresh);
static DEVICE_ATTR(current_snap, 0444, rbd_snap_show, NULL);
static DEVICE_ATTR(snap_id, 0444, rbd_snap_id_show, NULL);
static DEVICE_ATTR(parent, 0444, rbd_parent_show, NULL);

static struct attribute *rbd_attrs[] =;

static struct attribute_group rbd_attr_group =;

static const struct attribute_group *rbd_attr_groups[] =;

static void rbd_dev_release(struct device *dev);

static const struct device_type rbd_device_type =;

static struct rbd_spec *rbd_spec_get(struct rbd_spec *spec)
{}

static void rbd_spec_free(struct kref *kref);
static void rbd_spec_put(struct rbd_spec *spec)
{}

static struct rbd_spec *rbd_spec_alloc(void)
{}

static void rbd_spec_free(struct kref *kref)
{}

static void rbd_dev_free(struct rbd_device *rbd_dev)
{}

static void rbd_dev_release(struct device *dev)
{}

static struct rbd_device *__rbd_dev_create(struct rbd_spec *spec)
{}

/*
 * Create a mapping rbd_dev.
 */
static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
					 struct rbd_spec *spec,
					 struct rbd_options *opts)
{}

static void rbd_dev_destroy(struct rbd_device *rbd_dev)
{}

/*
 * Get the size and object order for an image snapshot, or if
 * snap_id is CEPH_NOSNAP, gets this information for the base
 * image.
 */
static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
				u8 *order, u64 *snap_size)
{}

static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev,
				    char **pobject_prefix)
{}

static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
				     bool read_only, u64 *snap_features)
{}

/*
 * These are generic image flags, but since they are used only for
 * object map, store them in rbd_dev->object_map_flags.
 *
 * For the same reason, this function is called only on object map
 * (re)load and not on header refresh.
 */
static int rbd_dev_v2_get_flags(struct rbd_device *rbd_dev)
{}

struct parent_image_info {};

static void rbd_parent_info_cleanup(struct parent_image_info *pii)
{}

/*
 * The caller is responsible for @pii.
 */
static int decode_parent_image_spec(void **p, void *end,
				    struct parent_image_info *pii)
{}

static int __get_parent_info(struct rbd_device *rbd_dev,
			     struct page *req_page,
			     struct page *reply_page,
			     struct parent_image_info *pii)
{}

/*
 * The caller is responsible for @pii.
 */
static int __get_parent_info_legacy(struct rbd_device *rbd_dev,
				    struct page *req_page,
				    struct page *reply_page,
				    struct parent_image_info *pii)
{}

static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev,
				  struct parent_image_info *pii)
{}

static int rbd_dev_setup_parent(struct rbd_device *rbd_dev)
{}

static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev,
				    u64 *stripe_unit, u64 *stripe_count)
{}

static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev, s64 *data_pool_id)
{}

static char *rbd_dev_image_name(struct rbd_device *rbd_dev)
{}

static u64 rbd_v1_snap_id_by_name(struct rbd_device *rbd_dev, const char *name)
{}

static u64 rbd_v2_snap_id_by_name(struct rbd_device *rbd_dev, const char *name)
{}

/*
 * Assumes name is never RBD_SNAP_HEAD_NAME; returns CEPH_NOSNAP if
 * no snapshot by that name is found, or if an error occurs.
 */
static u64 rbd_snap_id_by_name(struct rbd_device *rbd_dev, const char *name)
{}

/*
 * An image being mapped will have everything but the snap id.
 */
static int rbd_spec_fill_snap_id(struct rbd_device *rbd_dev)
{}

/*
 * A parent image will have all ids but none of the names.
 *
 * All names in an rbd spec are dynamically allocated.  It's OK if we
 * can't figure out the name for an image id.
 */
static int rbd_spec_fill_names(struct rbd_device *rbd_dev)
{}

static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev,
				   struct ceph_snap_context **psnapc)
{}

static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
					u64 snap_id)
{}

static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev,
				  struct rbd_image_header *header,
				  bool first_time)
{}

static int rbd_dev_header_info(struct rbd_device *rbd_dev,
			       struct rbd_image_header *header,
			       bool first_time)
{}

/*
 * Skips over white space at *buf, and updates *buf to point to the
 * first found non-space character (if any). Returns the length of
 * the token (string of non-white space characters) found.  Note
 * that *buf must be terminated with '\0'.
 */
static inline size_t next_token(const char **buf)
{}

/*
 * Finds the next token in *buf, dynamically allocates a buffer big
 * enough to hold a copy of it, and copies the token into the new
 * buffer.  The copy is guaranteed to be terminated with '\0'.  Note
 * that a duplicate buffer is created even for a zero-length token.
 *
 * Returns a pointer to the newly-allocated duplicate, or a null
 * pointer if memory for the duplicate was not available.  If
 * the lenp argument is a non-null pointer, the length of the token
 * (not including the '\0') is returned in *lenp.
 *
 * If successful, the *buf pointer will be updated to point beyond
 * the end of the found token.
 *
 * Note: uses GFP_KERNEL for allocation.
 */
static inline char *dup_token(const char **buf, size_t *lenp)
{}

static int rbd_parse_param(struct fs_parameter *param,
			    struct rbd_parse_opts_ctx *pctx)
{}

/*
 * This duplicates most of generic_parse_monolithic(), untying it from
 * fs_context and skipping standard superblock and security options.
 */
static int rbd_parse_options(char *options, struct rbd_parse_opts_ctx *pctx)
{}

/*
 * Parse the options provided for an "rbd add" (i.e., rbd image
 * mapping) request.  These arrive via a write to /sys/bus/rbd/add,
 * and the data written is passed here via a NUL-terminated buffer.
 * Returns 0 if successful or an error code otherwise.
 *
 * The information extracted from these options is recorded in
 * the other parameters which return dynamically-allocated
 * structures:
 *  ceph_opts
 *      The address of a pointer that will refer to a ceph options
 *      structure.  Caller must release the returned pointer using
 *      ceph_destroy_options() when it is no longer needed.
 *  rbd_opts
 *	Address of an rbd options pointer.  Fully initialized by
 *	this function; caller must release with kfree().
 *  spec
 *	Address of an rbd image specification pointer.  Fully
 *	initialized by this function based on parsed options.
 *	Caller must release with rbd_spec_put().
 *
 * The options passed take this form:
 *  <mon_addrs> <options> <pool_name> <image_name> [<snap_id>]
 * where:
 *  <mon_addrs>
 *      A comma-separated list of one or more monitor addresses.
 *      A monitor address is an ip address, optionally followed
 *      by a port number (separated by a colon).
 *        I.e.:  ip1[:port1][,ip2[:port2]...]
 *  <options>
 *      A comma-separated list of ceph and/or rbd options.
 *  <pool_name>
 *      The name of the rados pool containing the rbd image.
 *  <image_name>
 *      The name of the image in that pool to map.
 *  <snap_id>
 *      An optional snapshot id.  If provided, the mapping will
 *      present data from the image at the time that snapshot was
 *      created.  The image head is used if no snapshot id is
 *      provided.  Snapshot mappings are always read-only.
 */
static int rbd_add_parse_args(const char *buf,
				struct ceph_options **ceph_opts,
				struct rbd_options **opts,
				struct rbd_spec **rbd_spec)
{}

static void rbd_dev_image_unlock(struct rbd_device *rbd_dev)
{}

/*
 * If the wait is interrupted, an error is returned even if the lock
 * was successfully acquired.  rbd_dev_image_unlock() will release it
 * if needed.
 */
static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
{}

/*
 * An rbd format 2 image has a unique identifier, distinct from the
 * name given to it by the user.  Internally, that identifier is
 * what's used to specify the names of objects related to the image.
 *
 * A special "rbd id" object is used to map an rbd image name to its
 * id.  If that object doesn't exist, then there is no v2 rbd image
 * with the supplied name.
 *
 * This function will record the given rbd_dev's image_id field if
 * it can be determined, and in that case will return 0.  If any
 * errors occur a negative errno will be returned and the rbd_dev's
 * image_id field will be unchanged (and should be NULL).
 */
static int rbd_dev_image_id(struct rbd_device *rbd_dev)
{}

/*
 * Undo whatever state changes are made by v1 or v2 header info
 * call.
 */
static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
{}

static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev,
				     struct rbd_image_header *header)
{}

/*
 * @depth is rbd_dev_image_probe() -> rbd_dev_probe_parent() ->
 * rbd_dev_image_probe() recursion depth, which means it's also the
 * length of the already discovered part of the parent chain.
 */
static int rbd_dev_probe_parent(struct rbd_device *rbd_dev, int depth)
{}

static void rbd_dev_device_release(struct rbd_device *rbd_dev)
{}

/*
 * rbd_dev->header_rwsem must be locked for write and will be unlocked
 * upon return.
 */
static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
{}

static int rbd_dev_header_name(struct rbd_device *rbd_dev)
{}

static void rbd_print_dne(struct rbd_device *rbd_dev, bool is_snap)
{}

static void rbd_dev_image_release(struct rbd_device *rbd_dev)
{}

/*
 * Probe for the existence of the header object for the given rbd
 * device.  If this image is the one being mapped (i.e., not a
 * parent), initiate a watch on its header object before using that
 * object to get detailed information about the rbd image.
 *
 * On success, returns with header_rwsem held for write if called
 * with @depth == 0.
 */
static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth)
{}

static void rbd_dev_update_header(struct rbd_device *rbd_dev,
				  struct rbd_image_header *header)
{}

static void rbd_dev_update_parent(struct rbd_device *rbd_dev,
				  struct parent_image_info *pii)
{}

static int rbd_dev_refresh(struct rbd_device *rbd_dev)
{}

static ssize_t do_rbd_add(const char *buf, size_t count)
{}

static ssize_t add_store(const struct bus_type *bus, const char *buf, size_t count)
{}

static ssize_t add_single_major_store(const struct bus_type *bus, const char *buf,
				      size_t count)
{}

static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
{}

static ssize_t do_rbd_remove(const char *buf, size_t count)
{}

static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count)
{}

static ssize_t remove_single_major_store(const struct bus_type *bus, const char *buf,
					 size_t count)
{}

/*
 * create control files in sysfs
 * /sys/bus/rbd/...
 */
static int __init rbd_sysfs_init(void)
{}

static void __exit rbd_sysfs_cleanup(void)
{}

static int __init rbd_slab_init(void)
{}

static void rbd_slab_exit(void)
{}

static int __init rbd_init(void)
{}

static void __exit rbd_exit(void)
{}

module_init();
module_exit(rbd_exit);

MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
/* following authorship retained from original osdblk.c */
MODULE_AUTHOR();

MODULE_DESCRIPTION();
MODULE_LICENSE();