|
@@ -1471,6 +1471,88 @@ success:
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static struct block_device *open_backing_dev(struct drbd_device *device,
|
|
|
|
+ const char *bdev_path, void *claim_ptr, bool do_bd_link)
|
|
|
|
+{
|
|
|
|
+ struct block_device *bdev;
|
|
|
|
+ int err = 0;
|
|
|
|
+
|
|
|
|
+ bdev = blkdev_get_by_path(bdev_path,
|
|
|
|
+ FMODE_READ | FMODE_WRITE | FMODE_EXCL, claim_ptr);
|
|
|
|
+ if (IS_ERR(bdev)) {
|
|
|
|
+ drbd_err(device, "open(\"%s\") failed with %ld\n",
|
|
|
|
+ bdev_path, PTR_ERR(bdev));
|
|
|
|
+ return bdev;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!do_bd_link)
|
|
|
|
+ return bdev;
|
|
|
|
+
|
|
|
|
+ err = bd_link_disk_holder(bdev, device->vdisk);
|
|
|
|
+ if (err) {
|
|
|
|
+ blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
|
|
|
|
+ drbd_err(device, "bd_link_disk_holder(\"%s\", ...) failed with %d\n",
|
|
|
|
+ bdev_path, err);
|
|
|
|
+ bdev = ERR_PTR(err);
|
|
|
|
+ }
|
|
|
|
+ return bdev;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int open_backing_devices(struct drbd_device *device,
|
|
|
|
+ struct disk_conf *new_disk_conf,
|
|
|
|
+ struct drbd_backing_dev *nbc)
|
|
|
|
+{
|
|
|
|
+ struct block_device *bdev;
|
|
|
|
+
|
|
|
|
+ bdev = open_backing_dev(device, new_disk_conf->backing_dev, device, true);
|
|
|
|
+ if (IS_ERR(bdev))
|
|
|
|
+ return ERR_OPEN_DISK;
|
|
|
|
+ nbc->backing_bdev = bdev;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * meta_dev_idx >= 0: external fixed size, possibly multiple
|
|
|
|
+ * drbd sharing one meta device. TODO in that case, paranoia
|
|
|
|
+ * check that [md_bdev, meta_dev_idx] is not yet used by some
|
|
|
|
+ * other drbd minor! (if you use drbd.conf + drbdadm, that
|
|
|
|
+ * should check it for you already; but if you don't, or
|
|
|
|
+ * someone fooled it, we need to double check here)
|
|
|
|
+ */
|
|
|
|
+ bdev = open_backing_dev(device, new_disk_conf->meta_dev,
|
|
|
|
+ /* claim ptr: device, if claimed exclusively; shared drbd_m_holder,
|
|
|
|
+ * if potentially shared with other drbd minors */
|
|
|
|
+ (new_disk_conf->meta_dev_idx < 0) ? (void*)device : (void*)drbd_m_holder,
|
|
|
|
+ /* avoid double bd_claim_by_disk() for the same (source,target) tuple,
|
|
|
|
+ * as would happen with internal metadata. */
|
|
|
|
+ (new_disk_conf->meta_dev_idx != DRBD_MD_INDEX_FLEX_INT &&
|
|
|
|
+ new_disk_conf->meta_dev_idx != DRBD_MD_INDEX_INTERNAL));
|
|
|
|
+ if (IS_ERR(bdev))
|
|
|
|
+ return ERR_OPEN_MD_DISK;
|
|
|
|
+ nbc->md_bdev = bdev;
|
|
|
|
+ return NO_ERROR;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void close_backing_dev(struct drbd_device *device, struct block_device *bdev,
|
|
|
|
+ bool do_bd_unlink)
|
|
|
|
+{
|
|
|
|
+ if (!bdev)
|
|
|
|
+ return;
|
|
|
|
+ if (do_bd_unlink)
|
|
|
|
+ bd_unlink_disk_holder(bdev, device->vdisk);
|
|
|
|
+ blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev)
|
|
|
|
+{
|
|
|
|
+ if (ldev == NULL)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ close_backing_dev(device, ldev->md_bdev, ldev->md_bdev != ldev->backing_bdev);
|
|
|
|
+ close_backing_dev(device, ldev->backing_bdev, true);
|
|
|
|
+
|
|
|
|
+ kfree(ldev->disk_conf);
|
|
|
|
+ kfree(ldev);
|
|
|
|
+}
|
|
|
|
+
|
|
int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
|
int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
{
|
|
struct drbd_config_context adm_ctx;
|
|
struct drbd_config_context adm_ctx;
|
|
@@ -1484,7 +1566,6 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
|
sector_t min_md_device_sectors;
|
|
sector_t min_md_device_sectors;
|
|
struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
|
|
struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
|
|
struct disk_conf *new_disk_conf = NULL;
|
|
struct disk_conf *new_disk_conf = NULL;
|
|
- struct block_device *bdev;
|
|
|
|
struct lru_cache *resync_lru = NULL;
|
|
struct lru_cache *resync_lru = NULL;
|
|
struct fifo_buffer *new_plan = NULL;
|
|
struct fifo_buffer *new_plan = NULL;
|
|
union drbd_state ns, os;
|
|
union drbd_state ns, os;
|
|
@@ -1572,35 +1653,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
|
}
|
|
}
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
|
|
|
- bdev = blkdev_get_by_path(new_disk_conf->backing_dev,
|
|
|
|
- FMODE_READ | FMODE_WRITE | FMODE_EXCL, device);
|
|
|
|
- if (IS_ERR(bdev)) {
|
|
|
|
- drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->backing_dev,
|
|
|
|
- PTR_ERR(bdev));
|
|
|
|
- retcode = ERR_OPEN_DISK;
|
|
|
|
- goto fail;
|
|
|
|
- }
|
|
|
|
- nbc->backing_bdev = bdev;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * meta_dev_idx >= 0: external fixed size, possibly multiple
|
|
|
|
- * drbd sharing one meta device. TODO in that case, paranoia
|
|
|
|
- * check that [md_bdev, meta_dev_idx] is not yet used by some
|
|
|
|
- * other drbd minor! (if you use drbd.conf + drbdadm, that
|
|
|
|
- * should check it for you already; but if you don't, or
|
|
|
|
- * someone fooled it, we need to double check here)
|
|
|
|
- */
|
|
|
|
- bdev = blkdev_get_by_path(new_disk_conf->meta_dev,
|
|
|
|
- FMODE_READ | FMODE_WRITE | FMODE_EXCL,
|
|
|
|
- (new_disk_conf->meta_dev_idx < 0) ?
|
|
|
|
- (void *)device : (void *)drbd_m_holder);
|
|
|
|
- if (IS_ERR(bdev)) {
|
|
|
|
- drbd_err(device, "open(\"%s\") failed with %ld\n", new_disk_conf->meta_dev,
|
|
|
|
- PTR_ERR(bdev));
|
|
|
|
- retcode = ERR_OPEN_MD_DISK;
|
|
|
|
|
|
+ retcode = open_backing_devices(device, new_disk_conf, nbc);
|
|
|
|
+ if (retcode != NO_ERROR)
|
|
goto fail;
|
|
goto fail;
|
|
- }
|
|
|
|
- nbc->md_bdev = bdev;
|
|
|
|
|
|
|
|
if ((nbc->backing_bdev == nbc->md_bdev) !=
|
|
if ((nbc->backing_bdev == nbc->md_bdev) !=
|
|
(new_disk_conf->meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
|
|
(new_disk_conf->meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
|
|
@@ -1900,12 +1955,8 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
|
fail:
|
|
fail:
|
|
conn_reconfig_done(connection);
|
|
conn_reconfig_done(connection);
|
|
if (nbc) {
|
|
if (nbc) {
|
|
- if (nbc->backing_bdev)
|
|
|
|
- blkdev_put(nbc->backing_bdev,
|
|
|
|
- FMODE_READ | FMODE_WRITE | FMODE_EXCL);
|
|
|
|
- if (nbc->md_bdev)
|
|
|
|
- blkdev_put(nbc->md_bdev,
|
|
|
|
- FMODE_READ | FMODE_WRITE | FMODE_EXCL);
|
|
|
|
|
|
+ close_backing_dev(device, nbc->md_bdev, nbc->md_bdev != nbc->backing_bdev);
|
|
|
|
+ close_backing_dev(device, nbc->backing_bdev, true);
|
|
kfree(nbc);
|
|
kfree(nbc);
|
|
}
|
|
}
|
|
kfree(new_disk_conf);
|
|
kfree(new_disk_conf);
|