aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-06-14 12:28:09 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:57:46 -0500
commit089c075d88ac9407b8d7c5c8fc4b21c0d940bd82 (patch)
treec68e1a24d7813abe883702255a37dc704f2ea8fd /drivers/block/drbd/drbd_nl.c
parent44e52cfaa22e44a0197b44cd72c3440bc2a6e1ed (diff)
drbd: Convert the generic netlink interface to accept connection endpoints
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r--drivers/block/drbd/drbd_nl.c158
1 files changed, 94 insertions, 64 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 352be132b4be..e7933e04e7b8 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -94,6 +94,8 @@ static struct drbd_config_context {
94 /* pointer into the request skb, 94 /* pointer into the request skb,
95 * limited lifetime! */ 95 * limited lifetime! */
96 char *resource_name; 96 char *resource_name;
97 struct nlattr *my_addr;
98 struct nlattr *peer_addr;
97 99
98 /* reply buffer */ 100 /* reply buffer */
99 struct sk_buff *reply_skb; 101 struct sk_buff *reply_skb;
@@ -142,6 +144,7 @@ int drbd_msg_put_info(const char *info)
142 */ 144 */
143#define DRBD_ADM_NEED_MINOR 1 145#define DRBD_ADM_NEED_MINOR 1
144#define DRBD_ADM_NEED_RESOURCE 2 146#define DRBD_ADM_NEED_RESOURCE 2
147#define DRBD_ADM_NEED_CONNECTION 4
145static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info, 148static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
146 unsigned flags) 149 unsigned flags)
147{ 150{
@@ -174,6 +177,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
174 adm_ctx.reply_dh->minor = d_in->minor; 177 adm_ctx.reply_dh->minor = d_in->minor;
175 adm_ctx.reply_dh->ret_code = NO_ERROR; 178 adm_ctx.reply_dh->ret_code = NO_ERROR;
176 179
180 adm_ctx.volume = VOLUME_UNSPECIFIED;
177 if (info->attrs[DRBD_NLA_CFG_CONTEXT]) { 181 if (info->attrs[DRBD_NLA_CFG_CONTEXT]) {
178 struct nlattr *nla; 182 struct nlattr *nla;
179 /* parse and validate only */ 183 /* parse and validate only */
@@ -191,12 +195,21 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
191 195
192 /* and assign stuff to the global adm_ctx */ 196 /* and assign stuff to the global adm_ctx */
193 nla = nested_attr_tb[__nla_type(T_ctx_volume)]; 197 nla = nested_attr_tb[__nla_type(T_ctx_volume)];
194 adm_ctx.volume = nla ? nla_get_u32(nla) : VOLUME_UNSPECIFIED; 198 if (nla)
199 adm_ctx.volume = nla_get_u32(nla);
195 nla = nested_attr_tb[__nla_type(T_ctx_resource_name)]; 200 nla = nested_attr_tb[__nla_type(T_ctx_resource_name)];
196 if (nla) 201 if (nla)
197 adm_ctx.resource_name = nla_data(nla); 202 adm_ctx.resource_name = nla_data(nla);
198 } else 203 adm_ctx.my_addr = nested_attr_tb[__nla_type(T_ctx_my_addr)];
199 adm_ctx.volume = VOLUME_UNSPECIFIED; 204 adm_ctx.peer_addr = nested_attr_tb[__nla_type(T_ctx_peer_addr)];
205 if ((adm_ctx.my_addr &&
206 nla_len(adm_ctx.my_addr) > sizeof(adm_ctx.tconn->my_addr)) ||
207 (adm_ctx.peer_addr &&
208 nla_len(adm_ctx.peer_addr) > sizeof(adm_ctx.tconn->peer_addr))) {
209 err = -EINVAL;
210 goto fail;
211 }
212 }
200 213
201 adm_ctx.minor = d_in->minor; 214 adm_ctx.minor = d_in->minor;
202 adm_ctx.mdev = minor_to_mdev(d_in->minor); 215 adm_ctx.mdev = minor_to_mdev(d_in->minor);
@@ -211,6 +224,26 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
211 return ERR_INVALID_REQUEST; 224 return ERR_INVALID_REQUEST;
212 } 225 }
213 226
227 if (flags & DRBD_ADM_NEED_CONNECTION) {
228 if (adm_ctx.tconn && !(flags & DRBD_ADM_NEED_RESOURCE)) {
229 drbd_msg_put_info("no resource name expected");
230 return ERR_INVALID_REQUEST;
231 }
232 if (adm_ctx.mdev) {
233 drbd_msg_put_info("no minor number expected");
234 return ERR_INVALID_REQUEST;
235 }
236 if (adm_ctx.my_addr && adm_ctx.peer_addr)
237 adm_ctx.tconn = conn_get_by_addrs(nla_data(adm_ctx.my_addr),
238 nla_len(adm_ctx.my_addr),
239 nla_data(adm_ctx.peer_addr),
240 nla_len(adm_ctx.peer_addr));
241 if (!adm_ctx.tconn) {
242 drbd_msg_put_info("unknown connection");
243 return ERR_INVALID_REQUEST;
244 }
245 }
246
214 /* some more paranoia, if the request was over-determined */ 247 /* some more paranoia, if the request was over-determined */
215 if (adm_ctx.mdev && adm_ctx.tconn && 248 if (adm_ctx.mdev && adm_ctx.tconn &&
216 adm_ctx.mdev->tconn != adm_ctx.tconn) { 249 adm_ctx.mdev->tconn != adm_ctx.tconn) {
@@ -268,30 +301,28 @@ static int drbd_adm_finish(struct genl_info *info, int retcode)
268static void setup_khelper_env(struct drbd_tconn *tconn, char **envp) 301static void setup_khelper_env(struct drbd_tconn *tconn, char **envp)
269{ 302{
270 char *afs; 303 char *afs;
271 struct net_conf *nc;
272 304
273 rcu_read_lock(); 305 /* FIXME: A future version will not allow this case. */
274 nc = rcu_dereference(tconn->net_conf); 306 if (tconn->my_addr_len == 0 || tconn->peer_addr_len == 0)
275 if (nc) { 307 return;
276 switch (((struct sockaddr *)nc->peer_addr)->sa_family) { 308
277 case AF_INET6: 309 switch (((struct sockaddr *)&tconn->peer_addr)->sa_family) {
278 afs = "ipv6"; 310 case AF_INET6:
279 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6", 311 afs = "ipv6";
280 &((struct sockaddr_in6 *)nc->peer_addr)->sin6_addr); 312 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6",
281 break; 313 &((struct sockaddr_in6 *)&tconn->peer_addr)->sin6_addr);
282 case AF_INET: 314 break;
283 afs = "ipv4"; 315 case AF_INET:
284 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", 316 afs = "ipv4";
285 &((struct sockaddr_in *)nc->peer_addr)->sin_addr); 317 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
286 break; 318 &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
287 default: 319 break;
288 afs = "ssocks"; 320 default:
289 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", 321 afs = "ssocks";
290 &((struct sockaddr_in *)nc->peer_addr)->sin_addr); 322 snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4",
291 } 323 &((struct sockaddr_in *)&tconn->peer_addr)->sin_addr);
292 snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs);
293 } 324 }
294 rcu_read_unlock(); 325 snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs);
295} 326}
296 327
297int drbd_khelper(struct drbd_conf *mdev, char *cmd) 328int drbd_khelper(struct drbd_conf *mdev, char *cmd)
@@ -1874,7 +1905,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info)
1874 int rsr; /* re-sync running */ 1905 int rsr; /* re-sync running */
1875 struct crypto crypto = { }; 1906 struct crypto crypto = { };
1876 1907
1877 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); 1908 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION);
1878 if (!adm_ctx.reply_skb) 1909 if (!adm_ctx.reply_skb)
1879 return retcode; 1910 return retcode;
1880 if (retcode != NO_ERROR) 1911 if (retcode != NO_ERROR)
@@ -1986,18 +2017,39 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
1986 struct drbd_conf *mdev; 2017 struct drbd_conf *mdev;
1987 struct net_conf *old_conf, *new_conf = NULL; 2018 struct net_conf *old_conf, *new_conf = NULL;
1988 struct crypto crypto = { }; 2019 struct crypto crypto = { };
1989 struct drbd_tconn *oconn;
1990 struct drbd_tconn *tconn; 2020 struct drbd_tconn *tconn;
1991 struct sockaddr *new_my_addr, *new_peer_addr, *taken_addr;
1992 enum drbd_ret_code retcode; 2021 enum drbd_ret_code retcode;
1993 int i; 2022 int i;
1994 int err; 2023 int err;
1995 2024
1996 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); 2025 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
2026
1997 if (!adm_ctx.reply_skb) 2027 if (!adm_ctx.reply_skb)
1998 return retcode; 2028 return retcode;
1999 if (retcode != NO_ERROR) 2029 if (retcode != NO_ERROR)
2000 goto out; 2030 goto out;
2031 if (!(adm_ctx.my_addr && adm_ctx.peer_addr)) {
2032 drbd_msg_put_info("connection endpoint(s) missing");
2033 retcode = ERR_INVALID_REQUEST;
2034 goto out;
2035 }
2036
2037 /* No need for _rcu here. All reconfiguration is
2038 * strictly serialized on genl_lock(). We are protected against
2039 * concurrent reconfiguration/addition/deletion */
2040 list_for_each_entry(tconn, &drbd_tconns, all_tconn) {
2041 if (nla_len(adm_ctx.my_addr) == tconn->my_addr_len &&
2042 !memcmp(nla_data(adm_ctx.my_addr), &tconn->my_addr, tconn->my_addr_len)) {
2043 retcode = ERR_LOCAL_ADDR;
2044 goto out;
2045 }
2046
2047 if (nla_len(adm_ctx.peer_addr) == tconn->peer_addr_len &&
2048 !memcmp(nla_data(adm_ctx.peer_addr), &tconn->peer_addr, tconn->peer_addr_len)) {
2049 retcode = ERR_PEER_ADDR;
2050 goto out;
2051 }
2052 }
2001 2053
2002 tconn = adm_ctx.tconn; 2054 tconn = adm_ctx.tconn;
2003 conn_reconfig_start(tconn); 2055 conn_reconfig_start(tconn);
@@ -2027,37 +2079,6 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
2027 if (retcode != NO_ERROR) 2079 if (retcode != NO_ERROR)
2028 goto fail; 2080 goto fail;
2029 2081
2030 retcode = NO_ERROR;
2031
2032 new_my_addr = (struct sockaddr *)&new_conf->my_addr;
2033 new_peer_addr = (struct sockaddr *)&new_conf->peer_addr;
2034
2035 /* No need for _rcu here. All reconfiguration is
2036 * strictly serialized on genl_lock(). We are protected against
2037 * concurrent reconfiguration/addition/deletion */
2038 list_for_each_entry(oconn, &drbd_tconns, all_tconn) {
2039 struct net_conf *nc;
2040 if (oconn == tconn)
2041 continue;
2042
2043 rcu_read_lock();
2044 nc = rcu_dereference(oconn->net_conf);
2045 if (nc) {
2046 taken_addr = (struct sockaddr *)&nc->my_addr;
2047 if (new_conf->my_addr_len == nc->my_addr_len &&
2048 !memcmp(new_my_addr, taken_addr, new_conf->my_addr_len))
2049 retcode = ERR_LOCAL_ADDR;
2050
2051 taken_addr = (struct sockaddr *)&nc->peer_addr;
2052 if (new_conf->peer_addr_len == nc->peer_addr_len &&
2053 !memcmp(new_peer_addr, taken_addr, new_conf->peer_addr_len))
2054 retcode = ERR_PEER_ADDR;
2055 }
2056 rcu_read_unlock();
2057 if (retcode != NO_ERROR)
2058 goto fail;
2059 }
2060
2061 retcode = alloc_crypto(&crypto, new_conf); 2082 retcode = alloc_crypto(&crypto, new_conf);
2062 if (retcode != NO_ERROR) 2083 if (retcode != NO_ERROR)
2063 goto fail; 2084 goto fail;
@@ -2083,6 +2104,11 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
2083 tconn->csums_tfm = crypto.csums_tfm; 2104 tconn->csums_tfm = crypto.csums_tfm;
2084 tconn->verify_tfm = crypto.verify_tfm; 2105 tconn->verify_tfm = crypto.verify_tfm;
2085 2106
2107 tconn->my_addr_len = nla_len(adm_ctx.my_addr);
2108 memcpy(&tconn->my_addr, nla_data(adm_ctx.my_addr), tconn->my_addr_len);
2109 tconn->peer_addr_len = nla_len(adm_ctx.peer_addr);
2110 memcpy(&tconn->peer_addr, nla_data(adm_ctx.peer_addr), tconn->peer_addr_len);
2111
2086 mutex_unlock(&tconn->conf_update); 2112 mutex_unlock(&tconn->conf_update);
2087 2113
2088 rcu_read_lock(); 2114 rcu_read_lock();
@@ -2170,7 +2196,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info)
2170 enum drbd_ret_code retcode; 2196 enum drbd_ret_code retcode;
2171 int err; 2197 int err;
2172 2198
2173 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); 2199 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_CONNECTION);
2174 if (!adm_ctx.reply_skb) 2200 if (!adm_ctx.reply_skb)
2175 return retcode; 2201 return retcode;
2176 if (retcode != NO_ERROR) 2202 if (retcode != NO_ERROR)
@@ -2529,7 +2555,7 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
2529 return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED)); 2555 return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED));
2530} 2556}
2531 2557
2532int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, unsigned vnr) 2558int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_tconn *tconn, unsigned vnr)
2533{ 2559{
2534 struct nlattr *nla; 2560 struct nlattr *nla;
2535 nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT); 2561 nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT);
@@ -2537,7 +2563,11 @@ int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, uns
2537 goto nla_put_failure; 2563 goto nla_put_failure;
2538 if (vnr != VOLUME_UNSPECIFIED) 2564 if (vnr != VOLUME_UNSPECIFIED)
2539 NLA_PUT_U32(skb, T_ctx_volume, vnr); 2565 NLA_PUT_U32(skb, T_ctx_volume, vnr);
2540 NLA_PUT_STRING(skb, T_ctx_resource_name, resource_name); 2566 NLA_PUT_STRING(skb, T_ctx_resource_name, tconn->name);
2567 if (tconn->my_addr_len)
2568 NLA_PUT(skb, T_ctx_my_addr, tconn->my_addr_len, &tconn->my_addr);
2569 if (tconn->peer_addr_len)
2570 NLA_PUT(skb, T_ctx_peer_addr, tconn->peer_addr_len, &tconn->peer_addr);
2541 nla_nest_end(skb, nla); 2571 nla_nest_end(skb, nla);
2542 return 0; 2572 return 0;
2543 2573
@@ -2574,7 +2604,7 @@ int nla_put_status_info(struct sk_buff *skb, struct drbd_conf *mdev,
2574 2604
2575 /* We need to add connection name and volume number information still. 2605 /* We need to add connection name and volume number information still.
2576 * Minor number is in drbd_genlmsghdr. */ 2606 * Minor number is in drbd_genlmsghdr. */
2577 if (nla_put_drbd_cfg_context(skb, mdev->tconn->name, mdev->vnr)) 2607 if (nla_put_drbd_cfg_context(skb, mdev->tconn, mdev->vnr))
2578 goto nla_put_failure; 2608 goto nla_put_failure;
2579 2609
2580 if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive)) 2610 if (res_opts_to_skb(skb, &mdev->tconn->res_opts, exclude_sensitive))
@@ -2736,7 +2766,7 @@ next_tconn:
2736 /* this is a tconn without a single volume */ 2766 /* this is a tconn without a single volume */
2737 dh->minor = -1U; 2767 dh->minor = -1U;
2738 dh->ret_code = NO_ERROR; 2768 dh->ret_code = NO_ERROR;
2739 if (nla_put_drbd_cfg_context(skb, tconn->name, VOLUME_UNSPECIFIED)) 2769 if (nla_put_drbd_cfg_context(skb, tconn, VOLUME_UNSPECIFIED))
2740 genlmsg_cancel(skb, dh); 2770 genlmsg_cancel(skb, dh);
2741 else 2771 else
2742 genlmsg_end(skb, dh); 2772 genlmsg_end(skb, dh);