static int rbd_dev_snaps_update(struct rbd_device *rbd_dev);
-static void rbd_dev_release(struct device *dev);
+static void rbd_dev_device_release(struct device *dev);
static void rbd_snap_destroy(struct rbd_snap *snap);
static ssize_t rbd_add(struct bus_type *bus, const char *buf,
kfree(rbdc);
}
-/* Caller has to fill in snapc->seq and snapc->snaps[0..snap_count-1] */
-
-static struct ceph_snap_context *rbd_snap_context_create(u32 snap_count)
-{
- struct ceph_snap_context *snapc;
- size_t size;
-
- size = sizeof (struct ceph_snap_context);
- size += snap_count * sizeof (snapc->snaps[0]);
- snapc = kzalloc(size, GFP_KERNEL);
- if (!snapc)
- return NULL;
-
- atomic_set(&snapc->nref, 1);
- snapc->num_snaps = snap_count;
-
- return snapc;
-}
-
-static inline void rbd_snap_context_get(struct ceph_snap_context *snapc)
-{
- (void)ceph_get_snap_context(snapc);
-}
-
-static inline void rbd_snap_context_put(struct ceph_snap_context *snapc)
-{
- ceph_put_snap_context(snapc);
-}
-
/*
* Drop reference to ceph client node. If it's not referenced anymore, release
* it.
header->image_size = le64_to_cpu(ondisk->image_size);
- header->snapc = rbd_snap_context_create(snap_count);
+ header->snapc = ceph_create_snap_context(snap_count, GFP_KERNEL);
if (!header->snapc)
goto out_err;
header->snapc->seq = le64_to_cpu(ondisk->snap_seq);
rbd_dev->mapping.read_only = true;
}
-static void rbd_header_free(struct rbd_image_header *header)
+static void rbd_dev_clear_mapping(struct rbd_device *rbd_dev)
{
- kfree(header->object_prefix);
- header->object_prefix = NULL;
- kfree(header->snap_sizes);
- header->snap_sizes = NULL;
- kfree(header->snap_names);
- header->snap_names = NULL;
- rbd_snap_context_put(header->snapc);
- header->snapc = NULL;
+ rbd_dev->mapping.size = 0;
+ rbd_dev->mapping.features = 0;
+ rbd_dev->mapping.read_only = true;
}
static const char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset)
if (write_request) {
down_read(&rbd_dev->header_rwsem);
- rbd_snap_context_get(rbd_dev->header.snapc);
+ ceph_get_snap_context(rbd_dev->header.snapc);
up_read(&rbd_dev->header_rwsem);
}
rbd_assert(img_request->obj_request_count == 0);
if (img_request_write_test(img_request))
- rbd_snap_context_put(img_request->snapc);
+ ceph_put_snap_context(img_request->snapc);
if (img_request_child_test(img_request))
rbd_obj_request_put(img_request->obj_request);
kfree(rbd_dev->header.snap_sizes);
kfree(rbd_dev->header.snap_names);
/* osd requests may still refer to snapc */
- rbd_snap_context_put(rbd_dev->header.snapc);
+ ceph_put_snap_context(rbd_dev->header.snapc);
if (hver)
*hver = h.obj_version;
static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver)
{
+ u64 image_size;
int ret;
rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+ image_size = rbd_dev->header.image_size;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
if (rbd_dev->image_format == 1)
ret = rbd_dev_v1_refresh(rbd_dev, hver);
else
ret = rbd_dev_v2_refresh(rbd_dev, hver);
mutex_unlock(&ctl_mutex);
- revalidate_disk(rbd_dev->disk);
if (ret)
rbd_warn(rbd_dev, "got notification but failed to "
" update snaps: %d\n", ret);
+ if (image_size != rbd_dev->header.image_size)
+ revalidate_disk(rbd_dev->disk);
return ret;
}
goto out;
ret = 0;
- snapc = rbd_snap_context_create(snap_count);
+ snapc = ceph_create_snap_context(snap_count, GFP_KERNEL);
if (!snapc) {
ret = -ENOMEM;
goto out;
static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver)
{
int ret;
- __u8 obj_order;
down_write(&rbd_dev->header_rwsem);
- /* Grab old order first, to see if it changes */
-
- obj_order = rbd_dev->header.obj_order,
ret = rbd_dev_v2_image_size(rbd_dev);
if (ret)
goto out;
- if (rbd_dev->header.obj_order != obj_order) {
- ret = -EIO;
- goto out;
- }
rbd_update_mapping_size(rbd_dev);
ret = rbd_dev_v2_snap_context(rbd_dev, hver);
dev->bus = &rbd_bus_type;
dev->type = &rbd_device_type;
dev->parent = &rbd_root_dev;
- dev->release = rbd_dev_release;
+ dev->release = rbd_dev_device_release;
dev_set_name(dev, "%d", rbd_dev->dev_id);
ret = device_register(dev);
return ret;
}
-static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
+/* Undo whatever state changes are made by v1 or v2 image probe */
+
+static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
{
- int ret;
- size_t size;
+ struct rbd_image_header *header;
- /* Record the header object name for this rbd image. */
+ rbd_dev_remove_parent(rbd_dev);
+ rbd_spec_put(rbd_dev->parent_spec);
+ rbd_dev->parent_spec = NULL;
+ rbd_dev->parent_overlap = 0;
- size = strlen(rbd_dev->spec->image_name) + sizeof (RBD_SUFFIX);
- rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
- if (!rbd_dev->header_name) {
- ret = -ENOMEM;
- goto out_err;
- }
- sprintf(rbd_dev->header_name, "%s%s",
- rbd_dev->spec->image_name, RBD_SUFFIX);
+ /* Free dynamic fields from the header, then zero it out */
+
+ header = &rbd_dev->header;
+ ceph_put_snap_context(header->snapc);
+ kfree(header->snap_sizes);
+ kfree(header->snap_names);
+ kfree(header->object_prefix);
+ memset(header, 0, sizeof (*header));
+}
+
+static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
+{
+ int ret;
/* Populate rbd image metadata */
static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
{
- size_t size;
int ret;
u64 ver = 0;
- /*
- * Image id was filled in by the caller. Record the header
- * object name for this rbd image.
- */
- size = sizeof (RBD_HEADER_PREFIX) + strlen(rbd_dev->spec->image_id);
- rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
- if (!rbd_dev->header_name)
- return -ENOMEM;
- sprintf(rbd_dev->header_name, "%s%s",
- RBD_HEADER_PREFIX, rbd_dev->spec->image_id);
-
- /* Get the size and object order for the image */
ret = rbd_dev_v2_image_size(rbd_dev);
if (ret)
goto out_err;
ret = rbd_dev_v2_parent_info(rbd_dev);
if (ret)
goto out_err;
- rbd_warn(rbd_dev, "WARNING: kernel support for "
- "layered rbd images is EXPERIMENTAL!");
+
+ /*
+ * Don't print a warning for parent images. We can
+ * tell this point because we won't know its pool
+ * name yet (just its pool id).
+ */
+ if (rbd_dev->spec->pool_name)
+ rbd_warn(rbd_dev, "WARNING: kernel layering "
+ "is EXPERIMENTAL!");
}
/* If the image supports fancy striping, get its parameters */
return ret;
}
-static int rbd_dev_probe_finish(struct rbd_device *rbd_dev)
+static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
{
int ret;
- ret = rbd_dev_header_watch_sync(rbd_dev, 1);
- if (ret)
- return ret;
-
ret = rbd_dev_mapping_set(rbd_dev);
if (ret)
return ret;
return ret;
}
+static int rbd_dev_header_name(struct rbd_device *rbd_dev)
+{
+ struct rbd_spec *spec = rbd_dev->spec;
+ size_t size;
+
+ /* Record the header object name for this rbd image. */
+
+ rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+
+ if (rbd_dev->image_format == 1)
+ size = strlen(spec->image_name) + sizeof (RBD_SUFFIX);
+ else
+ size = sizeof (RBD_HEADER_PREFIX) + strlen(spec->image_id);
+
+ rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
+ if (!rbd_dev->header_name)
+ return -ENOMEM;
+
+ if (rbd_dev->image_format == 1)
+ sprintf(rbd_dev->header_name, "%s%s",
+ spec->image_name, RBD_SUFFIX);
+ else
+ sprintf(rbd_dev->header_name, "%s%s",
+ RBD_HEADER_PREFIX, spec->image_id);
+ return 0;
+}
+
+static void rbd_dev_image_release(struct rbd_device *rbd_dev)
+{
+ int ret;
+
+ rbd_remove_all_snaps(rbd_dev);
+ rbd_dev_unprobe(rbd_dev);
+ ret = rbd_dev_header_watch_sync(rbd_dev, 0);
+ if (ret)
+ rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret);
+ kfree(rbd_dev->header_name);
+ rbd_dev->header_name = NULL;
+ rbd_dev->image_format = 0;
+ kfree(rbd_dev->spec->image_id);
+ rbd_dev->spec->image_id = NULL;
+
+ rbd_dev_destroy(rbd_dev);
+}
+
/*
* Probe for the existence of the header object for the given rbd
* device. For format 2 images this includes determining the image
static int rbd_dev_image_probe(struct rbd_device *rbd_dev)
{
int ret;
+ int tmp;
/*
* Get the id from the image id object. If it's not a
rbd_assert(rbd_dev->spec->image_id);
rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+ ret = rbd_dev_header_name(rbd_dev);
+ if (ret)
+ goto err_out_format;
+
+ ret = rbd_dev_header_watch_sync(rbd_dev, 1);
+ if (ret)
+ goto out_header_name;
+
if (rbd_dev->image_format == 1)
ret = rbd_dev_v1_probe(rbd_dev);
else
ret = rbd_dev_v2_probe(rbd_dev);
if (ret)
- goto out_err;
+ goto err_out_watch;
ret = rbd_dev_snaps_update(rbd_dev);
if (ret)
- goto out_err;
+ goto err_out_probe;
ret = rbd_dev_spec_update(rbd_dev);
if (ret)
goto err_out_snaps;
ret = rbd_dev_probe_parent(rbd_dev);
- if (ret)
- goto err_out_snaps;
-
- ret = rbd_dev_probe_finish(rbd_dev);
- if (ret)
- goto err_out_parent;
+ if (!ret)
+ return 0;
- return ret;
-err_out_parent:
- rbd_dev_remove_parent(rbd_dev);
- rbd_header_free(&rbd_dev->header);
err_out_snaps:
rbd_remove_all_snaps(rbd_dev);
-out_err:
+err_out_probe:
+ rbd_dev_unprobe(rbd_dev);
+err_out_watch:
+ tmp = rbd_dev_header_watch_sync(rbd_dev, 0);
+ if (tmp)
+ rbd_warn(rbd_dev, "unable to tear down watch request\n");
+out_header_name:
+ kfree(rbd_dev->header_name);
+ rbd_dev->header_name = NULL;
+err_out_format:
+ rbd_dev->image_format = 0;
kfree(rbd_dev->spec->image_id);
rbd_dev->spec->image_id = NULL;
if (rc < 0)
goto err_out_rbd_dev;
- return count;
+ rc = rbd_dev_device_setup(rbd_dev);
+ if (!rc)
+ return count;
+
+ rbd_dev_image_release(rbd_dev);
err_out_rbd_dev:
- kfree(rbd_dev->header_name);
rbd_dev_destroy(rbd_dev);
err_out_client:
rbd_put_client(rbdc);
return NULL;
}
-static void rbd_dev_release(struct device *dev)
+static void rbd_dev_device_release(struct device *dev)
{
struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
- if (rbd_dev->watch_event)
- rbd_dev_header_watch_sync(rbd_dev, 0);
-
- /* clean up and free blkdev */
rbd_free_disk(rbd_dev);
+ clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
+ rbd_dev_clear_mapping(rbd_dev);
unregister_blkdev(rbd_dev->major, rbd_dev->name);
-
- /* release allocated disk header fields */
- rbd_header_free(&rbd_dev->header);
-
- /* done with the id, and with the rbd_dev */
+ rbd_dev->major = 0;
rbd_dev_id_put(rbd_dev);
rbd_dev_mapping_clear(rbd_dev);
- rbd_assert(rbd_dev->rbd_client != NULL);
- rbd_spec_put(rbd_dev->parent_spec);
- kfree(rbd_dev->header_name);
- rbd_dev_destroy(rbd_dev);
-
- /* release module ref */
- module_put(THIS_MODULE);
}
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
second = third;
}
rbd_assert(second);
- rbd_remove_all_snaps(second);
- rbd_bus_del_dev(second);
+ rbd_dev_image_release(second);
first->parent = NULL;
first->parent_overlap = 0;
size_t count)
{
struct rbd_device *rbd_dev = NULL;
- int target_id, rc;
+ int target_id;
unsigned long ul;
- int ret = count;
+ int ret;
- rc = strict_strtoul(buf, 10, &ul);
- if (rc)
- return rc;
+ ret = strict_strtoul(buf, 10, &ul);
+ if (ret)
+ return ret;
/* convert to int; abort if we lost anything in the conversion */
target_id = (int) ul;
spin_unlock_irq(&rbd_dev->lock);
if (ret < 0)
goto done;
-
- rbd_dev_remove_parent(rbd_dev);
-
- rbd_remove_all_snaps(rbd_dev);
+ ret = count;
rbd_bus_del_dev(rbd_dev);
+ rbd_dev_image_release(rbd_dev);
+ module_put(THIS_MODULE);
done:
mutex_unlock(&ctl_mutex);