Loading drivers/block/drbd/drbd_main.c +0 −2 Original line number Diff line number Diff line Loading @@ -2303,9 +2303,7 @@ struct drbd_tconn *drbd_new_tconn(const char *name) 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); Loading drivers/block/drbd/drbd_nl.c +152 −51 Original line number Diff line number Diff line Loading @@ -49,6 +49,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); Loading Loading @@ -1416,6 +1417,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 Loading @@ -1423,7 +1436,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); Loading @@ -1432,13 +1444,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; Loading Loading @@ -1680,10 +1686,49 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) 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; Loading @@ -1704,35 +1749,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, Loading @@ -1743,7 +1761,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); Loading Loading @@ -2644,9 +2661,21 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info) 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); Loading @@ -2655,19 +2684,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; 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; Loading @@ -2683,12 +2782,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); Loading include/linux/drbd_genl.h +2 −0 Original line number Diff line number Diff line Loading @@ -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)) Loading
drivers/block/drbd/drbd_main.c +0 −2 Original line number Diff line number Diff line Loading @@ -2303,9 +2303,7 @@ struct drbd_tconn *drbd_new_tconn(const char *name) 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); Loading
drivers/block/drbd/drbd_nl.c +152 −51 Original line number Diff line number Diff line Loading @@ -49,6 +49,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); Loading Loading @@ -1416,6 +1417,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 Loading @@ -1423,7 +1436,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); Loading @@ -1432,13 +1444,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; Loading Loading @@ -1680,10 +1686,49 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) 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; Loading @@ -1704,35 +1749,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, Loading @@ -1743,7 +1761,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); Loading Loading @@ -2644,9 +2661,21 @@ int drbd_adm_add_minor(struct sk_buff *skb, struct genl_info *info) 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); Loading @@ -2655,19 +2684,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; 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; Loading @@ -2683,12 +2782,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); Loading
include/linux/drbd_genl.h +2 −0 Original line number Diff line number Diff line Loading @@ -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))