/* 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 /* Activate rbd_assert() calls */ /* * 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){ unsigned int counter; counter = (unsigned int)atomic_fetch_add_unless(v, 1, 0); if (counter <= (unsigned int)INT_MAX) return (int)counter; atomic_dec(v); return -EINVAL;} /* Decrement the counter. Return the resulting value, or -EINVAL */static int atomic_dec_return_safe(atomic_t *v){ int counter; counter = atomic_dec_return(v); if (counter >= 0) return counter; atomic_inc(v); return -EINVAL;} #define RBD_DRV_NAME "rbd" #define RBD_MINORS_PER_MAJOR 256#define RBD_SINGLE_MAJOR_PART_SHIFT 4 #define RBD_MAX_PARENT_CHAIN_LEN 16 #define RBD_SNAP_DEV_NAME_PREFIX "snap_"#define RBD_MAX_SNAP_NAME_LEN \ (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1)) #define RBD_MAX_SNAP_COUNT 510 /* allows max snapc to fit in 4KB */ #define RBD_SNAP_HEAD_NAME "-" #define BAD_SNAP_INDEX U32_MAX /* invalid index into snap array */ /* This allows a single page to hold an image name sent by OSD */#define RBD_IMAGE_NAME_LEN_MAX (PAGE_SIZE - sizeof (__le32) - 1)#define RBD_IMAGE_ID_LEN_MAX 64 #define RBD_OBJ_PREFIX_LEN_MAX 64 #define RBD_NOTIFY_TIMEOUT 5 /* seconds */#define RBD_RETRY_DELAY msecs_to_jiffies(1000) /* Feature bits */ #define RBD_FEATURE_LAYERING (1ULL<<0)#define RBD_FEATURE_STRIPINGV2 (1ULL<<1)#define RBD_FEATURE_EXCLUSIVE_LOCK (1ULL<<2)#define RBD_FEATURE_OBJECT_MAP (1ULL<<3)#define RBD_FEATURE_FAST_DIFF (1ULL<<4)#define RBD_FEATURE_DEEP_FLATTEN (1ULL<<5)#define RBD_FEATURE_DATA_POOL (1ULL<<7)#define RBD_FEATURE_OPERATIONS (1ULL<<8) #define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING | \ RBD_FEATURE_STRIPINGV2 | \ RBD_FEATURE_EXCLUSIVE_LOCK | \ RBD_FEATURE_OBJECT_MAP | \ RBD_FEATURE_FAST_DIFF | \ RBD_FEATURE_DEEP_FLATTEN | \ RBD_FEATURE_DATA_POOL | \ RBD_FEATURE_OPERATIONS) /* Features supported by this (client software) implementation. */ #define RBD_FEATURES_SUPPORTED (RBD_FEATURES_ALL) /* * 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 32 /* * block device image metadata (in-memory version) */struct rbd_image_header { /* These six fields never change for a given rbd image */ char *object_prefix; __u8 obj_order; u64 stripe_unit; u64 stripe_count; s64 data_pool_id; u64 features; /* Might be changeable someday? */ /* The remaining fields need to be updated occasionally */ u64 image_size; struct ceph_snap_context *snapc; char *snap_names; /* format 1 only */ u64 *snap_sizes; /* format 1 only */}; /* * 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 { u64 pool_id; const char *pool_name; const char *pool_ns; /* NULL if default, never "" */ const char *image_id; const char *image_name; u64 snap_id; const char *snap_name; struct kref kref;}; /* * an instance of the client. multiple devices may share an rbd client. */struct rbd_client { struct ceph_client *client; struct kref kref; struct list_head node;}; struct pending_result { int result; /* first nonzero result */ int num_pending;}; struct rbd_img_request; enum obj_request_type { OBJ_REQUEST_NODATA = 1, OBJ_REQUEST_BIO, /* pointer into provided bio (list) */ OBJ_REQUEST_BVECS, /* pointer into provided bio_vec array */ OBJ_REQUEST_OWN_BVECS, /* private bio_vec array, doesn't own pages */}; enum obj_operation_type { OBJ_OP_READ = 1, OBJ_OP_WRITE, OBJ_OP_DISCARD, OBJ_OP_ZEROOUT,}; #define RBD_OBJ_FLAG_DELETION (1U << 0)#define RBD_OBJ_FLAG_COPYUP_ENABLED (1U << 1)#define RBD_OBJ_FLAG_COPYUP_ZEROS (1U << 2)#define RBD_OBJ_FLAG_MAY_EXIST (1U << 3)#define RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT (1U << 4) enum rbd_obj_read_state { RBD_OBJ_READ_START = 1, RBD_OBJ_READ_OBJECT, RBD_OBJ_READ_PARENT,}; /* * 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 { RBD_OBJ_WRITE_START = 1, RBD_OBJ_WRITE_PRE_OBJECT_MAP, RBD_OBJ_WRITE_OBJECT, __RBD_OBJ_WRITE_COPYUP, RBD_OBJ_WRITE_COPYUP, RBD_OBJ_WRITE_POST_OBJECT_MAP,}; enum rbd_obj_copyup_state { RBD_OBJ_COPYUP_START = 1, RBD_OBJ_COPYUP_READ_PARENT, __RBD_OBJ_COPYUP_OBJECT_MAPS, RBD_OBJ_COPYUP_OBJECT_MAPS, __RBD_OBJ_COPYUP_WRITE_OBJECT, RBD_OBJ_COPYUP_WRITE_OBJECT,}; struct rbd_obj_request { struct ceph_object_extent ex; unsigned int flags; /* RBD_OBJ_FLAG_* */ union { enum rbd_obj_read_state read_state; /* for reads */ enum rbd_obj_write_state write_state; /* for writes */ }; struct rbd_img_request *img_request; struct ceph_file_extent *img_extents; u32 num_img_extents; union { struct ceph_bio_iter bio_pos; struct { struct ceph_bvec_iter bvec_pos; u32 bvec_count; u32 bvec_idx; }; }; enum rbd_obj_copyup_state copyup_state; struct bio_vec *copyup_bvecs; u32 copyup_bvec_count; struct list_head osd_reqs; /* w/ r_private_item */ struct mutex state_mutex; struct pending_result pending; struct kref kref;}; enum img_req_flags { IMG_REQ_CHILD, /* initiator: block = 0, child image = 1 */ IMG_REQ_LAYERED, /* ENOENT handling: normal = 0, layered = 1 */}; enum rbd_img_state { RBD_IMG_START = 1, RBD_IMG_EXCLUSIVE_LOCK, __RBD_IMG_OBJECT_REQUESTS, RBD_IMG_OBJECT_REQUESTS,}; struct rbd_img_request { struct rbd_device *rbd_dev; enum obj_operation_type op_type; enum obj_request_type data_type; unsigned long flags; enum rbd_img_state state; union { u64 snap_id; /* for reads */ struct ceph_snap_context *snapc; /* for writes */ }; struct rbd_obj_request *obj_request; /* obj req initiator */ struct list_head lock_item; struct list_head object_extents; /* obj_req.ex structs */ struct mutex state_mutex; struct pending_result pending; struct work_struct work; int work_result;}; #define for_each_obj_request(ireq, oreq) \ list_for_each_entry(oreq, &(ireq)->object_extents, ex.oe_item)#define for_each_obj_request_safe(ireq, oreq, n) \ list_for_each_entry_safe(oreq, n, &(ireq)->object_extents, ex.oe_item) enum rbd_watch_state { RBD_WATCH_STATE_UNREGISTERED, RBD_WATCH_STATE_REGISTERED, RBD_WATCH_STATE_ERROR,}; enum rbd_lock_state { RBD_LOCK_STATE_UNLOCKED, RBD_LOCK_STATE_LOCKED, RBD_LOCK_STATE_QUIESCING,}; /* WatchNotify::ClientId */struct rbd_client_id { u64 gid; u64 handle;}; struct rbd_mapping { u64 size;}; /* * a single device */struct rbd_device { int dev_id; /* blkdev unique id */ int major; /* blkdev assigned major */ int minor; struct gendisk *disk; /* blkdev's gendisk and rq */ u32 image_format; /* Either 1 or 2 */ struct rbd_client *rbd_client; char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */ spinlock_t lock; /* queue, flags, open_count */ struct rbd_image_header header; unsigned long flags; /* possibly lock protected */ struct rbd_spec *spec; struct rbd_options *opts; char *config_info; /* add{,_single_major} string */ struct ceph_object_id header_oid; struct ceph_object_locator header_oloc; struct ceph_file_layout layout; /* used for all rbd requests */ struct mutex watch_mutex; enum rbd_watch_state watch_state; struct ceph_osd_linger_request *watch_handle; u64 watch_cookie; struct delayed_work watch_dwork; struct rw_semaphore lock_rwsem; enum rbd_lock_state lock_state; char lock_cookie[32]; struct rbd_client_id owner_cid; struct work_struct acquired_lock_work; struct work_struct released_lock_work; struct delayed_work lock_dwork; struct work_struct unlock_work; spinlock_t lock_lists_lock; struct list_head acquiring_list; struct list_head running_list; struct completion acquire_wait; int acquire_err; struct completion quiescing_wait; spinlock_t object_map_lock; u8 *object_map; u64 object_map_size; /* in objects */ u64 object_map_flags; struct workqueue_struct *task_wq; struct rbd_spec *parent_spec; u64 parent_overlap; atomic_t parent_ref; struct rbd_device *parent; /* Block layer tags. */ struct blk_mq_tag_set tag_set; /* protects updating the header */ struct rw_semaphore header_rwsem; struct rbd_mapping mapping; struct list_head node; /* sysfs related */ struct device dev; unsigned long open_count; /* protected by lock */}; /* * 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 { RBD_DEV_FLAG_EXISTS, /* rbd_dev_device_setup() ran */ RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */ RBD_DEV_FLAG_READONLY, /* -o ro or snapshot */}; 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 = { .nref = REFCOUNT_INIT(1),}; /* * single-major requires >= 0.75 version of userspace rbd utility. */static bool single_major = true;module_param(single_major, bool, 0444);MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: true)"); 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);Lines 1–500 of 7445. Load more
/* 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 /* Activate rbd_assert() calls */ /* * 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) { unsigned int counter; counter = (unsigned int)atomic_fetch_add_unless(v, 1, 0); if (counter <= (unsigned int)INT_MAX) return (int)counter; atomic_dec(v); return -EINVAL; } /* Decrement the counter. Return the resulting value, or -EINVAL */ static int atomic_dec_return_safe(atomic_t *v) { int counter; counter = atomic_dec_return(v); if (counter >= 0) return counter; atomic_inc(v); return -EINVAL; } #define RBD_DRV_NAME "rbd" #define RBD_MINORS_PER_MAJOR 256 #define RBD_SINGLE_MAJOR_PART_SHIFT 4 #define RBD_MAX_PARENT_CHAIN_LEN 16 #define RBD_SNAP_DEV_NAME_PREFIX "snap_" #define RBD_MAX_SNAP_NAME_LEN \ (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1)) #define RBD_MAX_SNAP_COUNT 510 /* allows max snapc to fit in 4KB */ #define RBD_SNAP_HEAD_NAME "-" #define BAD_SNAP_INDEX U32_MAX /* invalid index into snap array */ /* This allows a single page to hold an image name sent by OSD */ #define RBD_IMAGE_NAME_LEN_MAX (PAGE_SIZE - sizeof (__le32) - 1) #define RBD_IMAGE_ID_LEN_MAX 64 #define RBD_OBJ_PREFIX_LEN_MAX 64 #define RBD_NOTIFY_TIMEOUT 5 /* seconds */ #define RBD_RETRY_DELAY msecs_to_jiffies(1000) /* Feature bits */ #define RBD_FEATURE_LAYERING (1ULL<<0) #define RBD_FEATURE_STRIPINGV2 (1ULL<<1) #define RBD_FEATURE_EXCLUSIVE_LOCK (1ULL<<2) #define RBD_FEATURE_OBJECT_MAP (1ULL<<3) #define RBD_FEATURE_FAST_DIFF (1ULL<<4) #define RBD_FEATURE_DEEP_FLATTEN (1ULL<<5) #define RBD_FEATURE_DATA_POOL (1ULL<<7) #define RBD_FEATURE_OPERATIONS (1ULL<<8) #define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING | \ RBD_FEATURE_STRIPINGV2 | \ RBD_FEATURE_EXCLUSIVE_LOCK | \ RBD_FEATURE_OBJECT_MAP | \ RBD_FEATURE_FAST_DIFF | \ RBD_FEATURE_DEEP_FLATTEN | \ RBD_FEATURE_DATA_POOL | \ RBD_FEATURE_OPERATIONS) /* Features supported by this (client software) implementation. */ #define RBD_FEATURES_SUPPORTED (RBD_FEATURES_ALL) /* * 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 32 /* * block device image metadata (in-memory version) */ struct rbd_image_header { /* These six fields never change for a given rbd image */ char *object_prefix; __u8 obj_order; u64 stripe_unit; u64 stripe_count; s64 data_pool_id; u64 features; /* Might be changeable someday? */ /* The remaining fields need to be updated occasionally */ u64 image_size; struct ceph_snap_context *snapc; char *snap_names; /* format 1 only */ u64 *snap_sizes; /* format 1 only */ }; /* * 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 { u64 pool_id; const char *pool_name; const char *pool_ns; /* NULL if default, never "" */ const char *image_id; const char *image_name; u64 snap_id; const char *snap_name; struct kref kref; }; /* * an instance of the client. multiple devices may share an rbd client. */ struct rbd_client { struct ceph_client *client; struct kref kref; struct list_head node; }; struct pending_result { int result; /* first nonzero result */ int num_pending; }; struct rbd_img_request; enum obj_request_type { OBJ_REQUEST_NODATA = 1, OBJ_REQUEST_BIO, /* pointer into provided bio (list) */ OBJ_REQUEST_BVECS, /* pointer into provided bio_vec array */ OBJ_REQUEST_OWN_BVECS, /* private bio_vec array, doesn't own pages */ }; enum obj_operation_type { OBJ_OP_READ = 1, OBJ_OP_WRITE, OBJ_OP_DISCARD, OBJ_OP_ZEROOUT, }; #define RBD_OBJ_FLAG_DELETION (1U << 0) #define RBD_OBJ_FLAG_COPYUP_ENABLED (1U << 1) #define RBD_OBJ_FLAG_COPYUP_ZEROS (1U << 2) #define RBD_OBJ_FLAG_MAY_EXIST (1U << 3) #define RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT (1U << 4) enum rbd_obj_read_state { RBD_OBJ_READ_START = 1, RBD_OBJ_READ_OBJECT, RBD_OBJ_READ_PARENT, }; /* * 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 { RBD_OBJ_WRITE_START = 1, RBD_OBJ_WRITE_PRE_OBJECT_MAP, RBD_OBJ_WRITE_OBJECT, __RBD_OBJ_WRITE_COPYUP, RBD_OBJ_WRITE_COPYUP, RBD_OBJ_WRITE_POST_OBJECT_MAP, }; enum rbd_obj_copyup_state { RBD_OBJ_COPYUP_START = 1, RBD_OBJ_COPYUP_READ_PARENT, __RBD_OBJ_COPYUP_OBJECT_MAPS, RBD_OBJ_COPYUP_OBJECT_MAPS, __RBD_OBJ_COPYUP_WRITE_OBJECT, RBD_OBJ_COPYUP_WRITE_OBJECT, }; struct rbd_obj_request { struct ceph_object_extent ex; unsigned int flags; /* RBD_OBJ_FLAG_* */ union { enum rbd_obj_read_state read_state; /* for reads */ enum rbd_obj_write_state write_state; /* for writes */ }; struct rbd_img_request *img_request; struct ceph_file_extent *img_extents; u32 num_img_extents; union { struct ceph_bio_iter bio_pos; struct { struct ceph_bvec_iter bvec_pos; u32 bvec_count; u32 bvec_idx; }; }; enum rbd_obj_copyup_state copyup_state; struct bio_vec *copyup_bvecs; u32 copyup_bvec_count; struct list_head osd_reqs; /* w/ r_private_item */ struct mutex state_mutex; struct pending_result pending; struct kref kref; }; enum img_req_flags { IMG_REQ_CHILD, /* initiator: block = 0, child image = 1 */ IMG_REQ_LAYERED, /* ENOENT handling: normal = 0, layered = 1 */ }; enum rbd_img_state { RBD_IMG_START = 1, RBD_IMG_EXCLUSIVE_LOCK, __RBD_IMG_OBJECT_REQUESTS, RBD_IMG_OBJECT_REQUESTS, }; struct rbd_img_request { struct rbd_device *rbd_dev; enum obj_operation_type op_type; enum obj_request_type data_type; unsigned long flags; enum rbd_img_state state; union { u64 snap_id; /* for reads */ struct ceph_snap_context *snapc; /* for writes */ }; struct rbd_obj_request *obj_request; /* obj req initiator */ struct list_head lock_item; struct list_head object_extents; /* obj_req.ex structs */ struct mutex state_mutex; struct pending_result pending; struct work_struct work; int work_result; }; #define for_each_obj_request(ireq, oreq) \ list_for_each_entry(oreq, &(ireq)->object_extents, ex.oe_item) #define for_each_obj_request_safe(ireq, oreq, n) \ list_for_each_entry_safe(oreq, n, &(ireq)->object_extents, ex.oe_item) enum rbd_watch_state { RBD_WATCH_STATE_UNREGISTERED, RBD_WATCH_STATE_REGISTERED, RBD_WATCH_STATE_ERROR, }; enum rbd_lock_state { RBD_LOCK_STATE_UNLOCKED, RBD_LOCK_STATE_LOCKED, RBD_LOCK_STATE_QUIESCING, }; /* WatchNotify::ClientId */ struct rbd_client_id { u64 gid; u64 handle; }; struct rbd_mapping { u64 size; }; /* * a single device */ struct rbd_device { int dev_id; /* blkdev unique id */ int major; /* blkdev assigned major */ int minor; struct gendisk *disk; /* blkdev's gendisk and rq */ u32 image_format; /* Either 1 or 2 */ struct rbd_client *rbd_client; char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */ spinlock_t lock; /* queue, flags, open_count */ struct rbd_image_header header; unsigned long flags; /* possibly lock protected */ struct rbd_spec *spec; struct rbd_options *opts; char *config_info; /* add{,_single_major} string */ struct ceph_object_id header_oid; struct ceph_object_locator header_oloc; struct ceph_file_layout layout; /* used for all rbd requests */ struct mutex watch_mutex; enum rbd_watch_state watch_state; struct ceph_osd_linger_request *watch_handle; u64 watch_cookie; struct delayed_work watch_dwork; struct rw_semaphore lock_rwsem; enum rbd_lock_state lock_state; char lock_cookie[32]; struct rbd_client_id owner_cid; struct work_struct acquired_lock_work; struct work_struct released_lock_work; struct delayed_work lock_dwork; struct work_struct unlock_work; spinlock_t lock_lists_lock; struct list_head acquiring_list; struct list_head running_list; struct completion acquire_wait; int acquire_err; struct completion quiescing_wait; spinlock_t object_map_lock; u8 *object_map; u64 object_map_size; /* in objects */ u64 object_map_flags; struct workqueue_struct *task_wq; struct rbd_spec *parent_spec; u64 parent_overlap; atomic_t parent_ref; struct rbd_device *parent; /* Block layer tags. */ struct blk_mq_tag_set tag_set; /* protects updating the header */ struct rw_semaphore header_rwsem; struct rbd_mapping mapping; struct list_head node; /* sysfs related */ struct device dev; unsigned long open_count; /* protected by lock */ }; /* * 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 { RBD_DEV_FLAG_EXISTS, /* rbd_dev_device_setup() ran */ RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */ RBD_DEV_FLAG_READONLY, /* -o ro or snapshot */ }; 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 = { .nref = REFCOUNT_INIT(1), }; /* * single-major requires >= 0.75 version of userspace rbd utility. */ static bool single_major = true; module_param(single_major, bool, 0444); MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: true)"); 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);