|
|
50dc83 |
From 9912a432dc3493007462f76c5933d04a160814ae Mon Sep 17 00:00:00 2001
|
|
|
50dc83 |
From: Pranith Kumar K <pkarampu@redhat.com>
|
|
|
50dc83 |
Date: Thu, 20 Jun 2019 17:05:49 +0530
|
|
|
50dc83 |
Subject: [PATCH 198/221] cluster/ec: Prevent double pre-op xattrops
|
|
|
50dc83 |
|
|
|
50dc83 |
Problem:
|
|
|
50dc83 |
Race:
|
|
|
50dc83 |
Thread-1 Thread-2
|
|
|
50dc83 |
1) Does ec_get_size_version() to perform
|
|
|
50dc83 |
pre-op fxattrop as part of write-1
|
|
|
50dc83 |
2) Calls ec_set_dirty_flag() in
|
|
|
50dc83 |
ec_get_size_version() for write-2.
|
|
|
50dc83 |
This sets dirty[] to 1
|
|
|
50dc83 |
3) Completes executing
|
|
|
50dc83 |
ec_prepare_update_cbk leading to
|
|
|
50dc83 |
ctx->dirty[] = '1'
|
|
|
50dc83 |
4) Takes LOCK(inode->lock) to check if there are
|
|
|
50dc83 |
any flags and sets dirty-flag because
|
|
|
50dc83 |
lock->waiting_flag is 0 now. This leads to
|
|
|
50dc83 |
fxattrop to increment on-disk dirty[] to '2'
|
|
|
50dc83 |
|
|
|
50dc83 |
At the end of the writes the file will be marked for heal even when it doesn't need heal.
|
|
|
50dc83 |
|
|
|
50dc83 |
Fix:
|
|
|
50dc83 |
Perform ec_set_dirty_flag() and other checks inside LOCK() to prevent dirty[] to be marked
|
|
|
50dc83 |
as '1' in step 2) above
|
|
|
50dc83 |
|
|
|
50dc83 |
> Upstream-patch: https://review.gluster.org/c/glusterfs/+/22907
|
|
|
50dc83 |
|
|
|
50dc83 |
fixes: bz#1600918
|
|
|
50dc83 |
Change-Id: Icac2ab39c0b1e7e154387800fbededc561612865
|
|
|
50dc83 |
Signed-off-by: Pranith Kumar K <pkarampu@redhat.com>
|
|
|
50dc83 |
Reviewed-on: https://code.engineering.redhat.com/gerrit/174385
|
|
|
50dc83 |
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
|
|
|
50dc83 |
Tested-by: Atin Mukherjee <amukherj@redhat.com>
|
|
|
50dc83 |
---
|
|
|
50dc83 |
tests/basic/ec/ec-dirty-flags.t | 23 +++++++++++++++++++++++
|
|
|
50dc83 |
xlators/cluster/ec/src/ec-common.c | 13 +++++++------
|
|
|
50dc83 |
2 files changed, 30 insertions(+), 6 deletions(-)
|
|
|
50dc83 |
create mode 100644 tests/basic/ec/ec-dirty-flags.t
|
|
|
50dc83 |
|
|
|
50dc83 |
diff --git a/tests/basic/ec/ec-dirty-flags.t b/tests/basic/ec/ec-dirty-flags.t
|
|
|
50dc83 |
new file mode 100644
|
|
|
50dc83 |
index 0000000..68e6610
|
|
|
50dc83 |
--- /dev/null
|
|
|
50dc83 |
+++ b/tests/basic/ec/ec-dirty-flags.t
|
|
|
50dc83 |
@@ -0,0 +1,23 @@
|
|
|
50dc83 |
+#!/bin/bash
|
|
|
50dc83 |
+
|
|
|
50dc83 |
+. $(dirname $0)/../../include.rc
|
|
|
50dc83 |
+. $(dirname $0)/../../volume.rc
|
|
|
50dc83 |
+
|
|
|
50dc83 |
+# This checks if the fop keeps the dirty flags settings correctly after
|
|
|
50dc83 |
+# finishing the fop.
|
|
|
50dc83 |
+
|
|
|
50dc83 |
+cleanup
|
|
|
50dc83 |
+TEST glusterd
|
|
|
50dc83 |
+TEST pidof glusterd
|
|
|
50dc83 |
+TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..2}
|
|
|
50dc83 |
+TEST $CLI volume heal $V0 disable
|
|
|
50dc83 |
+TEST $CLI volume start $V0
|
|
|
50dc83 |
+
|
|
|
50dc83 |
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0;
|
|
|
50dc83 |
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0
|
|
|
50dc83 |
+cd $M0
|
|
|
50dc83 |
+for i in {1..1000}; do dd if=/dev/zero of=file-${i} bs=512k count=2; done
|
|
|
50dc83 |
+cd -
|
|
|
50dc83 |
+EXPECT "^0$" get_pending_heal_count $V0
|
|
|
50dc83 |
+
|
|
|
50dc83 |
+cleanup
|
|
|
50dc83 |
diff --git a/xlators/cluster/ec/src/ec-common.c b/xlators/cluster/ec/src/ec-common.c
|
|
|
50dc83 |
index 9cc6395..35c2256 100644
|
|
|
50dc83 |
--- a/xlators/cluster/ec/src/ec-common.c
|
|
|
50dc83 |
+++ b/xlators/cluster/ec/src/ec-common.c
|
|
|
50dc83 |
@@ -1405,6 +1405,10 @@ ec_get_size_version(ec_lock_link_t *link)
|
|
|
50dc83 |
!ec_is_data_fop(fop->id))
|
|
|
50dc83 |
link->optimistic_changelog = _gf_true;
|
|
|
50dc83 |
|
|
|
50dc83 |
+ memset(&loc, 0, sizeof(loc));
|
|
|
50dc83 |
+
|
|
|
50dc83 |
+ LOCK(&lock->loc.inode->lock);
|
|
|
50dc83 |
+
|
|
|
50dc83 |
set_dirty = ec_set_dirty_flag(link, ctx, dirty);
|
|
|
50dc83 |
|
|
|
50dc83 |
/* If ec metadata has already been retrieved, do not try again. */
|
|
|
50dc83 |
@@ -1412,20 +1416,16 @@ ec_get_size_version(ec_lock_link_t *link)
|
|
|
50dc83 |
if (ec_is_data_fop(fop->id)) {
|
|
|
50dc83 |
fop->healing |= lock->healing;
|
|
|
50dc83 |
}
|
|
|
50dc83 |
- return;
|
|
|
50dc83 |
+ goto unlock;
|
|
|
50dc83 |
}
|
|
|
50dc83 |
|
|
|
50dc83 |
/* Determine if there's something we need to retrieve for the current
|
|
|
50dc83 |
* operation. */
|
|
|
50dc83 |
if (!set_dirty && !lock->query && (lock->loc.inode->ia_type != IA_IFREG) &&
|
|
|
50dc83 |
(lock->loc.inode->ia_type != IA_INVAL)) {
|
|
|
50dc83 |
- return;
|
|
|
50dc83 |
+ goto unlock;
|
|
|
50dc83 |
}
|
|
|
50dc83 |
|
|
|
50dc83 |
- memset(&loc, 0, sizeof(loc));
|
|
|
50dc83 |
-
|
|
|
50dc83 |
- LOCK(&lock->loc.inode->lock);
|
|
|
50dc83 |
-
|
|
|
50dc83 |
changed_flags = ec_set_xattrop_flags_and_params(lock, link, dirty);
|
|
|
50dc83 |
if (link->waiting_flags) {
|
|
|
50dc83 |
/* This fop needs to wait until all its flags are cleared which
|
|
|
50dc83 |
@@ -1436,6 +1436,7 @@ ec_get_size_version(ec_lock_link_t *link)
|
|
|
50dc83 |
GF_ASSERT(!changed_flags);
|
|
|
50dc83 |
}
|
|
|
50dc83 |
|
|
|
50dc83 |
+unlock:
|
|
|
50dc83 |
UNLOCK(&lock->loc.inode->lock);
|
|
|
50dc83 |
|
|
|
50dc83 |
if (!changed_flags)
|
|
|
50dc83 |
--
|
|
|
50dc83 |
1.8.3.1
|
|
|
50dc83 |
|