*/
struct idr minors;
struct list_head drbd_tconns; /* list of struct drbd_tconn */
-DEFINE_MUTEX(drbd_cfg_mutex);
+DECLARE_RWSEM(drbd_cfg_rwsem);
struct kmem_cache *drbd_request_cache;
struct kmem_cache *drbd_ee_cache; /* peer requests */
if (!name || !name[0])
return NULL;
- mutex_lock(&drbd_cfg_mutex);
+ down_read(&drbd_cfg_rwsem);
list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
if (!strcmp(tconn->name, name))
goto found;
}
tconn = NULL;
found:
- mutex_unlock(&drbd_cfg_mutex);
+ up_read(&drbd_cfg_rwsem);
return tconn;
}
DRBD_ON_NO_DATA_DEF, /* on_no_data */
};
- mutex_lock(&drbd_cfg_mutex);
+ down_write(&drbd_cfg_rwsem);
list_add_tail(&tconn->all_tconn, &drbd_tconns);
- mutex_unlock(&drbd_cfg_mutex);
+ up_write(&drbd_cfg_rwsem);
return tconn;
new_my_addr = (struct sockaddr *)&new_conf->my_addr;
new_peer_addr = (struct sockaddr *)&new_conf->peer_addr;
- /* No need to take drbd_cfg_mutex here. All reconfiguration is
+ /* No need to take drbd_cfg_rwsem here. All reconfiguration is
* strictly serialized on genl_lock(). We are protected against
* concurrent reconfiguration/addition/deletion */
list_for_each_entry(oconn, &drbd_tconns, all_tconn) {
*/
/* synchronize with drbd_new_tconn/drbd_free_tconn */
- mutex_lock(&drbd_cfg_mutex);
+ down_read(&drbd_cfg_rwsem);
next_tconn:
/* revalidate iterator position */
list_for_each_entry(tmp, &drbd_tconns, all_tconn) {
}
out:
- mutex_unlock(&drbd_cfg_mutex);
+ up_read(&drbd_cfg_rwsem);
/* where to start the next iteration */
cb->args[0] = (long)pos;
cb->args[1] = (pos == tconn) ? volume + 1 : 0;
if (retcode != NO_ERROR)
goto out;
- mutex_lock(&drbd_cfg_mutex);
+ down_write(&drbd_cfg_rwsem);
retcode = adm_delete_minor(adm_ctx.mdev);
- mutex_unlock(&drbd_cfg_mutex);
+ up_write(&drbd_cfg_rwsem);
/* if this was the last volume of this connection,
* this will terminate all threads */
if (retcode == NO_ERROR)
goto out;
}
- mutex_lock(&drbd_cfg_mutex);
+ down_read(&drbd_cfg_rwsem);
/* demote */
idr_for_each_entry(&adm_ctx.tconn->volumes, mdev, i) {
retcode = drbd_set_role(mdev, R_SECONDARY, 0);
goto out_unlock;
}
}
+ up_read(&drbd_cfg_rwsem);
/* delete volumes */
+ down_write(&drbd_cfg_rwsem);
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;
+ up_write(&drbd_cfg_rwsem);
+ goto out;
}
}
/* "can not happen" */
retcode = ERR_CONN_IN_USE;
drbd_msg_put_info("failed to delete connection");
- goto out_unlock;
}
+
+ up_write(&drbd_cfg_rwsem);
+ goto out;
out_unlock:
- mutex_unlock(&drbd_cfg_mutex);
+ up_read(&drbd_cfg_rwsem);
out:
drbd_adm_finish(info, retcode);
return 0;
if (retcode != NO_ERROR)
goto out;
- mutex_lock(&drbd_cfg_mutex);
+ down_write(&drbd_cfg_rwsem);
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);
+ up_write(&drbd_cfg_rwsem);
out:
drbd_adm_finish(info, retcode);