ping_manager() to prevent 'add' before 'remove' completes
It is currently possible to remove a device and re-add it without the manager noticing, i.e. without detecting a mdstat->devcnt container->devcnt mismatch. Introduce ping_manager() to arrange for mdmon to run manage_container() prior to mdadm dropping the exclusive open() on the container. Despite these precautions sysfs_read() may still fail. If this happens invalidate container->devcnt to ensure manage_container() runs at the next event. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
4795982e68
commit
313a4a82f1
17
Manage.c
17
Manage.c
|
@ -712,6 +712,23 @@ int Manage_subdevs(char *devname, int fd,
|
||||||
close(lfd);
|
close(lfd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (tst->ss->external) {
|
||||||
|
/*
|
||||||
|
* Before dropping our exclusive open we make an
|
||||||
|
* attempt at preventing mdmon from seeing an
|
||||||
|
* 'add' event before reconciling this 'remove'
|
||||||
|
* event.
|
||||||
|
*/
|
||||||
|
char *name = devnum2devname(fd2devnum(fd));
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
fprintf(stderr, Name ": unable to get container name\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ping_manager(name);
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
close(lfd);
|
close(lfd);
|
||||||
if (verbose >= 0)
|
if (verbose >= 0)
|
||||||
fprintf(stderr, Name ": hot removed %s\n",
|
fprintf(stderr, Name ": hot removed %s\n",
|
||||||
|
|
17
managemon.c
17
managemon.c
|
@ -265,8 +265,11 @@ static void manage_container(struct mdstat_ent *mdstat,
|
||||||
* These need to be remove from, or added to, the array
|
* These need to be remove from, or added to, the array
|
||||||
*/
|
*/
|
||||||
mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS);
|
mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS);
|
||||||
if (!mdi)
|
if (!mdi) {
|
||||||
|
/* invalidate the current count so we can try again */
|
||||||
|
container->devcnt = -1;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* check for removals */
|
/* check for removals */
|
||||||
for (cdp = &container->devs; *cdp; ) {
|
for (cdp = &container->devs; *cdp; ) {
|
||||||
|
@ -525,14 +528,15 @@ static void handle_message(struct supertype *container, struct metadata_update *
|
||||||
|
|
||||||
struct metadata_update *mu;
|
struct metadata_update *mu;
|
||||||
|
|
||||||
if (msg->len == 0) {
|
if (msg->len <= 0)
|
||||||
int cnt;
|
|
||||||
|
|
||||||
while (update_queue_pending || update_queue) {
|
while (update_queue_pending || update_queue) {
|
||||||
check_update_queue(container);
|
check_update_queue(container);
|
||||||
usleep(15*1000);
|
usleep(15*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg->len == 0) { /* ping_monitor */
|
||||||
|
int cnt;
|
||||||
|
|
||||||
cnt = monitor_loop_cnt;
|
cnt = monitor_loop_cnt;
|
||||||
if (cnt & 1)
|
if (cnt & 1)
|
||||||
cnt += 2; /* wait until next pselect */
|
cnt += 2; /* wait until next pselect */
|
||||||
|
@ -542,6 +546,11 @@ static void handle_message(struct supertype *container, struct metadata_update *
|
||||||
|
|
||||||
while (monitor_loop_cnt - cnt < 0)
|
while (monitor_loop_cnt - cnt < 0)
|
||||||
usleep(10 * 1000);
|
usleep(10 * 1000);
|
||||||
|
} else if (msg->len == -1) { /* ping_manager */
|
||||||
|
struct mdstat_ent *mdstat = mdstat_read(1, 0);
|
||||||
|
|
||||||
|
manage(mdstat, container);
|
||||||
|
free_mdstat(mdstat);
|
||||||
} else {
|
} else {
|
||||||
mu = malloc(sizeof(*mu));
|
mu = malloc(sizeof(*mu));
|
||||||
mu->len = msg->len;
|
mu->len = msg->len;
|
||||||
|
|
33
msg.c
33
msg.c
|
@ -81,12 +81,12 @@ static int recv_buf(int fd, void* buf, int len, int tmo)
|
||||||
|
|
||||||
int send_message(int fd, struct metadata_update *msg, int tmo)
|
int send_message(int fd, struct metadata_update *msg, int tmo)
|
||||||
{
|
{
|
||||||
__u32 len = msg->len;
|
__s32 len = msg->len;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
rv = send_buf(fd, &start_magic, 4, tmo);
|
rv = send_buf(fd, &start_magic, 4, tmo);
|
||||||
rv = rv ?: send_buf(fd, &len, 4, tmo);
|
rv = rv ?: send_buf(fd, &len, 4, tmo);
|
||||||
if (len)
|
if (len > 0)
|
||||||
rv = rv ?: send_buf(fd, msg->buf, msg->len, tmo);
|
rv = rv ?: send_buf(fd, msg->buf, msg->len, tmo);
|
||||||
rv = send_buf(fd, &end_magic, 4, tmo);
|
rv = send_buf(fd, &end_magic, 4, tmo);
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ int send_message(int fd, struct metadata_update *msg, int tmo)
|
||||||
int receive_message(int fd, struct metadata_update *msg, int tmo)
|
int receive_message(int fd, struct metadata_update *msg, int tmo)
|
||||||
{
|
{
|
||||||
__u32 magic;
|
__u32 magic;
|
||||||
__u32 len;
|
__s32 len;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
rv = recv_buf(fd, &magic, 4, tmo);
|
rv = recv_buf(fd, &magic, 4, tmo);
|
||||||
|
@ -105,7 +105,7 @@ int receive_message(int fd, struct metadata_update *msg, int tmo)
|
||||||
rv = recv_buf(fd, &len, 4, tmo);
|
rv = recv_buf(fd, &len, 4, tmo);
|
||||||
if (rv < 0 || len > MSG_MAX_LEN)
|
if (rv < 0 || len > MSG_MAX_LEN)
|
||||||
return -1;
|
return -1;
|
||||||
if (len) {
|
if (len > 0) {
|
||||||
msg->buf = malloc(len);
|
msg->buf = malloc(len);
|
||||||
if (msg->buf == NULL)
|
if (msg->buf == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -177,6 +177,7 @@ int connect_monitor(char *devname)
|
||||||
return sfd;
|
return sfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* give the monitor a chance to update the metadata */
|
||||||
int ping_monitor(char *devname)
|
int ping_monitor(char *devname)
|
||||||
{
|
{
|
||||||
int sfd = connect_monitor(devname);
|
int sfd = connect_monitor(devname);
|
||||||
|
@ -196,3 +197,27 @@ int ping_monitor(char *devname)
|
||||||
close(sfd);
|
close(sfd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* give the manager a chance to view the updated container state. This
|
||||||
|
* would naturally happen due to the manager noticing a change in
|
||||||
|
* /proc/mdstat; however, pinging encourages this detection to happen
|
||||||
|
* while an exclusive open() on the container is active
|
||||||
|
*/
|
||||||
|
int ping_manager(char *devname)
|
||||||
|
{
|
||||||
|
int sfd = connect_monitor(devname);
|
||||||
|
struct metadata_update msg = { .len = -1 };
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (sfd < 0)
|
||||||
|
return sfd;
|
||||||
|
|
||||||
|
err = send_message(sfd, &msg, 20);
|
||||||
|
|
||||||
|
/* check the reply */
|
||||||
|
if (!err && wait_reply(sfd, 20) != 0)
|
||||||
|
err = -1;
|
||||||
|
|
||||||
|
close(sfd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
1
msg.h
1
msg.h
|
@ -27,5 +27,6 @@ extern int ack(int fd, int tmo);
|
||||||
extern int wait_reply(int fd, int tmo);
|
extern int wait_reply(int fd, int tmo);
|
||||||
extern int connect_monitor(char *devname);
|
extern int connect_monitor(char *devname);
|
||||||
extern int ping_monitor(char *devname);
|
extern int ping_monitor(char *devname);
|
||||||
|
extern int ping_manager(char *devname);
|
||||||
|
|
||||||
#define MSG_MAX_LEN (4*1024*1024)
|
#define MSG_MAX_LEN (4*1024*1024)
|
||||||
|
|
Loading…
Reference in New Issue