Loading drivers/block/drbd/drbd_int.h +7 −0 Original line number Diff line number Diff line Loading @@ -836,6 +836,11 @@ struct drbd_tconn { /* is a resource from the config file */ wait_queue_head_t ping_wait; /* Woken upon reception of a ping, and a state change */ struct res_opts res_opts; struct sockaddr_storage my_addr; int my_addr_len; struct sockaddr_storage peer_addr; int peer_addr_len; struct drbd_socket data; /* data/barrier/cstate/parameter packets */ struct drbd_socket meta; /* ping/ack (metadata) packets */ int agreed_pro_version; /* actually used protocol version */ Loading Loading @@ -1377,6 +1382,8 @@ extern void drbd_minor_destroy(struct kref *kref); struct drbd_tconn *conn_create(const char *name); extern void conn_destroy(struct kref *kref); struct drbd_tconn *conn_get_by_name(const char *name); extern struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len, void *peer_addr, int peer_addr_len); extern void conn_free_crypto(struct drbd_tconn *tconn); extern int proc_details; Loading drivers/block/drbd/drbd_main.c +21 −0 Original line number Diff line number Diff line Loading @@ -2420,6 +2420,27 @@ struct drbd_tconn *conn_get_by_name(const char *name) return tconn; } struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len, void *peer_addr, int peer_addr_len) { struct drbd_tconn *tconn; rcu_read_lock(); list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) { if (tconn->my_addr_len == my_addr_len && tconn->peer_addr_len == peer_addr_len && !memcmp(&tconn->my_addr, my_addr, my_addr_len) && !memcmp(&tconn->peer_addr, peer_addr, peer_addr_len)) { kref_get(&tconn->kref); goto found; } } tconn = NULL; found: rcu_read_unlock(); return tconn; } static int drbd_alloc_socket(struct drbd_socket *socket) { socket->rbuf = (void *) __get_free_page(GFP_KERNEL); Loading drivers/block/drbd/drbd_nl.c +94 −64 Original line number Diff line number Diff line Loading @@ -94,6 +94,8 @@ static struct drbd_config_context { /* pointer into the request skb, * limited lifetime! */ char *resource_name; struct nlattr *my_addr; struct nlattr *peer_addr; /* reply buffer */ struct sk_buff *reply_skb; Loading Loading @@ -142,6 +144,7 @@ int drbd_msg_put_info(const char *info) */ #define DRBD_ADM_NEED_MINOR 1 #define DRBD_ADM_NEED_RESOURCE 2 #define DRBD_ADM_NEED_CONNECTION 4 static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, unsigned flags) { Loading Loading @@ -174,6 +177,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, adm_ctx.reply_dh->minor = d_in->minor; adm_ctx.reply_dh->ret_code = NO_ERROR; adm_ctx.volume = VOLUME_UNSPECIFIED; if (info->attrs[DRBD_NLA_CFG_CONTEXT]) { struct nlattr *nla; /* parse and validate only */ Loading @@ -191,12 +195,21 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, /* and assign stuff to the global adm_ctx */ nla = nested_attr_tb[__nla_type(T_ctx_volume)]; adm_ctx.volume = nla ? nla_get_u32(nla) : VOLUME_UNSPECIFIED; if (nla) adm_ctx.volume = nla_get_u32(nla); nla = nested_attr_tb[__nla_type(T_ctx_resource_name)]; if (nla) adm_ctx.resource_name = nla_data(nla); } else adm_ctx.volume = VOLUME_UNSPECIFIED; adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)]; adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)]; if ((adm_ctx.my_addr && nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) || (adm_ctx.peer_addr && nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) { err = -EINVAL; goto fail; } } adm_ctx.minor = d_in->minor; adm_ctx.mdev = minor_to_mdev(d_in->minor); Loading @@ -211,6 +224,26 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, return ERR_INVALID_REQUEST; } if (flags & DRBD_ADM_NEED_CONNECTION) { if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) { drbd_msg_put_info("no resource name expected"); return ERR_INVALID_REQUEST; } if (adm_ctx.mdev) { drbd_msg_put_info("no minor number expected"); return ERR_INVALID_REQUEST; } if (adm_ctx.my_addr && adm_ctx.peer_addr) adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr), nla_len(adm_ctx.my_addr), nla_data(adm_ctx.peer_addr), nla_len(adm_ctx.peer_addr)); if (!adm_ctx.tconn) { drbd_msg_put_info("unknown connection"); return ERR_INVALID_REQUEST; } } /* some more paranoia, if the request was over-determined */ if (adm_ctx.mdev && adm_ctx.tconn && adm_ctx.mdev->tconn != adm_ctx.tconn) { Loading Loading @@ -268,31 +301,29 @@ static int drbd_adm_finish(struct genl_info *info, int retcode) static void setup_khelper_env(struct drbd_tconn *tconn, char **envp) { char *afs; struct net_conf *nc; rcu_read_lock(); nc = rcu_dereference(tconn->net_conf); if (nc) { switch (((struct sockaddr *)nc->peer_addr)->sa_family) { /* FIXME: A future version will not allow this case. */ if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0) return; switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) { case AF_INET6: afs = "ipv6"; snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6", &((struct sockaddr_in6 *)nc->peer_addr)->sin6_addr); &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr); break; case AF_INET: afs = "ipv4"; snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", &((struct sockaddr_in *)nc->peer_addr)->sin_addr); &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr); break; default: afs = "ssocks"; snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", &((struct sockaddr_in *)nc->peer_addr)->sin_addr); &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr); } snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs); } rcu_read_unlock(); } int drbd_khelper(struct drbd_conf *mdev, char *cmd) { Loading Loading @@ -1874,7 +1905,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) int rsr; /* re-sync running */ struct crypto crypto = { }; retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) Loading Loading @@ -1986,18 +2017,39 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) struct drbd_conf *mdev; struct net_conf *old_conf, *new_conf = NULL; struct crypto crypto = { }; struct drbd_tconn *oconn; struct drbd_tconn *tconn; struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr; enum drbd_ret_code retcode; int i; int err; retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) { drbd_msg_put_info("connection endpoint(s) missing"); retcode = ERR_INVALID_REQUEST; goto out; } /* No need for _rcu here. All reconfiguration is * strictly serialized on genl_lock(). We are protected against * concurrent reconfiguration/addition/deletion */ list_for_each_entry(tconn, &drbd_tconns, all_tconn) { if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len && !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->my_addr_len)) { retcode = ERR_LOCAL_ADDR; goto out; } if (nla_len(adm_ctx.peer_addr) == tconn->peer_addr_len && !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->peer_addr_len)) { retcode = ERR_PEER_ADDR; goto out; } } tconn = adm_ctx.tconn; conn_reconfig_start(tconn); Loading Loading @@ -2027,37 +2079,6 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) if (retcode != NO_ERROR) goto fail; retcode = NO_ERROR; new_my_addr = (struct sockaddr *)&new_conf->my_addr; new_peer_addr = (struct sockaddr *)&new_conf->peer_addr; /* No need for _rcu 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) { struct net_conf *nc; if (oconn == tconn) continue; rcu_read_lock(); nc = rcu_dereference(oconn->net_conf); if (nc) { taken_addr = (struct sockaddr *)&nc->my_addr; if (new_conf->my_addr_len == nc->my_addr_len && !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len)) retcode = ERR_LOCAL_ADDR; taken_addr = (struct sockaddr *)&nc->peer_addr; if (new_conf->peer_addr_len == nc->peer_addr_len && !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len)) retcode = ERR_PEER_ADDR; } rcu_read_unlock(); if (retcode != NO_ERROR) goto fail; } retcode = alloc_crypto(&crypto, new_conf); if (retcode != NO_ERROR) goto fail; Loading @@ -2083,6 +2104,11 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) tconn->csums_tfm = crypto.csums_tfm; tconn->verify_tfm = crypto.verify_tfm; tconn->my_addr_len = nla_len(adm_ctx.my_addr); memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len); tconn->peer_addr_len = nla_len(adm_ctx.peer_addr); memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len); mutex_unlock(&tconn->conf_update); rcu_read_lock(); Loading Loading @@ -2170,7 +2196,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) enum drbd_ret_code retcode; int err; retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) Loading Loading @@ -2529,7 +2555,7 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info) return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED)); } int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, unsigned vnr) int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_tconn *tconn, unsigned vnr) { struct nlattr *nla; nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT); Loading @@ -2537,7 +2563,11 @@ int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, uns goto nla_put_failure; if (vnr != VOLUME_UNSPECIFIED) NLA_PUT_U32(skb, T_ctx_volume, vnr); NLA_PUT_STRING(skb, T_ctx_resource_name, resource_name); NLA_PUT_STRING(skb, T_ctx_resource_name, tconn->name); if (tconn->my_addr_len) NLA_PUT(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr); if (tconn->peer_addr_len) NLA_PUT(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr); nla_nest_end(skb, nla); return 0; Loading Loading @@ -2574,7 +2604,7 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev, /* We need to add connection name and volume number information still. * Minor number is in drbd_genlmsghdr. */ if (nla_put_drbd_cfg_context(skb, mdev->tconn->name, mdev->vnr)) if (nla_put_drbd_cfg_context(skb, mdev->tconn, mdev->vnr)) goto nla_put_failure; if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive)) Loading Loading @@ -2736,7 +2766,7 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb) /* this is a tconn without a single volume */ dh->minor = -1U; dh->ret_code = NO_ERROR; if (nla_put_drbd_cfg_context(skb, tconn->name, VOLUME_UNSPECIFIED)) if (nla_put_drbd_cfg_context(skb, tconn, VOLUME_UNSPECIFIED)) genlmsg_cancel(skb, dh); else genlmsg_end(skb, dh); Loading drivers/block/drbd/drbd_receiver.c +9 −12 Original line number Diff line number Diff line Loading @@ -626,23 +626,21 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn) rcu_read_unlock(); return NULL; } sndbuf_size = nc->sndbuf_size; rcvbuf_size = nc->rcvbuf_size; connect_int = nc->connect_int; rcu_read_unlock(); my_addr_len = min_t(int, nc->my_addr_len, sizeof(src_in6)); memcpy(&src_in6, nc->my_addr, my_addr_len); my_addr_len = min_t(int, tconn->my_addr_len, sizeof(src_in6)); memcpy(&src_in6, &tconn->my_addr, my_addr_len); if (((struct sockaddr *)nc->my_addr)->sa_family == AF_INET6) if (((struct sockaddr *)&tconn->my_addr)->sa_family == AF_INET6) src_in6.sin6_port = 0; else ((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */ peer_addr_len = min_t(int, nc->peer_addr_len, sizeof(src_in6)); memcpy(&peer_in6, nc->peer_addr, peer_addr_len); rcu_read_unlock(); peer_addr_len = min_t(int, tconn->peer_addr_len, sizeof(src_in6)); memcpy(&peer_in6, &tconn->peer_addr, peer_addr_len); what = "sock_create_kern"; err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family, Loading Loading @@ -714,15 +712,14 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) rcu_read_unlock(); return NULL; } sndbuf_size = nc->sndbuf_size; rcvbuf_size = nc->rcvbuf_size; connect_int = nc->connect_int; my_addr_len = min_t(int, nc->my_addr_len, sizeof(struct sockaddr_in6)); memcpy(&my_addr, nc->my_addr, my_addr_len); rcu_read_unlock(); my_addr_len = min_t(int, tconn->my_addr_len, sizeof(struct sockaddr_in6)); memcpy(&my_addr, &tconn->my_addr, my_addr_len); what = "sock_create_kern"; err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &s_listen); Loading drivers/block/drbd/drbd_state.c +2 −0 Original line number Diff line number Diff line Loading @@ -1418,6 +1418,8 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused) mutex_lock(&tconn->conf_update); old_conf = tconn->net_conf; tconn->my_addr_len = 0; tconn->peer_addr_len = 0; rcu_assign_pointer(tconn->net_conf, NULL); conn_free_crypto(tconn); mutex_unlock(&tconn->conf_update); Loading Loading
drivers/block/drbd/drbd_int.h +7 −0 Original line number Diff line number Diff line Loading @@ -836,6 +836,11 @@ struct drbd_tconn { /* is a resource from the config file */ wait_queue_head_t ping_wait; /* Woken upon reception of a ping, and a state change */ struct res_opts res_opts; struct sockaddr_storage my_addr; int my_addr_len; struct sockaddr_storage peer_addr; int peer_addr_len; struct drbd_socket data; /* data/barrier/cstate/parameter packets */ struct drbd_socket meta; /* ping/ack (metadata) packets */ int agreed_pro_version; /* actually used protocol version */ Loading Loading @@ -1377,6 +1382,8 @@ extern void drbd_minor_destroy(struct kref *kref); struct drbd_tconn *conn_create(const char *name); extern void conn_destroy(struct kref *kref); struct drbd_tconn *conn_get_by_name(const char *name); extern struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len, void *peer_addr, int peer_addr_len); extern void conn_free_crypto(struct drbd_tconn *tconn); extern int proc_details; Loading
drivers/block/drbd/drbd_main.c +21 −0 Original line number Diff line number Diff line Loading @@ -2420,6 +2420,27 @@ struct drbd_tconn *conn_get_by_name(const char *name) return tconn; } struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len, void *peer_addr, int peer_addr_len) { struct drbd_tconn *tconn; rcu_read_lock(); list_for_each_entry_rcu(tconn, &drbd_tconns, all_tconn) { if (tconn->my_addr_len == my_addr_len && tconn->peer_addr_len == peer_addr_len && !memcmp(&tconn->my_addr, my_addr, my_addr_len) && !memcmp(&tconn->peer_addr, peer_addr, peer_addr_len)) { kref_get(&tconn->kref); goto found; } } tconn = NULL; found: rcu_read_unlock(); return tconn; } static int drbd_alloc_socket(struct drbd_socket *socket) { socket->rbuf = (void *) __get_free_page(GFP_KERNEL); Loading
drivers/block/drbd/drbd_nl.c +94 −64 Original line number Diff line number Diff line Loading @@ -94,6 +94,8 @@ static struct drbd_config_context { /* pointer into the request skb, * limited lifetime! */ char *resource_name; struct nlattr *my_addr; struct nlattr *peer_addr; /* reply buffer */ struct sk_buff *reply_skb; Loading Loading @@ -142,6 +144,7 @@ int drbd_msg_put_info(const char *info) */ #define DRBD_ADM_NEED_MINOR 1 #define DRBD_ADM_NEED_RESOURCE 2 #define DRBD_ADM_NEED_CONNECTION 4 static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, unsigned flags) { Loading Loading @@ -174,6 +177,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, adm_ctx.reply_dh->minor = d_in->minor; adm_ctx.reply_dh->ret_code = NO_ERROR; adm_ctx.volume = VOLUME_UNSPECIFIED; if (info->attrs[DRBD_NLA_CFG_CONTEXT]) { struct nlattr *nla; /* parse and validate only */ Loading @@ -191,12 +195,21 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, /* and assign stuff to the global adm_ctx */ nla = nested_attr_tb[__nla_type(T_ctx_volume)]; adm_ctx.volume = nla ? nla_get_u32(nla) : VOLUME_UNSPECIFIED; if (nla) adm_ctx.volume = nla_get_u32(nla); nla = nested_attr_tb[__nla_type(T_ctx_resource_name)]; if (nla) adm_ctx.resource_name = nla_data(nla); } else adm_ctx.volume = VOLUME_UNSPECIFIED; adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)]; adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)]; if ((adm_ctx.my_addr && nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) || (adm_ctx.peer_addr && nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) { err = -EINVAL; goto fail; } } adm_ctx.minor = d_in->minor; adm_ctx.mdev = minor_to_mdev(d_in->minor); Loading @@ -211,6 +224,26 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, return ERR_INVALID_REQUEST; } if (flags & DRBD_ADM_NEED_CONNECTION) { if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) { drbd_msg_put_info("no resource name expected"); return ERR_INVALID_REQUEST; } if (adm_ctx.mdev) { drbd_msg_put_info("no minor number expected"); return ERR_INVALID_REQUEST; } if (adm_ctx.my_addr && adm_ctx.peer_addr) adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr), nla_len(adm_ctx.my_addr), nla_data(adm_ctx.peer_addr), nla_len(adm_ctx.peer_addr)); if (!adm_ctx.tconn) { drbd_msg_put_info("unknown connection"); return ERR_INVALID_REQUEST; } } /* some more paranoia, if the request was over-determined */ if (adm_ctx.mdev && adm_ctx.tconn && adm_ctx.mdev->tconn != adm_ctx.tconn) { Loading Loading @@ -268,31 +301,29 @@ static int drbd_adm_finish(struct genl_info *info, int retcode) static void setup_khelper_env(struct drbd_tconn *tconn, char **envp) { char *afs; struct net_conf *nc; rcu_read_lock(); nc = rcu_dereference(tconn->net_conf); if (nc) { switch (((struct sockaddr *)nc->peer_addr)->sa_family) { /* FIXME: A future version will not allow this case. */ if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0) return; switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) { case AF_INET6: afs = "ipv6"; snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6", &((struct sockaddr_in6 *)nc->peer_addr)->sin6_addr); &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr); break; case AF_INET: afs = "ipv4"; snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", &((struct sockaddr_in *)nc->peer_addr)->sin_addr); &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr); break; default: afs = "ssocks"; snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", &((struct sockaddr_in *)nc->peer_addr)->sin_addr); &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr); } snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs); } rcu_read_unlock(); } int drbd_khelper(struct drbd_conf *mdev, char *cmd) { Loading Loading @@ -1874,7 +1905,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) int rsr; /* re-sync running */ struct crypto crypto = { }; retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) Loading Loading @@ -1986,18 +2017,39 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) struct drbd_conf *mdev; struct net_conf *old_conf, *new_conf = NULL; struct crypto crypto = { }; struct drbd_tconn *oconn; struct drbd_tconn *tconn; struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr; enum drbd_ret_code retcode; int i; int err; retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) goto out; if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) { drbd_msg_put_info("connection endpoint(s) missing"); retcode = ERR_INVALID_REQUEST; goto out; } /* No need for _rcu here. All reconfiguration is * strictly serialized on genl_lock(). We are protected against * concurrent reconfiguration/addition/deletion */ list_for_each_entry(tconn, &drbd_tconns, all_tconn) { if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len && !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->my_addr_len)) { retcode = ERR_LOCAL_ADDR; goto out; } if (nla_len(adm_ctx.peer_addr) == tconn->peer_addr_len && !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->peer_addr_len)) { retcode = ERR_PEER_ADDR; goto out; } } tconn = adm_ctx.tconn; conn_reconfig_start(tconn); Loading Loading @@ -2027,37 +2079,6 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) if (retcode != NO_ERROR) goto fail; retcode = NO_ERROR; new_my_addr = (struct sockaddr *)&new_conf->my_addr; new_peer_addr = (struct sockaddr *)&new_conf->peer_addr; /* No need for _rcu 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) { struct net_conf *nc; if (oconn == tconn) continue; rcu_read_lock(); nc = rcu_dereference(oconn->net_conf); if (nc) { taken_addr = (struct sockaddr *)&nc->my_addr; if (new_conf->my_addr_len == nc->my_addr_len && !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len)) retcode = ERR_LOCAL_ADDR; taken_addr = (struct sockaddr *)&nc->peer_addr; if (new_conf->peer_addr_len == nc->peer_addr_len && !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len)) retcode = ERR_PEER_ADDR; } rcu_read_unlock(); if (retcode != NO_ERROR) goto fail; } retcode = alloc_crypto(&crypto, new_conf); if (retcode != NO_ERROR) goto fail; Loading @@ -2083,6 +2104,11 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) tconn->csums_tfm = crypto.csums_tfm; tconn->verify_tfm = crypto.verify_tfm; tconn->my_addr_len = nla_len(adm_ctx.my_addr); memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len); tconn->peer_addr_len = nla_len(adm_ctx.peer_addr); memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len); mutex_unlock(&tconn->conf_update); rcu_read_lock(); Loading Loading @@ -2170,7 +2196,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) enum drbd_ret_code retcode; int err; retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION); if (!adm_ctx.reply_skb) return retcode; if (retcode != NO_ERROR) Loading Loading @@ -2529,7 +2555,7 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info) return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED)); } int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, unsigned vnr) int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_tconn *tconn, unsigned vnr) { struct nlattr *nla; nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT); Loading @@ -2537,7 +2563,11 @@ int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, uns goto nla_put_failure; if (vnr != VOLUME_UNSPECIFIED) NLA_PUT_U32(skb, T_ctx_volume, vnr); NLA_PUT_STRING(skb, T_ctx_resource_name, resource_name); NLA_PUT_STRING(skb, T_ctx_resource_name, tconn->name); if (tconn->my_addr_len) NLA_PUT(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr); if (tconn->peer_addr_len) NLA_PUT(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr); nla_nest_end(skb, nla); return 0; Loading Loading @@ -2574,7 +2604,7 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev, /* We need to add connection name and volume number information still. * Minor number is in drbd_genlmsghdr. */ if (nla_put_drbd_cfg_context(skb, mdev->tconn->name, mdev->vnr)) if (nla_put_drbd_cfg_context(skb, mdev->tconn, mdev->vnr)) goto nla_put_failure; if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive)) Loading Loading @@ -2736,7 +2766,7 @@ int get_one_status(struct sk_buff *skb, struct netlink_callback *cb) /* this is a tconn without a single volume */ dh->minor = -1U; dh->ret_code = NO_ERROR; if (nla_put_drbd_cfg_context(skb, tconn->name, VOLUME_UNSPECIFIED)) if (nla_put_drbd_cfg_context(skb, tconn, VOLUME_UNSPECIFIED)) genlmsg_cancel(skb, dh); else genlmsg_end(skb, dh); Loading
drivers/block/drbd/drbd_receiver.c +9 −12 Original line number Diff line number Diff line Loading @@ -626,23 +626,21 @@ static struct socket *drbd_try_connect(struct drbd_tconn *tconn) rcu_read_unlock(); return NULL; } sndbuf_size = nc->sndbuf_size; rcvbuf_size = nc->rcvbuf_size; connect_int = nc->connect_int; rcu_read_unlock(); my_addr_len = min_t(int, nc->my_addr_len, sizeof(src_in6)); memcpy(&src_in6, nc->my_addr, my_addr_len); my_addr_len = min_t(int, tconn->my_addr_len, sizeof(src_in6)); memcpy(&src_in6, &tconn->my_addr, my_addr_len); if (((struct sockaddr *)nc->my_addr)->sa_family == AF_INET6) if (((struct sockaddr *)&tconn->my_addr)->sa_family == AF_INET6) src_in6.sin6_port = 0; else ((struct sockaddr_in *)&src_in6)->sin_port = 0; /* AF_INET & AF_SCI */ peer_addr_len = min_t(int, nc->peer_addr_len, sizeof(src_in6)); memcpy(&peer_in6, nc->peer_addr, peer_addr_len); rcu_read_unlock(); peer_addr_len = min_t(int, tconn->peer_addr_len, sizeof(src_in6)); memcpy(&peer_in6, &tconn->peer_addr, peer_addr_len); what = "sock_create_kern"; err = sock_create_kern(((struct sockaddr *)&src_in6)->sa_family, Loading Loading @@ -714,15 +712,14 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn) rcu_read_unlock(); return NULL; } sndbuf_size = nc->sndbuf_size; rcvbuf_size = nc->rcvbuf_size; connect_int = nc->connect_int; my_addr_len = min_t(int, nc->my_addr_len, sizeof(struct sockaddr_in6)); memcpy(&my_addr, nc->my_addr, my_addr_len); rcu_read_unlock(); my_addr_len = min_t(int, tconn->my_addr_len, sizeof(struct sockaddr_in6)); memcpy(&my_addr, &tconn->my_addr, my_addr_len); what = "sock_create_kern"; err = sock_create_kern(((struct sockaddr *)&my_addr)->sa_family, SOCK_STREAM, IPPROTO_TCP, &s_listen); Loading
drivers/block/drbd/drbd_state.c +2 −0 Original line number Diff line number Diff line Loading @@ -1418,6 +1418,8 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused) mutex_lock(&tconn->conf_update); old_conf = tconn->net_conf; tconn->my_addr_len = 0; tconn->peer_addr_len = 0; rcu_assign_pointer(tconn->net_conf, NULL); conn_free_crypto(tconn); mutex_unlock(&tconn->conf_update); Loading