From patchwork Fri Aug 16 13:40:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guilherme Piccoli X-Patchwork-Id: 11097765 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A13BD13A0 for ; Fri, 16 Aug 2019 13:41:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8FEBC2022C for ; Fri, 16 Aug 2019 13:41:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 842712870B; Fri, 16 Aug 2019 13:41:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C911F28708 for ; Fri, 16 Aug 2019 13:41:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726032AbfHPNlM (ORCPT ); Fri, 16 Aug 2019 09:41:12 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:54791 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726742AbfHPNlL (ORCPT ); Fri, 16 Aug 2019 09:41:11 -0400 Received: from mail-qt1-f198.google.com ([209.85.160.198]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1hycTc-0001Kw-K3 for linux-block@vger.kernel.org; Fri, 16 Aug 2019 13:41:08 +0000 Received: by mail-qt1-f198.google.com with SMTP id h15so5887100qtq.18 for ; Fri, 16 Aug 2019 06:41:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=4N5xU9SyzOFldeE0V1HPJ7KCJ6tN+7YPLGNAaqnzYCw=; b=kOpl7eWO6FfDdIfcATYqsD3gxfeagYsEoc3v//VqePxhZ6N04HKHRoRqHGon+P+aKf i5lIlRWn5M8OvNLnsOz5LPv2C1aLVagjZhjYrf8Ql2v6IjqvZ4ia+ZqFqZIsT+L5EpgG vlNWEBfgMtdBH7zUtZdSVDz2lGUxfSHPDSmm8S0Mfs26U2vitP9GzI5Bl/KkepMHo30C Faa5UFUd3MsFM3R0Xnh8U3CUJbM55Xpo5xC58YJXz0/KWfS77ytiKh5SIPseqyUA4slp dbcEZTIEbaHxKWcC8NRQ68cesg2CtHTE2A9ucc4sWuyrGeqJCQgMSvefrBH5gpMoEKwJ SyCg== X-Gm-Message-State: APjAAAWZ47VYROmTgn4JmAEe0oKmYrRS+CiQUNSk/U6hbhd0Vg6kp79Z NEqbeQir9FQa0+yYRBVhuERo6+5FKfnDjFNfAZLi6BSbgmFXjAHXYEo5s4B3+33/57lslzt2ijG wmAXRBI36bPzKhAkCJc+dt5mSxnE454l85/XLtUD/ X-Received: by 2002:ae9:e91a:: with SMTP id x26mr8807455qkf.305.1565962866539; Fri, 16 Aug 2019 06:41:06 -0700 (PDT) X-Google-Smtp-Source: APXvYqwygp8F7l+JofXM1Fz9C0aXGXFyMZ2WmVpWE1a9KOfVKgvwBjgYBmjCKz5pS9XXRy+Bg7quRQ== X-Received: by 2002:ae9:e91a:: with SMTP id x26mr8807436qkf.305.1565962866250; Fri, 16 Aug 2019 06:41:06 -0700 (PDT) Received: from localhost ([191.13.19.2]) by smtp.gmail.com with ESMTPSA id u57sm3517952qtk.29.2019.08.16.06.41.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 16 Aug 2019 06:41:05 -0700 (PDT) From: "Guilherme G. Piccoli" To: linux-raid@vger.kernel.org Cc: linux-block@vger.kernel.org, dm-devel@redhat.com, gpiccoli@canonical.com, jay.vosburgh@canonical.com, NeilBrown , Song Liu Subject: [PATCH v2 1/2] md raid0/linear: Introduce new array state 'broken' Date: Fri, 16 Aug 2019 10:40:58 -0300 Message-Id: <20190816134059.29751-1-gpiccoli@canonical.com> X-Mailer: git-send-email 2.22.0 MIME-Version: 1.0 Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Currently if md raid0/linear array gets one or more members removed while being mounted, kernel keeps showing state 'clean' in the 'array_state' sysfs attribute. Despite udev signaling the member device is gone, 'mdadm' cannot issue the STOP_ARRAY ioctl successfully, given the array is mounted. Nothing else hints that something is wrong (except that the removed devices don't show properly in the output of 'mdadm detail' command). There is no other property to be checked, and if user is not performing reads/writes to the array, even kernel log is quiet and doesn't give a clue about the missing member. This patch changes this behavior; when 'array_state' is read we introduce a non-expensive check (only for raid0/md-linear) that relies in the comparison of the total number of disks when array was assembled with gendisk flags of those devices to validate if all members are available and functional. A new array state 'broken' was added: it mimics the state 'clean' in every aspect, being useful only to distinguish if such array has some member missing. Also, we show a rate-limited warning in kernel log in such case. This patch has no proper functional change other than adding the 'clean'-like state; it was tested with ext4 and xfs filesystems. It requires a 'mdadm' counterpart to handle the 'broken' state. Cc: NeilBrown Cc: Song Liu Signed-off-by: Guilherme G. Piccoli --- Cover-letter from v1: lore.kernel.org/linux-block/20190729203135.12934-1-gpiccoli@canonical.com v1 -> v2: * Added handling for md/linear 'broken' state; * Check for is_missing_dev() instead of personality (thanks Neil for the suggestion); * Changed is_missing_dev() handlers to static; * Print rate-limited warning in case of more members go away, not only the first. Song, after thinking and experimenting a bit more, I don't think it makes sense to allow setting the 'broken' state, unless we refactor and "re-purpose" this state. What 'broken' really means is a 'clean' state but with 1+ members missing - setting it is the same as set 'clean', so it'd be counter-intuitive to set 'broken' but having in fact set 'clean' merely with the name 'broken'. The purpose of 'broken' is really to only indicate a missing member, as noticed by kernel in array_state reads. If you really think we should use 'broken' for other purposes and hence users should be allowed to set it, let's discuss and rewrite it. Personally I think the less we change, the better. We just need some way to warn users about the missing members of their arrays. Thanks, Guilherme drivers/md/md-linear.c | 25 +++++++++++++++++++++++++ drivers/md/md.c | 22 ++++++++++++++++++---- drivers/md/md.h | 2 ++ drivers/md/raid0.c | 26 ++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c index ed2297541414..a404f700e3f8 100644 --- a/drivers/md/md-linear.c +++ b/drivers/md/md-linear.c @@ -237,6 +237,30 @@ static void linear_free(struct mddev *mddev, void *priv) kfree(conf); } +static bool linear_is_missing_dev(struct mddev *mddev) +{ + struct md_rdev *rdev; + static int already_missing; + int def_disks, work_disks = 0; + + def_disks = mddev->raid_disks; + rdev_for_each(rdev, mddev) + if (rdev->bdev->bd_disk->flags & GENHD_FL_UP) + work_disks++; + + if (unlikely(def_disks - work_disks)) { + if (already_missing < (def_disks - work_disks)) { + already_missing = def_disks - work_disks; + pr_warn("md: %s: linear array has %d missing/failed members\n", + mdname(mddev), already_missing); + } + return true; + } + + already_missing = 0; + return false; +} + static bool linear_make_request(struct mddev *mddev, struct bio *bio) { char b[BDEVNAME_SIZE]; @@ -325,6 +349,7 @@ static struct md_personality linear_personality = .size = linear_size, .quiesce = linear_quiesce, .congested = linear_congested, + .is_missing_dev = linear_is_missing_dev, }; static int __init linear_init (void) diff --git a/drivers/md/md.c b/drivers/md/md.c index ba4de55eea13..0ef93d21cab6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4160,12 +4160,17 @@ __ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR, * active-idle * like active, but no writes have been seen for a while (100msec). * + * broken + * RAID0/LINEAR-only: same as clean, but array is missing a member. + * It's useful because RAID0/LINEAR mounted-arrays aren't stopped + * when a member is gone, so this state will at least alert the + * user that something is wrong. */ enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active, - write_pending, active_idle, bad_word}; + write_pending, active_idle, broken, bad_word}; static char *array_states[] = { "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active", - "write-pending", "active-idle", NULL }; + "write-pending", "active-idle", "broken", NULL }; static int match_word(const char *word, char **list) { @@ -4181,7 +4186,7 @@ array_state_show(struct mddev *mddev, char *page) { enum array_state st = inactive; - if (mddev->pers) + if (mddev->pers) { switch(mddev->ro) { case 1: st = readonly; @@ -4201,7 +4206,15 @@ array_state_show(struct mddev *mddev, char *page) st = active; spin_unlock(&mddev->lock); } - else { + + if ((mddev->pers->is_missing_dev) && + ((st == clean) || (st == broken))) { + if (mddev->pers->is_missing_dev(mddev)) + st = broken; + else + st = clean; + } + } else { if (list_empty(&mddev->disks) && mddev->raid_disks == 0 && mddev->dev_sectors == 0) @@ -4315,6 +4328,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) break; case write_pending: case active_idle: + case broken: /* these cannot be set */ break; } diff --git a/drivers/md/md.h b/drivers/md/md.h index 5d7c1cad4946..2b40990c7642 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -590,6 +590,8 @@ struct md_personality int (*congested)(struct mddev *mddev, int bits); /* Changes the consistency policy of an active array. */ int (*change_consistency_policy)(struct mddev *mddev, const char *buf); + /* Check if there are any missing/failed members - RAID0/LINEAR only. */ + bool (*is_missing_dev)(struct mddev *mddev); }; struct md_sysfs_entry { diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index ef896ee7198b..f7144be96029 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -455,6 +455,31 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev, } } +static bool raid0_is_missing_dev(struct mddev *mddev) +{ + struct md_rdev *rdev; + static int already_missing; + int def_disks, work_disks = 0; + struct r0conf *conf = mddev->private; + + def_disks = conf->strip_zone[0].nb_dev; + rdev_for_each(rdev, mddev) + if (rdev->bdev->bd_disk->flags & GENHD_FL_UP) + work_disks++; + + if (unlikely(def_disks - work_disks)) { + if (already_missing < (def_disks - work_disks)) { + already_missing = def_disks - work_disks; + pr_warn("md: %s: raid0 array has %d missing/failed members\n", + mdname(mddev), already_missing); + } + return true; + } + + already_missing = 0; + return false; +} + static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) { struct r0conf *conf = mddev->private; @@ -788,6 +813,7 @@ static struct md_personality raid0_personality= .takeover = raid0_takeover, .quiesce = raid0_quiesce, .congested = raid0_congested, + .is_missing_dev = raid0_is_missing_dev, }; static int __init raid0_init (void) From patchwork Fri Aug 16 13:41:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guilherme Piccoli X-Patchwork-Id: 11097771 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DEC8613A0 for ; Fri, 16 Aug 2019 13:42:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CEB1228671 for ; Fri, 16 Aug 2019 13:42:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C311A28A2E; Fri, 16 Aug 2019 13:42:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A0ECE289BF for ; Fri, 16 Aug 2019 13:42:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726742AbfHPNmP (ORCPT ); Fri, 16 Aug 2019 09:42:15 -0400 Received: from youngberry.canonical.com ([91.189.89.112]:54810 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727358AbfHPNmP (ORCPT ); Fri, 16 Aug 2019 09:42:15 -0400 Received: from mail-qt1-f198.google.com ([209.85.160.198]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1hycUe-0001OM-Up for linux-block@vger.kernel.org; Fri, 16 Aug 2019 13:42:13 +0000 Received: by mail-qt1-f198.google.com with SMTP id z93so5890726qtc.22 for ; Fri, 16 Aug 2019 06:42:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=l+8f369/PZxPnH/wRGFLn8dKQECj39mKS8gSVV13NFI=; b=DmAJOzx/n6SmDHfkoI6mprEnlGFs97RvQ+jRwazyAS9AEqNyWU610RU54F73upwBff PfPSJg/roF5KYYadl3PTL5vPYtHXLb3VTOVkiUhLQ6QUdTpFHPWWw4YxerZpHbWYBCyU uEiikF9fbjfoOtM0Py4lUpN6ZMx/5x0Z/oJY8pfG2S7Sw4ZT8V9As8VTncwZKVqYO7Aa KF3JUr5LfnXRA4pxvFE5HOyyUeVYo5Gf5bAwVJK2pOECNXQoxsR3hgRcFjL8MtF9n8Wa Nx2/sg5QMF9HyQO7m8jEsadCkBo6z8at8wet0ntLCUF9eotyWBpocQGHfpRcLw9sOA0q XHnw== X-Gm-Message-State: APjAAAUlNt4IvImTi50yIIS6bX86XpkFEBX8BZcd+8CA9agzPcBaKr+M 5SnbXKdYUGR50AHqF/MHWMSwKhjIJXOwMuJ4c8QmYzwVI/e2Vagzps06NUrPQwarhW3+a5LmlkA L3ZdoHItbGz179BDzcJLZ4fWv9BvSMg1LIbSamA9G X-Received: by 2002:a37:ae42:: with SMTP id x63mr8652141qke.41.1565962932141; Fri, 16 Aug 2019 06:42:12 -0700 (PDT) X-Google-Smtp-Source: APXvYqzJTF7IPK6SUgtPz/ldEmLfKgxtVugCq0GMPxIQYTfd1vRzKTe2t9Bp29Ps4UkTYcAArexUGA== X-Received: by 2002:a37:ae42:: with SMTP id x63mr8652119qke.41.1565962931877; Fri, 16 Aug 2019 06:42:11 -0700 (PDT) Received: from localhost ([191.13.19.2]) by smtp.gmail.com with ESMTPSA id d71sm3014956qkg.70.2019.08.16.06.42.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 16 Aug 2019 06:42:11 -0700 (PDT) From: "Guilherme G. Piccoli" To: linux-raid@vger.kernel.org Cc: linux-block@vger.kernel.org, dm-devel@redhat.com, gpiccoli@canonical.com, jay.vosburgh@canonical.com, NeilBrown , Song Liu Subject: [PATCH v2 2/2] mdadm: Introduce new array state 'broken' for raid0/linear Date: Fri, 16 Aug 2019 10:41:00 -0300 Message-Id: <20190816134059.29751-2-gpiccoli@canonical.com> X-Mailer: git-send-email 2.22.0 In-Reply-To: <20190816134059.29751-1-gpiccoli@canonical.com> References: <20190816134059.29751-1-gpiccoli@canonical.com> MIME-Version: 1.0 Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Currently if a md raid0/linear array gets one or more members removed while being mounted, kernel keeps showing state 'clean' in the 'array_state' sysfs attribute. Despite udev signaling the member device is gone, 'mdadm' cannot issue the STOP_ARRAY ioctl successfully, given the array is mounted. Nothing else hints that something is wrong (except that the removed devices don't show properly in the output of mdadm 'detail' command). There is no other property to be checked, and if user is not performing reads/writes to the array, even kernel log is quiet and doesn't give a clue about the missing member. This patch is the mdadm counterpart of kernel new array state 'broken'. The 'broken' state mimics the state 'clean' in every aspect, being useful only to distinguish if an array has some member missing. All necessary paths in mdadm were changed to deal with 'broken' state, and in case the tool runs in a kernel that is not updated, it'll work normally, i.e., it doesn't require the 'broken' state in order to work. Also, this patch changes the way the array state is showed in the 'detail' command (for raid0/linear only) - now it takes the 'array_state' sysfs attribute into account instead of only rely in the MD_SB_CLEAN flag. Cc: NeilBrown Cc: Song Liu Signed-off-by: Guilherme G. Piccoli --- v1 -> v2: * Added handling for md/linear 'broken' state. Detail.c | 17 +++++++++++++++-- Monitor.c | 9 +++++++-- maps.c | 1 + mdadm.h | 1 + mdmon.h | 2 +- monitor.c | 4 ++-- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Detail.c b/Detail.c index ad60434..cc7e9f1 100644 --- a/Detail.c +++ b/Detail.c @@ -81,6 +81,7 @@ int Detail(char *dev, struct context *c) int external; int inactive; int is_container = 0; + char arrayst[12] = { 0 }; /* no state is >10 chars currently */ if (fd < 0) { pr_err("cannot open %s: %s\n", @@ -485,9 +486,21 @@ int Detail(char *dev, struct context *c) else st = ", degraded"; + if (array.state & (1 << MD_SB_CLEAN)) { + if ((array.level == 0) || + (array.level == LEVEL_LINEAR)) + strncpy(arrayst, + map_num(sysfs_array_states, + sra->array_state), + sizeof(arrayst)-1); + else + strncpy(arrayst, "clean", + sizeof(arrayst)-1); + } else + strncpy(arrayst, "active", sizeof(arrayst)-1); + printf(" State : %s%s%s%s%s%s \n", - (array.state & (1 << MD_SB_CLEAN)) ? - "clean" : "active", st, + arrayst, st, (!e || (e->percent < 0 && e->percent != RESYNC_PENDING && e->percent != RESYNC_DELAYED)) ? diff --git a/Monitor.c b/Monitor.c index 036103f..9fd5406 100644 --- a/Monitor.c +++ b/Monitor.c @@ -1055,8 +1055,12 @@ int Wait(char *dev) } } +/* The state "broken" is used only for RAID0/LINEAR - it's the same as + * "clean", but used in case the array has one or more members missing. + */ +#define CLEAN_STATES_LAST_POS 5 static char *clean_states[] = { - "clear", "inactive", "readonly", "read-auto", "clean", NULL }; + "clear", "inactive", "readonly", "read-auto", "clean", "broken", NULL }; int WaitClean(char *dev, int verbose) { @@ -1116,7 +1120,8 @@ int WaitClean(char *dev, int verbose) rv = read(state_fd, buf, sizeof(buf)); if (rv < 0) break; - if (sysfs_match_word(buf, clean_states) <= 4) + if (sysfs_match_word(buf, clean_states) + <= CLEAN_STATES_LAST_POS) break; rv = sysfs_wait(state_fd, &delay); if (rv < 0 && errno != EINTR) diff --git a/maps.c b/maps.c index 02a0474..49b7f2c 100644 --- a/maps.c +++ b/maps.c @@ -150,6 +150,7 @@ mapping_t sysfs_array_states[] = { { "read-auto", ARRAY_READ_AUTO }, { "clean", ARRAY_CLEAN }, { "write-pending", ARRAY_WRITE_PENDING }, + { "broken", ARRAY_BROKEN }, { NULL, ARRAY_UNKNOWN_STATE } }; diff --git a/mdadm.h b/mdadm.h index 43b07d5..c88ceab 100644 --- a/mdadm.h +++ b/mdadm.h @@ -373,6 +373,7 @@ struct mdinfo { ARRAY_ACTIVE, ARRAY_WRITE_PENDING, ARRAY_ACTIVE_IDLE, + ARRAY_BROKEN, ARRAY_UNKNOWN_STATE, } array_state; struct md_bb bb; diff --git a/mdmon.h b/mdmon.h index 818367c..b3d72ac 100644 --- a/mdmon.h +++ b/mdmon.h @@ -21,7 +21,7 @@ extern const char Name[]; enum array_state { clear, inactive, suspended, readonly, read_auto, - clean, active, write_pending, active_idle, bad_word}; + clean, active, write_pending, active_idle, broken, bad_word}; enum sync_action { idle, reshape, resync, recover, check, repair, bad_action }; diff --git a/monitor.c b/monitor.c index 81537ed..e0d3be6 100644 --- a/monitor.c +++ b/monitor.c @@ -26,7 +26,7 @@ static char *array_states[] = { "clear", "inactive", "suspended", "readonly", "read-auto", - "clean", "active", "write-pending", "active-idle", NULL }; + "clean", "active", "write-pending", "active-idle", "broken", NULL }; static char *sync_actions[] = { "idle", "reshape", "resync", "recover", "check", "repair", NULL }; @@ -476,7 +476,7 @@ static int read_and_act(struct active_array *a, fd_set *fds) a->next_state = clean; ret |= ARRAY_DIRTY; } - if (a->curr_state == clean) { + if ((a->curr_state == clean) || (a->curr_state == broken)) { a->container->ss->set_array_state(a, 1); } if (a->curr_state == active ||