diff options
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 97 |
1 files changed, 72 insertions, 25 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index daf388f4bd17..ac0a175e778c 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -252,43 +252,47 @@ static int drbd_adm_finish(struct genl_info *info, int retcode) return 0; } -int drbd_khelper(struct drbd_conf *mdev, char *cmd) +static void setup_khelper_env(struct drbd_tconn *tconn, char **envp) { - char *envp[] = { "HOME=/", - "TERM=linux", - "PATH=/sbin:/usr/sbin:/bin:/usr/bin", - NULL, /* Will be set to address family */ - NULL, /* Will be set to address */ - NULL }; - char mb[12], af[20], ad[60], *afs; - char *argv[] = {usermode_helper, cmd, mb, NULL }; - struct sib_info sib; - int ret; - - snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); + char *afs; - if (get_net_conf(mdev->tconn)) { - switch (((struct sockaddr *)mdev->tconn->net_conf->peer_addr)->sa_family) { + if (get_net_conf(tconn)) { + switch (((struct sockaddr *)tconn->net_conf->peer_addr)->sa_family) { case AF_INET6: afs = "ipv6"; - snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI6", - &((struct sockaddr_in6 *)mdev->tconn->net_conf->peer_addr)->sin6_addr); + snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI6", + &((struct sockaddr_in6 *)tconn->net_conf->peer_addr)->sin6_addr); break; case AF_INET: afs = "ipv4"; - snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4", - &((struct sockaddr_in *)mdev->tconn->net_conf->peer_addr)->sin_addr); + snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", + &((struct sockaddr_in *)tconn->net_conf->peer_addr)->sin_addr); break; default: afs = "ssocks"; - snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4", - &((struct sockaddr_in *)mdev->tconn->net_conf->peer_addr)->sin_addr); + snprintf(envp[4], 60, "DRBD_PEER_ADDRESS=%pI4", + &((struct sockaddr_in *)tconn->net_conf->peer_addr)->sin_addr); } - snprintf(af, 20, "DRBD_PEER_AF=%s", afs); - envp[3]=af; - envp[4]=ad; - put_net_conf(mdev->tconn); + snprintf(envp[3], 20, "DRBD_PEER_AF=%s", afs); + put_net_conf(tconn); } +} + +int drbd_khelper(struct drbd_conf *mdev, char *cmd) +{ + char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + (char[20]) { }, /* address family */ + (char[60]) { }, /* address */ + NULL }; + char mb[12]; + char *argv[] = {usermode_helper, cmd, mb, NULL }; + struct sib_info sib; + int ret; + + snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); + setup_khelper_env(mdev->tconn, envp); /* The helper may take some time. * write out any unsynced meta data changes now */ @@ -317,6 +321,49 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd) return ret; } +static void conn_md_sync(struct drbd_tconn *tconn) +{ + struct drbd_conf *mdev; + int minor; + + idr_for_each_entry(&tconn->volumes, mdev, minor) + drbd_md_sync(mdev); +} + +int conn_khelper(struct drbd_tconn *tconn, char *cmd) +{ + char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + (char[20]) { }, /* address family */ + (char[60]) { }, /* address */ + NULL }; + char *argv[] = {usermode_helper, cmd, tconn->name, NULL }; + int ret; + + setup_khelper_env(tconn, envp); + conn_md_sync(tconn); + + conn_info(tconn, "helper command: %s %s %s\n", usermode_helper, cmd, tconn->name); + /* TODO: conn_bcast_event() ?? */ + + ret = call_usermodehelper(usermode_helper, argv, envp, 1); + if (ret) + conn_warn(tconn, "helper command: %s %s %s exit code %u (0x%x)\n", + usermode_helper, cmd, tconn->name, + (ret >> 8) & 0xff, ret); + else + conn_info(tconn, "helper command: %s %s %s exit code %u (0x%x)\n", + usermode_helper, cmd, tconn->name, + (ret >> 8) & 0xff, ret); + /* TODO: conn_bcast_event() ?? */ + + if (ret < 0) /* Ignore any ERRNOs we got. */ + ret = 0; + + return ret; +} + enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev) { char *ex_to_string; |