From: Cao Guanghui <[email protected]>
update_size() has multiple issues in the revert path when
cluster_check_sync_size() detects that not all nodes have confirmed
the new size:
1. (pre-existing) The return value of resize() is immediately
overwritten by __sendmsg(), so a resize failure is silently lost.
2. (pre-existing) The on-disk superblock still retains the new size
from the earlier md_update_sb() call. Other nodes re-read it and
adopt the new size while the initiator runs with the reverted old
size.
3. (pre-existing) The function returns void, so callers cannot detect
failures.
Fix all of the above by:
- Using a separate variable for __sendmsg result so resize failure
is not overwritten
- Calling md_update_sb() after unlock_comm() to write the reverted
size back to disk. This must be outside the locked section because
md_update_sb() internally acquires MD_CLUSTER_SEND_LOCK via
metadata_update_start(), which would self-deadlock if already held.
- Changing return type from void to int with proper error codes
(-EIO for lock failure, -ENODEV for no device, ret for others)
Fixes: 818da59f97d6 ("md-cluster: add the support for resize")
Cc: [email protected]
Signed-off-by: Cao Guanghui <[email protected]>
---
drivers/md/md-cluster.c | 28 +++++++++++++++++++++++++---
drivers/md/md-cluster.h | 2 +-
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -1302,18 +1302,19 @@ static int cluster_check_sync_size(struct mddev *mddev)
* let other nodes to perform it. If one node can't update sync_size
* accordingly, we need to revert to previous value.
*/
-static void update_size(struct mddev *mddev, sector_t old_dev_sectors)
+static int update_size(struct mddev *mddev, sector_t old_dev_sectors)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
+ bool reverted = false;
struct cluster_msg cmsg;
struct md_rdev *rdev;
- int ret = 0;
+ int ret = 0, msg_ret = 0;
int raid_slot = -1;
md_update_sb(mddev, 1);
if (lock_comm(cinfo, 1)) {
pr_err("%s: lock_comm failed\n", __func__);
- return;
+ return -EIO;
}
memset(&cmsg, 0, sizeof(cmsg));
@@ -1335,12 +1336,12 @@ static int update_size(struct mddev *mddev, sector_t old_dev_sectors)
pr_err("%s:%d: failed to send METADATA_UPDATED msg\n",
__func__, __LINE__);
unlock_comm(cinfo);
- return;
+ return ret;
}
} else {
pr_err("md-cluster: No good device id found to send\n");
unlock_comm(cinfo);
- return;
+ return -ENODEV;
}
/*
@@ -1359,12 +1360,28 @@ static int update_size(struct mddev *mddev, sector_t old_dev_sectors)
} else {
/* revert to previous sectors */
ret = mddev->pers->resize(mddev, old_dev_sectors);
- ret = __sendmsg(cinfo, &cmsg);
if (ret)
+ pr_err("%s:%d: failed to revert array size\n",
+ __func__, __LINE__);
+ reverted = true;
+ msg_ret = __sendmsg(cinfo, &cmsg);
+ if (msg_ret) {
pr_err("%s:%d: failed to send METADATA_UPDATED msg\n",
__func__, __LINE__);
+ if (!ret)
+ ret = msg_ret;
+ }
}
unlock_comm(cinfo);
+
+ if (reverted)
+ /* Update on-disk superblock to match reverted in-memory
+ * size. Must be after unlock_comm() to avoid self-deadlock
+ * since md_update_sb() acquires the cluster send lock.
+ */
+ md_update_sb(mddev, 1);
+
+ return ret;
}
static int resync_start(struct mddev *mddev)
diff --git a/drivers/md/md-cluster.h b/drivers/md/md-cluster.h
--- a/drivers/md/md-cluster.h
+++ b/drivers/md/md-cluster.h
@@ -34,7 +34,7 @@ struct md_cluster_operations {
int (*resize_bitmaps)(struct mddev *mddev, sector_t newsize, sector_t oldsize);
int (*lock_all_bitmaps)(struct mddev *mddev);
void (*unlock_all_bitmaps)(struct mddev *mddev);
- void (*update_size)(struct mddev *mddev, sector_t old_dev_sectors);
+ int (*update_size)(struct mddev *mddev, sector_t old_dev_sectors);
};
extern int md_setup_cluster(struct mddev *mddev, int nodes);
--
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.