From: Philipp Reisner <philipp.reisner@linbit.com>
To: linux-kernel@vger.kernel.org, Jens Axboe <axboe@kernel.dk>
Cc: drbd-dev@lists.linbit.com
Subject: [PATCH 18/18] drbd: introduce in-kernel "down" command
Date: Thu, 1 Sep 2011 14:49:05 +0200 [thread overview]
Message-ID: <1314881345-6420-19-git-send-email-philipp.reisner@linbit.com> (raw)
In-Reply-To: <1314881345-6420-1-git-send-email-philipp.reisner@linbit.com>
From: Lars Ellenberg <lars.ellenberg@linbit.com>
This greatly simplifies deconfiguration of whole resources.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
---
drivers/block/drbd/drbd_main.c | 2 -
drivers/block/drbd/drbd_nl.c | 203 ++++++++++++++++++++++++++++++----------
include/linux/drbd_genl.h | 2 +
3 files changed, 154 insertions(+), 53 deletions(-)
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 2e79032..de49c8d 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -2303,9 +2303,7 @@ fail:
void drbd_free_tconn(struct drbd_tconn *tconn)
{
- mutex_lock(&drbd_cfg_mutex);
list_del(&tconn->all_tconn);
- mutex_unlock(&drbd_cfg_mutex);
idr_destroy(&tconn->volumes);
free_cpumask_var(tconn->cpu_mask);
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 773946d..2970f45 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -73,6 +73,7 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_create_connection(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_delete_connection(struct sk_buff *skb, struct genl_info *info);
+int drbd_adm_down(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info);
int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info);
@@ -1449,6 +1450,18 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
return 0;
}
+static int adm_detach(struct drbd_conf *mdev)
+{
+ enum drbd_ret_code retcode;
+ drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
+ retcode = drbd_request_state(mdev, NS(disk, D_DISKLESS));
+ wait_event(mdev->misc_wait,
+ mdev->state.disk != D_DISKLESS ||
+ !atomic_read(&mdev->local_cnt));
+ drbd_resume_io(mdev);
+ return retcode;
+}
+
/* Detaching the disk is a process in multiple stages. First we need to lock
* out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
* Then we transition to D_DISKLESS, and wait for put_ldev() to return all
@@ -1456,7 +1469,6 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
* Only then we have finally detached. */
int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
enum drbd_ret_code retcode;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
@@ -1465,13 +1477,7 @@ int drbd_adm_detach(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
- drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
- retcode = drbd_request_state(mdev, NS(disk, D_DISKLESS));
- wait_event(mdev->misc_wait,
- mdev->state.disk != D_DISKLESS ||
- !atomic_read(&mdev->local_cnt));
- drbd_resume_io(mdev);
+ retcode = adm_detach(adm_ctx.mdev);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -1713,10 +1719,49 @@ out:
return 0;
}
+static enum drbd_state_rv conn_try_disconnect(struct drbd_tconn *tconn, bool force)
+{
+ enum drbd_state_rv rv;
+ if (force) {
+ spin_lock_irq(&tconn->req_lock);
+ if (tconn->cstate >= C_WF_CONNECTION)
+ _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ spin_unlock_irq(&tconn->req_lock);
+ return SS_SUCCESS;
+ }
+
+ rv = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0);
+
+ switch (rv) {
+ case SS_NOTHING_TO_DO:
+ case SS_ALREADY_STANDALONE:
+ return SS_SUCCESS;
+ case SS_PRIMARY_NOP:
+ /* Our state checking code wants to see the peer outdated. */
+ rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+ pdsk, D_OUTDATED), CS_VERBOSE);
+ break;
+ case SS_CW_FAILED_BY_PEER:
+ /* The peer probably wants to see us outdated. */
+ rv = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+ disk, D_OUTDATED), 0);
+ if (rv == SS_IS_DISKLESS || rv == SS_LOWER_THAN_OUTDATED) {
+ conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+ rv = SS_SUCCESS;
+ }
+ break;
+ default:;
+ /* no special handling necessary */
+ }
+
+ return rv;
+}
+
int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
{
struct disconnect_parms parms;
struct drbd_tconn *tconn;
+ enum drbd_state_rv rv;
enum drbd_ret_code retcode;
int err;
@@ -1737,35 +1782,8 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
}
}
- if (parms.force_disconnect) {
- spin_lock_irq(&tconn->req_lock);
- if (tconn->cstate >= C_WF_CONNECTION)
- _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
- spin_unlock_irq(&tconn->req_lock);
- goto done;
- }
-
- retcode = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0);
-
- if (retcode == SS_NOTHING_TO_DO)
- goto done;
- else if (retcode == SS_ALREADY_STANDALONE)
- goto done;
- else if (retcode == SS_PRIMARY_NOP) {
- /* Our state checking code wants to see the peer outdated. */
- retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
- pdsk, D_OUTDATED), CS_VERBOSE);
- } else if (retcode == SS_CW_FAILED_BY_PEER) {
- /* The peer probably wants to see us outdated. */
- retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
- disk, D_OUTDATED), 0);
- if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) {
- conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
- retcode = SS_SUCCESS;
- }
- }
-
- if (retcode < SS_SUCCESS)
+ rv = conn_try_disconnect(tconn, parms.force_disconnect);
+ if (rv < SS_SUCCESS)
goto fail;
if (wait_event_interruptible(tconn->ping_wait,
@@ -1776,7 +1794,6 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
goto fail;
}
- done:
retcode = NO_ERROR;
fail:
drbd_adm_finish(info, retcode);
@@ -2677,9 +2694,21 @@ out:
return 0;
}
+static enum drbd_ret_code adm_delete_minor(struct drbd_conf *mdev)
+{
+ if (mdev->state.disk == D_DISKLESS &&
+ /* no need to be mdev->state.conn == C_STANDALONE &&
+ * we may want to delete a minor from a live replication group.
+ */
+ mdev->state.role == R_SECONDARY) {
+ drbd_delete_device(mdev_to_minor(mdev));
+ return NO_ERROR;
+ } else
+ return ERR_MINOR_CONFIGURED;
+}
+
int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
{
- struct drbd_conf *mdev;
enum drbd_ret_code retcode;
retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_MINOR);
@@ -2688,19 +2717,89 @@ int drbd_adm_delete_minor(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
- mdev = adm_ctx.mdev;
- if (mdev->state.disk == D_DISKLESS &&
- /* no need to be mdev->state.conn == C_STANDALONE &&
- * we may want to delete a minor from a live replication group.
- */
- mdev->state.role == R_SECONDARY) {
- drbd_delete_device(mdev_to_minor(mdev));
- retcode = NO_ERROR;
- /* if this was the last volume of this connection,
- * this will terminate all threads */
+ mutex_lock(&drbd_cfg_mutex);
+ retcode = adm_delete_minor(adm_ctx.mdev);
+ mutex_unlock(&drbd_cfg_mutex);
+ /* if this was the last volume of this connection,
+ * this will terminate all threads */
+ if (retcode == NO_ERROR)
conn_reconfig_done(adm_ctx.tconn);
- } else
- retcode = ERR_MINOR_CONFIGURED;
+out:
+ drbd_adm_finish(info, retcode);
+ return 0;
+}
+
+int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
+{
+ enum drbd_ret_code retcode;
+ enum drbd_state_rv rv;
+ struct drbd_conf *mdev;
+ unsigned i;
+
+ retcode = drbd_adm_prepare(skb, info, 0);
+ if (!adm_ctx.reply_skb)
+ return retcode;
+ if (retcode != NO_ERROR)
+ goto out;
+
+ if (!adm_ctx.tconn) {
+ retcode = ERR_CONN_NOT_KNOWN;
+ goto out;
+ }
+
+ mutex_lock(&drbd_cfg_mutex);
+ /* demote */
+ idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
+ retcode = drbd_set_role(mdev, R_SECONDARY, 0);
+ if (retcode < SS_SUCCESS) {
+ drbd_msg_put_info("failed to demote");
+ goto out_unlock;
+ }
+ }
+
+ /* disconnect */
+ rv = conn_try_disconnect(adm_ctx.tconn, 0);
+ if (rv < SS_SUCCESS) {
+ retcode = rv; /* enum type mismatch! */
+ drbd_msg_put_info("failed to disconnect");
+ goto out_unlock;
+ }
+
+ /* detach */
+ idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
+ rv = adm_detach(mdev);
+ if (rv < SS_SUCCESS) {
+ retcode = rv; /* enum type mismatch! */
+ drbd_msg_put_info("failed to detach");
+ goto out_unlock;
+ }
+ }
+
+ /* delete volumes */
+ idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
+ retcode = adm_delete_minor(mdev);
+ if (retcode != NO_ERROR) {
+ /* "can not happen" */
+ drbd_msg_put_info("failed to delete volume");
+ goto out_unlock;
+ }
+ }
+
+ /* stop all threads */
+ conn_reconfig_done(adm_ctx.tconn);
+
+ /* delete connection */
+ if (conn_lowest_minor(adm_ctx.tconn) < 0) {
+ drbd_free_tconn(adm_ctx.tconn);
+ retcode = NO_ERROR;
+ } else {
+ /* "can not happen" */
+ retcode = ERR_CONN_IN_USE;
+ drbd_msg_put_info("failed to delete connection");
+ goto out_unlock;
+ }
+out_unlock:
+ mutex_unlock(&drbd_cfg_mutex);
out:
drbd_adm_finish(info, retcode);
return 0;
@@ -2716,12 +2815,14 @@ int drbd_adm_delete_connection(struct sk_buff *skb, struct genl_info *info)
if (retcode != NO_ERROR)
goto out;
+ mutex_lock(&drbd_cfg_mutex);
if (conn_lowest_minor(adm_ctx.tconn) < 0) {
drbd_free_tconn(adm_ctx.tconn);
retcode = NO_ERROR;
} else {
retcode = ERR_CONN_IN_USE;
}
+ mutex_unlock(&drbd_cfg_mutex);
out:
drbd_adm_finish(info, retcode);
diff --git a/include/linux/drbd_genl.h b/include/linux/drbd_genl.h
index 84e1684..a07d692 100644
--- a/include/linux/drbd_genl.h
+++ b/include/linux/drbd_genl.h
@@ -347,3 +347,5 @@ GENL_op(DRBD_ADM_OUTDATE, 25, GENL_doit(drbd_adm_outdate),
GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, GENLA_F_REQUIRED))
GENL_op(DRBD_ADM_GET_TIMEOUT_TYPE, 26, GENL_doit(drbd_adm_get_timeout_type),
GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, GENLA_F_REQUIRED))
+GENL_op(DRBD_ADM_DOWN, 27, GENL_doit(drbd_adm_down),
+ GENL_tla_expected(DRBD_NLA_CFG_CONTEXT, GENLA_F_REQUIRED))
--
1.7.4.1
prev parent reply other threads:[~2011-09-01 12:49 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-09-01 12:48 [RFC 00/18] drbd: part 4 of adding multiple volume support to drbd Philipp Reisner
2011-09-01 12:48 ` [PATCH 01/18] drbd: default to detach on-io-error Philipp Reisner
2011-09-01 12:48 ` [PATCH 02/18] drbd: only wakeup if something changed in update_peer_seq Philipp Reisner
2011-09-01 12:48 ` [PATCH 03/18] drbd: add page pool to be used for meta data IO Philipp Reisner
2011-09-01 12:48 ` [PATCH 04/18] drbd: use the newly introduced page pool for bitmap IO Philipp Reisner
2011-09-01 12:48 ` [PATCH 05/18] drbd: introduce a bio_set to allocate housekeeping bios from Philipp Reisner
2011-09-01 12:48 ` [PATCH 06/18] drbd: fix drbd_delete_device: remove vnr from volumes; idr_remove(); synchronize_rcu(); before cleanup Philipp Reisner
2011-09-01 12:48 ` [PATCH 07/18] drbd: get rid of drbd_bcast_ee, it is of no use anymore Philipp Reisner
2011-09-01 12:48 ` [PATCH 08/18] drbd: prepare the transition from connector to genetlink Philipp Reisner
2011-09-01 12:48 ` [PATCH 09/18] drbd: switch configuration interface " Philipp Reisner
2011-09-01 12:48 ` [PATCH 10/18] drbd: allow holes in minor and volume id allocation Philipp Reisner
2011-09-01 12:48 ` [PATCH 11/18] drbd: remove now unused connector related files Philipp Reisner
2011-09-01 12:48 ` [PATCH 12/18] drbd: drbd_adm_get_status needs to show some more detail Philipp Reisner
2011-09-01 12:49 ` [PATCH 13/18] drbd: simplify conn_all_vols_unconf, make it bool Philipp Reisner
2011-09-01 12:49 ` [PATCH 14/18] drbd: Allow a Diskless Secondary volume to be removed Philipp Reisner
2011-09-01 12:49 ` [PATCH 15/18] drbd: new-connection and new-minor succeed, if the object already exists Philipp Reisner
2011-09-01 12:49 ` [PATCH 16/18] drbd: bail out if a config requrest is over-determined, and not matching Philipp Reisner
2011-09-01 12:49 ` [PATCH 17/18] drbd: add forgotten spin_unlock Philipp Reisner
2011-09-01 12:49 ` Philipp Reisner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1314881345-6420-19-git-send-email-philipp.reisner@linbit.com \
--to=philipp.reisner@linbit.com \
--cc=axboe@kernel.dk \
--cc=drbd-dev@lists.linbit.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®