diff options
Diffstat (limited to 'monitor.c')
-rw-r--r-- | monitor.c | 121 |
1 files changed, 60 insertions, 61 deletions
@@ -35,11 +35,6 @@ enum bb_action { COMPARE_BB, }; -static int write_attr(char *attr, int fd) -{ - return write(fd, attr, strlen(attr)); -} - static void add_fd(fd_set *fds, int *maxfd, int fd) { struct stat st; @@ -155,6 +150,8 @@ int read_dev_state(int fd) rv |= DS_SPARE; if (sysfs_attr_match(cp, "blocked")) rv |= DS_BLOCKED; + if (sysfs_attr_match(cp, "external_bbl")) + rv |= DS_EXTERNAL_BB; cp = strchr(cp, ','); if (cp) cp++; @@ -173,7 +170,7 @@ int process_ubb(struct active_array *a, struct mdinfo *mdi, const unsigned long * via sysfs file */ if ((ss->record_bad_block(a, mdi->disk.raid_disk, sector, length)) && - (write(mdi->bb_fd, buf, buf_len) == buf_len)) + (sysfs_write_descriptor(mdi->bb_fd, buf, buf_len, NULL) == MDADM_STATUS_SUCCESS)) return 1; /* @@ -311,9 +308,6 @@ static int check_for_cleared_bb(struct active_array *a, struct mdinfo *mdi) struct md_bb *bb; int i; - if (!ss->get_bad_blocks) - return -1; - /* * Get a list of bad blocks for an array, then read list of * acknowledged bad blocks from kernel and compare it against metadata @@ -402,11 +396,12 @@ static void signal_manager(void) #define ARRAY_DIRTY 1 #define ARRAY_BUSY 2 -static int read_and_act(struct active_array *a, fd_set *fds) +static int read_and_act(struct active_array *a) { unsigned long long sync_completed; - int check_degraded = 0; - int check_reshape = 0; + bool disks_to_remove = false; + bool check_degraded = false; + bool check_reshape = false; int deactivate = 0; struct mdinfo *mdi; int ret = 0; @@ -430,23 +425,32 @@ static int read_and_act(struct active_array *a, fd_set *fds) for (mdi = a->info.devs; mdi ; mdi = mdi->next) { mdi->next_state = 0; mdi->curr_state = 0; - if (mdi->state_fd >= 0) { - read_resync_start(mdi->recovery_fd, - &mdi->recovery_start); - mdi->curr_state = read_dev_state(mdi->state_fd); - } - /* - * If array is blocked and metadata handler is able to handle - * BB, check if you can acknowledge them to md driver. If - * successful, clear faulty state and unblock the array. - */ - if ((mdi->curr_state & DS_BLOCKED) && - a->container->ss->record_bad_block && - (process_dev_ubb(a, mdi) > 0)) { + + if (mdi->man_disk_to_remove) + /* We are removing this device, skip it then */ + continue; + + read_resync_start(mdi->recovery_fd, &mdi->recovery_start); + mdi->curr_state = read_dev_state(mdi->state_fd); + + if (!(mdi->curr_state & DS_EXTERNAL_BB)) + /* + * It assumes that superswitch badblock functions are set if disk + * has external badblocks support configured. + */ + continue; + + if ((mdi->curr_state & DS_BLOCKED) && process_dev_ubb(a, mdi) > 0) + /* + * Blocked has two meanings: we need to acknowledge failure or badblocks + * (if supported). Here, badblocks are handled. + * + * If successful, unblock the array. This is not perfect but + * process_dev_ubb() may disable badblock support in case of failure. + */ mdi->next_state |= DS_UNBLOCK; - } - if (FD_ISSET(mdi->bb_fd, fds)) - check_for_cleared_bb(a, mdi); + + check_for_cleared_bb(a, mdi); } gettimeofday(&tv, NULL); @@ -621,24 +625,12 @@ static int read_and_act(struct active_array *a, fd_set *fds) write_attr("-blocked", mdi->state_fd); } - if ((mdi->next_state & DS_REMOVE) && mdi->state_fd >= 0) { - int remove_result; - - /* The kernel may not be able to immediately remove the - * disk. In that case we wait a little while and - * try again. - */ - remove_result = write_attr("remove", mdi->state_fd); - if (remove_result > 0) { - dprintf_cont(" %d:removed", mdi->disk.raid_disk); - close(mdi->state_fd); - close(mdi->recovery_fd); - close(mdi->bb_fd); - close(mdi->ubb_fd); - mdi->state_fd = -1; - } else - ret |= ARRAY_BUSY; + if ((mdi->next_state & DS_REMOVE) && !mdi->man_disk_to_remove) { + dprintf_cont(" %d:disk_to_remove", mdi->disk.raid_disk); + mdi->man_disk_to_remove = true; + disks_to_remove = true; } + if (mdi->next_state & DS_INSYNC) { write_attr("+in_sync", mdi->state_fd); dprintf_cont(" %d:+in_sync", mdi->disk.raid_disk); @@ -651,17 +643,14 @@ static int read_and_act(struct active_array *a, fd_set *fds) a->prev_action = a->curr_action; - for (mdi = a->info.devs; mdi ; mdi = mdi->next) { + for (mdi = a->info.devs; mdi ; mdi = mdi->next) mdi->prev_state = mdi->curr_state; - mdi->next_state = 0; - } - if (check_degraded || check_reshape) { - /* manager will do the actual check */ - if (check_degraded) - a->check_degraded = 1; - if (check_reshape) - a->check_reshape = 1; + if (check_degraded || check_reshape || disks_to_remove) { + + a->check_member_remove |= disks_to_remove; + a->check_degraded |= check_degraded; + a->check_reshape |= check_reshape; signal_manager(); } @@ -734,13 +723,11 @@ int monitor_loop_cnt; static int wait_and_act(struct supertype *container, int nowait) { - fd_set rfds; - int maxfd = 0; - struct active_array **aap = &container->arrays; - struct active_array *a, **ap; - int rv; - struct mdinfo *mdi; + struct active_array *a, **ap, **aap = &container->arrays; static unsigned int dirty_arrays = ~0; /* start at some non-zero value */ + struct mdinfo *mdi; + int rv, maxfd = 0; + fd_set rfds; FD_ZERO(&rfds); @@ -764,7 +751,18 @@ static int wait_and_act(struct supertype *container, int nowait) add_fd(&rfds, &maxfd, a->info.state_fd); add_fd(&rfds, &maxfd, a->action_fd); add_fd(&rfds, &maxfd, a->sync_completed_fd); + for (mdi = a->info.devs ; mdi ; mdi = mdi->next) { + if (mdi->man_disk_to_remove) { + mdi->mon_descriptors_not_used = true; + + /* Managemon could be blocked on suspend in kernel. + * Monitor must respond if any badblock is recorded in this time. + */ + container->retry_soon = 1; + continue; + } + add_fd(&rfds, &maxfd, mdi->state_fd); add_fd(&rfds, &maxfd, mdi->bb_fd); add_fd(&rfds, &maxfd, mdi->ubb_fd); @@ -863,7 +861,8 @@ static int wait_and_act(struct supertype *container, int nowait) signal_manager(); } if (a->container && !a->to_remove) { - int ret = read_and_act(a, &rfds); + int ret = read_and_act(a); + rv |= 1; dirty_arrays += !!(ret & ARRAY_DIRTY); /* when terminating stop manipulating the array after it |