From 71080da8ddd0d31ecdf1ad9185efcc5573997c81 Mon Sep 17 00:00:00 2001 From: Deepshikha Khandelwal Date: Tue, 21 Jul 2020 06:42:33 +0000 Subject: [PATCH] autobuild v6.0-40 Resolves: bz#1812789 bz#1844359 bz#1847081 bz#1854165 Signed-off-by: Deepshikha Khandelwal --- ...DHT-Handle-the-pause-case-missed-out.patch | 48 + 0453-glusterd-add-brick-command-failure.patch | 300 ++++ ...void-use-after-freed-of-frame-for-bl.patch | 152 ++ ...s-prevent-deletion-of-locked-entries.patch | 1253 +++++++++++++++++ 0456-add-clean-local-after-grant-lock.patch | 74 + glusterfs.spec | 10 +- 6 files changed, 1836 insertions(+), 1 deletion(-) create mode 100644 0452-Tier-DHT-Handle-the-pause-case-missed-out.patch create mode 100644 0453-glusterd-add-brick-command-failure.patch create mode 100644 0454-features-locks-avoid-use-after-freed-of-frame-for-bl.patch create mode 100644 0455-locks-prevent-deletion-of-locked-entries.patch create mode 100644 0456-add-clean-local-after-grant-lock.patch diff --git a/0452-Tier-DHT-Handle-the-pause-case-missed-out.patch b/0452-Tier-DHT-Handle-the-pause-case-missed-out.patch new file mode 100644 index 0000000..0b115bb --- /dev/null +++ b/0452-Tier-DHT-Handle-the-pause-case-missed-out.patch @@ -0,0 +1,48 @@ +From c184943bdf38de5b4cbf165fd1cd98ce7bd9e976 Mon Sep 17 00:00:00 2001 +From: hari gowtham +Date: Tue, 16 Jun 2020 14:47:53 +0530 +Subject: [PATCH 452/456] Tier/DHT: Handle the pause case missed out + +Problem: While backporting a change from master +the changes related to tier were removed. This started affecting +the tier pause functionality. Backporting it +to downstream left this usecase messed up as we still support tier. +patch that caused this: https://code.engineering.redhat.com/gerrit/#/c/202647/2 + +Fix: add the condition back for tier pause to work. + +Label: DOWNSTREAM ONLY + +BUG: 1844359 +Change-Id: I46c6c179b09c7e1a729be9fd257fa4a490f0287e +Signed-off-by: hari gowtham +Reviewed-on: https://code.engineering.redhat.com/gerrit/203560 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + xlators/cluster/dht/src/dht-rebalance.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/xlators/cluster/dht/src/dht-rebalance.c b/xlators/cluster/dht/src/dht-rebalance.c +index e9974cd..abc10fc 100644 +--- a/xlators/cluster/dht/src/dht-rebalance.c ++++ b/xlators/cluster/dht/src/dht-rebalance.c +@@ -1160,6 +1160,15 @@ __dht_rebalance_migrate_data(xlator_t *this, gf_defrag_info_t *defrag, + break; + } + ++ if ((defrag && defrag->cmd == GF_DEFRAG_CMD_START_TIER) && ++ (gf_defrag_get_pause_state(&defrag->tier_conf) != TIER_RUNNING)) { ++ gf_msg("tier", GF_LOG_INFO, 0, DHT_MSG_TIER_PAUSED, ++ "Migrate file paused"); ++ ret = -1; ++ break; ++ } ++ ++ + offset += ret; + total += ret; + +-- +1.8.3.1 + diff --git a/0453-glusterd-add-brick-command-failure.patch b/0453-glusterd-add-brick-command-failure.patch new file mode 100644 index 0000000..dd21350 --- /dev/null +++ b/0453-glusterd-add-brick-command-failure.patch @@ -0,0 +1,300 @@ +From a04592cce9aaa6ccb8a038bc3b4e31bc125d1d10 Mon Sep 17 00:00:00 2001 +From: Sanju Rakonde +Date: Tue, 16 Jun 2020 18:03:21 +0530 +Subject: [PATCH 453/456] glusterd: add-brick command failure + +Problem: add-brick operation is failing when replica or disperse +count is not mentioned in the add-brick command. + +Reason: with commit a113d93 we are checking brick order while +doing add-brick operation for replica and disperse volumes. If +replica count or disperse count is not mentioned in the command, +the dict get is failing and resulting add-brick operation failure. + +> upstream patch: https://review.gluster.org/#/c/glusterfs/+/24581/ +> fixes: #1306 +> Change-Id: Ie957540e303bfb5f2d69015661a60d7e72557353 +> Signed-off-by: Sanju Rakonde + +BUG: 1847081 +Change-Id: Ie957540e303bfb5f2d69015661a60d7e72557353 +Signed-off-by: Sanju Rakonde +Reviewed-on: https://code.engineering.redhat.com/gerrit/203867 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + tests/bugs/glusterd/brick-order-check-add-brick.t | 40 ++++++++++++++++++++++ + tests/cluster.rc | 11 ++++-- + xlators/mgmt/glusterd/src/glusterd-brick-ops.c | 39 ++++++++++++++------- + xlators/mgmt/glusterd/src/glusterd-utils.c | 30 ++--------------- + xlators/mgmt/glusterd/src/glusterd-utils.h | 3 +- + xlators/mgmt/glusterd/src/glusterd-volume-ops.c | 41 +++++++++++++++++++---- + 6 files changed, 115 insertions(+), 49 deletions(-) + create mode 100644 tests/bugs/glusterd/brick-order-check-add-brick.t + +diff --git a/tests/bugs/glusterd/brick-order-check-add-brick.t b/tests/bugs/glusterd/brick-order-check-add-brick.t +new file mode 100644 +index 0000000..29f0ed1 +--- /dev/null ++++ b/tests/bugs/glusterd/brick-order-check-add-brick.t +@@ -0,0 +1,40 @@ ++#!/bin/bash ++. $(dirname $0)/../../include.rc ++. $(dirname $0)/../../volume.rc ++. $(dirname $0)/../../cluster.rc ++. $(dirname $0)/../../snapshot.rc ++ ++cleanup; ++ ++TEST verify_lvm_version; ++#Create cluster with 3 nodes ++TEST launch_cluster 3 -NO_DEBUG -NO_FORCE ++TEST setup_lvm 3 ++ ++TEST $CLI_1 peer probe $H2 ++TEST $CLI_1 peer probe $H3 ++EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count ++ ++TEST $CLI_1 volume create $V0 replica 3 $H1:$L1/$V0 $H2:$L2/$V0 $H3:$L3/$V0 ++EXPECT '1 x 3 = 3' volinfo_field $V0 'Number of Bricks' ++EXPECT 'Created' volinfo_field $V0 'Status' ++ ++TEST $CLI_1 volume start $V0 ++EXPECT 'Started' volinfo_field $V0 'Status' ++ ++#add-brick with or without mentioning the replica count should not fail ++TEST $CLI_1 volume add-brick $V0 replica 3 $H1:$L1/${V0}_1 $H2:$L2/${V0}_1 $H3:$L3/${V0}_1 ++EXPECT '2 x 3 = 6' volinfo_field $V0 'Number of Bricks' ++ ++TEST $CLI_1 volume add-brick $V0 $H1:$L1/${V0}_2 $H2:$L2/${V0}_2 $H3:$L3/${V0}_2 ++EXPECT '3 x 3 = 9' volinfo_field $V0 'Number of Bricks' ++ ++#adding bricks from same host should fail the brick order check ++TEST ! $CLI_1 volume add-brick $V0 $H1:$L1/${V0}_3 $H1:$L1/${V0}_4 $H1:$L1/${V0}_5 ++EXPECT '3 x 3 = 9' volinfo_field $V0 'Number of Bricks' ++ ++#adding bricks from same host with force should succeed ++TEST $CLI_1 volume add-brick $V0 $H1:$L1/${V0}_3 $H1:$L1/${V0}_4 $H1:$L1/${V0}_5 force ++EXPECT '4 x 3 = 12' volinfo_field $V0 'Number of Bricks' ++ ++cleanup +diff --git a/tests/cluster.rc b/tests/cluster.rc +index 99be8e7..8b73153 100644 +--- a/tests/cluster.rc ++++ b/tests/cluster.rc +@@ -11,7 +11,7 @@ function launch_cluster() { + define_backends $count; + define_hosts $count; + define_glusterds $count $2; +- define_clis $count; ++ define_clis $count $3; + + start_glusterds; + } +@@ -133,8 +133,13 @@ function define_clis() { + lopt1="--log-file=$logdir/$logfile1" + + +- eval "CLI_$i='$CLI --glusterd-sock=${!b}/glusterd/gd.sock $lopt'"; +- eval "CLI$i='$CLI --glusterd-sock=${!b}/glusterd/gd.sock $lopt1'"; ++ if [ "$2" == "-NO_FORCE" ]; then ++ eval "CLI_$i='$CLI_NO_FORCE --glusterd-sock=${!b}/glusterd/gd.sock $lopt'"; ++ eval "CLI$i='$CLI_NO_FORCE --glusterd-sock=${!b}/glusterd/gd.sock $lopt1'"; ++ else ++ eval "CLI_$i='$CLI --glusterd-sock=${!b}/glusterd/gd.sock $lopt'"; ++ eval "CLI$i='$CLI --glusterd-sock=${!b}/glusterd/gd.sock $lopt1'"; ++ fi + done + } + +diff --git a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c +index 121346c..5ae577a 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c ++++ b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c +@@ -1576,20 +1576,35 @@ glusterd_op_stage_add_brick(dict_t *dict, char **op_errstr, dict_t *rsp_dict) + + /* Check brick order if the volume type is replicate or disperse. If + * force at the end of command not given then check brick order. ++ * doing this check at the originator node is sufficient. + */ + +- if (!is_force) { +- if ((volinfo->type == GF_CLUSTER_TYPE_REPLICATE) || +- (volinfo->type == GF_CLUSTER_TYPE_DISPERSE)) { +- ret = glusterd_check_brick_order(dict, msg, volinfo->type); +- if (ret) { +- gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BAD_BRKORDER, +- "Not adding brick because of " +- "bad brick order. %s", +- msg); +- *op_errstr = gf_strdup(msg); +- goto out; +- } ++ if (is_origin_glusterd(dict) && !is_force) { ++ ret = 0; ++ if (volinfo->type == GF_CLUSTER_TYPE_REPLICATE) { ++ gf_msg_debug(this->name, 0, ++ "Replicate cluster type " ++ "found. Checking brick order."); ++ if (replica_count) ++ ret = glusterd_check_brick_order(dict, msg, volinfo->type, ++ replica_count); ++ else ++ ret = glusterd_check_brick_order(dict, msg, volinfo->type, ++ volinfo->replica_count); ++ } else if (volinfo->type == GF_CLUSTER_TYPE_DISPERSE) { ++ gf_msg_debug(this->name, 0, ++ "Disperse cluster type" ++ " found. Checking brick order."); ++ ret = glusterd_check_brick_order(dict, msg, volinfo->type, ++ volinfo->disperse_count); ++ } ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BAD_BRKORDER, ++ "Not adding brick because of " ++ "bad brick order. %s", ++ msg); ++ *op_errstr = gf_strdup(msg); ++ goto out; + } + } + +diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c +index 6f904ae..545e688 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-utils.c ++++ b/xlators/mgmt/glusterd/src/glusterd-utils.c +@@ -14802,7 +14802,8 @@ glusterd_compare_addrinfo(struct addrinfo *first, struct addrinfo *next) + * volume are present on the same server + */ + int32_t +-glusterd_check_brick_order(dict_t *dict, char *err_str, int32_t type) ++glusterd_check_brick_order(dict_t *dict, char *err_str, int32_t type, ++ int32_t sub_count) + { + int ret = -1; + int i = 0; +@@ -14819,7 +14820,6 @@ glusterd_check_brick_order(dict_t *dict, char *err_str, int32_t type) + char *tmpptr = NULL; + char *volname = NULL; + int32_t brick_count = 0; +- int32_t sub_count = 0; + struct addrinfo *ai_info = NULL; + char brick_addr[128] = { + 0, +@@ -14870,31 +14870,6 @@ glusterd_check_brick_order(dict_t *dict, char *err_str, int32_t type) + goto out; + } + +- if (type != GF_CLUSTER_TYPE_DISPERSE) { +- ret = dict_get_int32n(dict, "replica-count", SLEN("replica-count"), +- &sub_count); +- if (ret) { +- gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, +- "Bricks check : Could" +- " not retrieve replica count"); +- goto out; +- } +- gf_msg_debug(this->name, 0, +- "Replicate cluster type " +- "found. Checking brick order."); +- } else { +- ret = dict_get_int32n(dict, "disperse-count", SLEN("disperse-count"), +- &sub_count); +- if (ret) { +- gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, +- "Bricks check : Could" +- " not retrieve disperse count"); +- goto out; +- } +- gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_DISPERSE_CLUSTER_FOUND, +- "Disperse cluster type" +- " found. Checking brick order."); +- } + brick_list_dup = brick_list_ptr = gf_strdup(brick_list); + /* Resolve hostnames and get addrinfo */ + while (i < brick_count) { +@@ -14989,5 +14964,6 @@ out: + ai_list_tmp2 = ai_list_tmp1; + } + free(ai_list_tmp2); ++ gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; + } +diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h +index e2e2454..5f5de82 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-utils.h ++++ b/xlators/mgmt/glusterd/src/glusterd-utils.h +@@ -883,6 +883,7 @@ char * + search_brick_path_from_proc(pid_t brick_pid, char *brickpath); + + int32_t +-glusterd_check_brick_order(dict_t *dict, char *err_str, int32_t type); ++glusterd_check_brick_order(dict_t *dict, char *err_str, int32_t type, ++ int32_t sub_count); + + #endif +diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +index 8da2ff3..134b04c 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c ++++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +@@ -1024,6 +1024,8 @@ glusterd_op_stage_create_volume(dict_t *dict, char **op_errstr, + int32_t local_brick_count = 0; + int32_t i = 0; + int32_t type = 0; ++ int32_t replica_count = 0; ++ int32_t disperse_count = 0; + char *brick = NULL; + char *tmpptr = NULL; + xlator_t *this = NULL; +@@ -1119,15 +1121,42 @@ glusterd_op_stage_create_volume(dict_t *dict, char **op_errstr, + } + + if (!is_force) { +- if ((type == GF_CLUSTER_TYPE_REPLICATE) || +- (type == GF_CLUSTER_TYPE_DISPERSE)) { +- ret = glusterd_check_brick_order(dict, msg, type); ++ if (type == GF_CLUSTER_TYPE_REPLICATE) { ++ ret = dict_get_int32n(dict, "replica-count", ++ SLEN("replica-count"), &replica_count); + if (ret) { +- gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BAD_BRKORDER, +- "Not creating volume because of " +- "bad brick order"); ++ gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, ++ "Bricks check : Could" ++ " not retrieve replica count"); ++ goto out; ++ } ++ gf_msg_debug(this->name, 0, ++ "Replicate cluster type " ++ "found. Checking brick order."); ++ ret = glusterd_check_brick_order(dict, msg, type, ++ replica_count); ++ } else if (type == GF_CLUSTER_TYPE_DISPERSE) { ++ ret = dict_get_int32n(dict, "disperse-count", ++ SLEN("disperse-count"), &disperse_count); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, ++ "Bricks check : Could" ++ " not retrieve disperse count"); + goto out; + } ++ gf_msg_debug(this->name, 0, ++ "Disperse cluster type" ++ " found. Checking brick order."); ++ ret = glusterd_check_brick_order(dict, msg, type, ++ disperse_count); ++ } ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BAD_BRKORDER, ++ "Not creating the volume because of " ++ "bad brick order. %s", ++ msg); ++ *op_errstr = gf_strdup(msg); ++ goto out; + } + } + } +-- +1.8.3.1 + diff --git a/0454-features-locks-avoid-use-after-freed-of-frame-for-bl.patch b/0454-features-locks-avoid-use-after-freed-of-frame-for-bl.patch new file mode 100644 index 0000000..6ad460d --- /dev/null +++ b/0454-features-locks-avoid-use-after-freed-of-frame-for-bl.patch @@ -0,0 +1,152 @@ +From cddd253c5e3f0a7c3b91c35cea8ad1921cb43b98 Mon Sep 17 00:00:00 2001 +From: Kinglong Mee +Date: Thu, 18 Jul 2019 11:43:01 +0800 +Subject: [PATCH 454/456] features/locks: avoid use after freed of frame for + blocked lock + +The fop contains blocked lock may use freed frame info when other +unlock fop has unwind the blocked lock. + +Because the blocked lock is added to block list in inode lock(or +other lock), after that, when out of the inode lock, the fop +contains the blocked lock should not use it. + +Upstream Patch - https://review.gluster.org/#/c/glusterfs/+/23155/ + +>Change-Id: Icb309a1cc78380dc982b26d50c18d67e4f2c8915 +>fixes: bz#1737291 +>Signed-off-by: Kinglong Mee + +Change-Id: Icb309a1cc78380dc982b26d50c18d67e4f2c8915 +BUG: 1812789 +Reviewed-on: https://code.engineering.redhat.com/gerrit/206465 +Tested-by: RHGS Build Bot +Reviewed-by: Xavi Hernandez Juan +--- + xlators/features/locks/src/common.c | 4 ++++ + xlators/features/locks/src/entrylk.c | 4 ++-- + xlators/features/locks/src/inodelk.c | 7 +++++-- + xlators/features/locks/src/posix.c | 5 +++-- + xlators/features/locks/src/reservelk.c | 2 -- + 5 files changed, 14 insertions(+), 8 deletions(-) + +diff --git a/xlators/features/locks/src/common.c b/xlators/features/locks/src/common.c +index 6e7fb4b..1406e70 100644 +--- a/xlators/features/locks/src/common.c ++++ b/xlators/features/locks/src/common.c +@@ -1080,6 +1080,10 @@ pl_setlk(xlator_t *this, pl_inode_t *pl_inode, posix_lock_t *lock, + lock->fl_type == F_UNLCK ? "Unlock" : "Lock", + lock->client_pid, lkowner_utoa(&lock->owner), + lock->user_flock.l_start, lock->user_flock.l_len); ++ ++ pl_trace_block(this, lock->frame, NULL, NULL, F_SETLKW, ++ &lock->user_flock, NULL); ++ + lock->blocked = 1; + __insert_lock(pl_inode, lock); + ret = -1; +diff --git a/xlators/features/locks/src/entrylk.c b/xlators/features/locks/src/entrylk.c +index ced5eca..93c649c 100644 +--- a/xlators/features/locks/src/entrylk.c ++++ b/xlators/features/locks/src/entrylk.c +@@ -552,6 +552,8 @@ __lock_blocked_add(xlator_t *this, pl_inode_t *pinode, pl_dom_list_t *dom, + gf_msg_trace(this->name, 0, "Blocking lock: {pinode=%p, basename=%s}", + pinode, lock->basename); + ++ entrylk_trace_block(this, lock->frame, NULL, NULL, NULL, lock->basename, ++ ENTRYLK_LOCK, lock->type); + out: + return -EAGAIN; + } +@@ -932,8 +934,6 @@ out: + op_ret, op_errno); + unwind: + STACK_UNWIND_STRICT(entrylk, frame, op_ret, op_errno, NULL); +- } else { +- entrylk_trace_block(this, frame, volume, fd, loc, basename, cmd, type); + } + + if (pcontend != NULL) { +diff --git a/xlators/features/locks/src/inodelk.c b/xlators/features/locks/src/inodelk.c +index a9c42f1..24dee49 100644 +--- a/xlators/features/locks/src/inodelk.c ++++ b/xlators/features/locks/src/inodelk.c +@@ -420,6 +420,8 @@ __lock_blocked_add(xlator_t *this, pl_dom_list_t *dom, pl_inode_lock_t *lock, + lkowner_utoa(&lock->owner), lock->user_flock.l_start, + lock->user_flock.l_len); + ++ pl_trace_block(this, lock->frame, NULL, NULL, F_SETLKW, &lock->user_flock, ++ lock->volume); + out: + return -EAGAIN; + } +@@ -959,6 +961,7 @@ pl_common_inodelk(call_frame_t *frame, xlator_t *this, const char *volume, + int ret = -1; + GF_UNUSED int dict_ret = -1; + int can_block = 0; ++ short lock_type = 0; + pl_inode_t *pinode = NULL; + pl_inode_lock_t *reqlock = NULL; + pl_dom_list_t *dom = NULL; +@@ -1024,13 +1027,13 @@ pl_common_inodelk(call_frame_t *frame, xlator_t *this, const char *volume, + /* fall through */ + + case F_SETLK: ++ lock_type = flock->l_type; + memcpy(&reqlock->user_flock, flock, sizeof(struct gf_flock)); + ret = pl_inode_setlk(this, ctx, pinode, reqlock, can_block, dom, + inode); + + if (ret < 0) { +- if ((can_block) && (F_UNLCK != flock->l_type)) { +- pl_trace_block(this, frame, fd, loc, cmd, flock, volume); ++ if ((can_block) && (F_UNLCK != lock_type)) { + goto out; + } + gf_log(this->name, GF_LOG_TRACE, "returning EAGAIN"); +diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c +index 50f1265..7887b82 100644 +--- a/xlators/features/locks/src/posix.c ++++ b/xlators/features/locks/src/posix.c +@@ -2557,6 +2557,7 @@ pl_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + uint32_t lk_flags = 0; + posix_locks_private_t *priv = this->private; + pl_local_t *local = NULL; ++ short lock_type = 0; + + int ret = dict_get_uint32(xdata, GF_LOCK_MODE, &lk_flags); + if (ret == 0) { +@@ -2701,6 +2702,7 @@ pl_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + case F_SETLK: + reqlock->frame = frame; + reqlock->this = this; ++ lock_type = flock->l_type; + + pthread_mutex_lock(&pl_inode->mutex); + { +@@ -2738,8 +2740,7 @@ pl_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + + ret = pl_setlk(this, pl_inode, reqlock, can_block); + if (ret == -1) { +- if ((can_block) && (F_UNLCK != flock->l_type)) { +- pl_trace_block(this, frame, fd, NULL, cmd, flock, NULL); ++ if ((can_block) && (F_UNLCK != lock_type)) { + goto out; + } + gf_log(this->name, GF_LOG_DEBUG, "returning EAGAIN"); +diff --git a/xlators/features/locks/src/reservelk.c b/xlators/features/locks/src/reservelk.c +index 51076d7..604691f 100644 +--- a/xlators/features/locks/src/reservelk.c ++++ b/xlators/features/locks/src/reservelk.c +@@ -312,8 +312,6 @@ grant_blocked_lock_calls(xlator_t *this, pl_inode_t *pl_inode) + ret = pl_setlk(this, pl_inode, lock, can_block); + if (ret == -1) { + if (can_block) { +- pl_trace_block(this, lock->frame, fd, NULL, cmd, +- &lock->user_flock, NULL); + continue; + } else { + gf_log(this->name, GF_LOG_DEBUG, "returning EAGAIN"); +-- +1.8.3.1 + diff --git a/0455-locks-prevent-deletion-of-locked-entries.patch b/0455-locks-prevent-deletion-of-locked-entries.patch new file mode 100644 index 0000000..5960690 --- /dev/null +++ b/0455-locks-prevent-deletion-of-locked-entries.patch @@ -0,0 +1,1253 @@ +From 3f6ff474db3934f43d9963dfe4dda7d201211e75 Mon Sep 17 00:00:00 2001 +From: Xavi Hernandez +Date: Fri, 12 Jun 2020 00:06:36 +0200 +Subject: [PATCH 455/456] locks: prevent deletion of locked entries + +To keep consistency inside transactions started by locking an entry or +an inode, this change delays the removal of entries that are currently +locked by one or more clients. Once all locks are released, the removal +is processed. + +It has also been improved the detection of stale inodes in the locking +code of EC. + +>Upstream patch - https://review.gluster.org/#/c/glusterfs/+/20025/ +>Fixes: #990 + +Change-Id: Ic8ba23d9480f80c7f74e7a310bf8a15922320fd5 +BUG: 1812789 +Signed-off-by: Xavi Hernandez +Reviewed-on: https://code.engineering.redhat.com/gerrit/206442 +Tested-by: RHGS Build Bot +--- + xlators/cluster/ec/src/ec-locks.c | 69 ++++++-- + xlators/features/locks/src/common.c | 316 ++++++++++++++++++++++++++++++++++- + xlators/features/locks/src/common.h | 43 +++++ + xlators/features/locks/src/entrylk.c | 19 +-- + xlators/features/locks/src/inodelk.c | 150 ++++++++++------- + xlators/features/locks/src/locks.h | 23 ++- + xlators/features/locks/src/posix.c | 183 ++++++++++++++++++-- + 7 files changed, 689 insertions(+), 114 deletions(-) + +diff --git a/xlators/cluster/ec/src/ec-locks.c b/xlators/cluster/ec/src/ec-locks.c +index ffcac07..db86296 100644 +--- a/xlators/cluster/ec/src/ec-locks.c ++++ b/xlators/cluster/ec/src/ec-locks.c +@@ -28,9 +28,36 @@ ec_lock_check(ec_fop_data_t *fop, uintptr_t *mask) + ec_t *ec = fop->xl->private; + ec_cbk_data_t *ans = NULL; + ec_cbk_data_t *cbk = NULL; +- uintptr_t locked = 0, notlocked = 0; ++ uintptr_t locked = 0; ++ int32_t good = 0; ++ int32_t eagain = 0; ++ int32_t estale = 0; + int32_t error = -1; + ++ /* There are some errors that we'll handle in an special way while trying ++ * to acquire a lock. ++ * ++ * EAGAIN: If it's found during a parallel non-blocking lock request, we ++ * consider that there's contention on the inode, so we consider ++ * the acquisition a failure and try again with a sequential ++ * blocking lock request. This will ensure that we get a lock on ++ * as many bricks as possible (ignoring EAGAIN here would cause ++ * unnecessary triggers of self-healing). ++ * ++ * If it's found during a sequential blocking lock request, it's ++ * considered an error. Lock will only succeed if there are ++ * enough other bricks locked. ++ * ++ * ESTALE: This can appear during parallel or sequential lock request if ++ * the inode has just been unlinked. We consider this error is ++ * not recoverable, but we also don't consider it as fatal. So, ++ * if it happens during parallel lock, we won't attempt a ++ * sequential one unless there are EAGAIN errors on other ++ * bricks (and are enough to form a quorum), but if we reach ++ * quorum counting the ESTALE bricks, we consider the whole ++ * result of the operation is ESTALE instead of EIO. ++ */ ++ + list_for_each_entry(ans, &fop->cbk_list, list) + { + if (ans->op_ret >= 0) { +@@ -38,24 +65,23 @@ ec_lock_check(ec_fop_data_t *fop, uintptr_t *mask) + error = EIO; + } + locked |= ans->mask; ++ good = ans->count; + cbk = ans; +- } else { +- if (ans->op_errno == EAGAIN) { +- switch (fop->uint32) { +- case EC_LOCK_MODE_NONE: +- case EC_LOCK_MODE_ALL: +- /* Goal is to treat non-blocking lock as failure +- * even if there is a single EAGAIN*/ +- notlocked |= ans->mask; +- break; +- } +- } ++ } else if (ans->op_errno == ESTALE) { ++ estale += ans->count; ++ } else if ((ans->op_errno == EAGAIN) && ++ (fop->uint32 != EC_LOCK_MODE_INC)) { ++ eagain += ans->count; + } + } + + if (error == -1) { +- if (gf_bits_count(locked | notlocked) >= ec->fragments) { +- if (notlocked == 0) { ++ /* If we have enough quorum with succeeded and EAGAIN answers, we ++ * ignore for now any ESTALE answer. If there are EAGAIN answers, ++ * we retry with a sequential blocking lock request if needed. ++ * Otherwise we succeed. */ ++ if ((good + eagain) >= ec->fragments) { ++ if (eagain == 0) { + if (fop->answer == NULL) { + fop->answer = cbk; + } +@@ -68,21 +94,28 @@ ec_lock_check(ec_fop_data_t *fop, uintptr_t *mask) + case EC_LOCK_MODE_NONE: + error = EAGAIN; + break; +- + case EC_LOCK_MODE_ALL: + fop->uint32 = EC_LOCK_MODE_INC; + break; +- + default: ++ /* This shouldn't happen because eagain cannot be > 0 ++ * when fop->uint32 is EC_LOCK_MODE_INC. */ + error = EIO; + break; + } + } + } else { +- if (fop->answer && fop->answer->op_ret < 0) ++ /* We have been unable to find enough candidates that will be able ++ * to take the lock. If we have quorum on some answer, we return ++ * it. Otherwise we check if ESTALE answers allow us to reach ++ * quorum. If so, we return ESTALE. */ ++ if (fop->answer && fop->answer->op_ret < 0) { + error = fop->answer->op_errno; +- else ++ } else if ((good + eagain + estale) >= ec->fragments) { ++ error = ESTALE; ++ } else { + error = EIO; ++ } + } + } + +diff --git a/xlators/features/locks/src/common.c b/xlators/features/locks/src/common.c +index 1406e70..0c52853 100644 +--- a/xlators/features/locks/src/common.c ++++ b/xlators/features/locks/src/common.c +@@ -462,11 +462,16 @@ pl_inode_get(xlator_t *this, inode_t *inode, pl_local_t *local) + INIT_LIST_HEAD(&pl_inode->blocked_calls); + INIT_LIST_HEAD(&pl_inode->metalk_list); + INIT_LIST_HEAD(&pl_inode->queued_locks); ++ INIT_LIST_HEAD(&pl_inode->waiting); + gf_uuid_copy(pl_inode->gfid, inode->gfid); + + pl_inode->check_mlock_info = _gf_true; + pl_inode->mlock_enforced = _gf_false; + ++ /* -2 means never looked up. -1 means something went wrong and link ++ * tracking is disabled. */ ++ pl_inode->links = -2; ++ + ret = __inode_ctx_put(inode, this, (uint64_t)(long)(pl_inode)); + if (ret) { + pthread_mutex_destroy(&pl_inode->mutex); +@@ -1276,4 +1281,313 @@ pl_local_init(call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd) + } + + return 0; +-} +\ No newline at end of file ++} ++ ++gf_boolean_t ++pl_is_lk_owner_valid(gf_lkowner_t *owner, client_t *client) ++{ ++ if (client && (client->opversion < GD_OP_VERSION_7_0)) { ++ return _gf_true; ++ } ++ ++ if (is_lk_owner_null(owner)) { ++ return _gf_false; ++ } ++ return _gf_true; ++} ++ ++static int32_t ++pl_inode_from_loc(loc_t *loc, inode_t **pinode) ++{ ++ inode_t *inode = NULL; ++ int32_t error = 0; ++ ++ if (loc->inode != NULL) { ++ inode = inode_ref(loc->inode); ++ goto done; ++ } ++ ++ if (loc->parent == NULL) { ++ error = EINVAL; ++ goto done; ++ } ++ ++ if (!gf_uuid_is_null(loc->gfid)) { ++ inode = inode_find(loc->parent->table, loc->gfid); ++ if (inode != NULL) { ++ goto done; ++ } ++ } ++ ++ if (loc->name == NULL) { ++ error = EINVAL; ++ goto done; ++ } ++ ++ inode = inode_grep(loc->parent->table, loc->parent, loc->name); ++ if (inode == NULL) { ++ /* We haven't found any inode. This means that the file doesn't exist ++ * or that even if it exists, we don't have any knowledge about it, so ++ * we don't have locks on it either, which is fine for our purposes. */ ++ goto done; ++ } ++ ++done: ++ *pinode = inode; ++ ++ return error; ++} ++ ++static gf_boolean_t ++pl_inode_has_owners(xlator_t *xl, client_t *client, pl_inode_t *pl_inode, ++ struct timespec *now, struct list_head *contend) ++{ ++ pl_dom_list_t *dom; ++ pl_inode_lock_t *lock; ++ gf_boolean_t has_owners = _gf_false; ++ ++ list_for_each_entry(dom, &pl_inode->dom_list, inode_list) ++ { ++ list_for_each_entry(lock, &dom->inodelk_list, list) ++ { ++ /* If the lock belongs to the same client, we assume it's related ++ * to the same operation, so we allow the removal to continue. */ ++ if (lock->client == client) { ++ continue; ++ } ++ /* If the lock belongs to an internal process, we don't block the ++ * removal. */ ++ if (lock->client_pid < 0) { ++ continue; ++ } ++ if (contend == NULL) { ++ return _gf_true; ++ } ++ has_owners = _gf_true; ++ inodelk_contention_notify_check(xl, lock, now, contend); ++ } ++ } ++ ++ return has_owners; ++} ++ ++int32_t ++pl_inode_remove_prepare(xlator_t *xl, call_frame_t *frame, loc_t *loc, ++ pl_inode_t **ppl_inode, struct list_head *contend) ++{ ++ struct timespec now; ++ inode_t *inode; ++ pl_inode_t *pl_inode; ++ int32_t error; ++ ++ pl_inode = NULL; ++ ++ error = pl_inode_from_loc(loc, &inode); ++ if ((error != 0) || (inode == NULL)) { ++ goto done; ++ } ++ ++ pl_inode = pl_inode_get(xl, inode, NULL); ++ if (pl_inode == NULL) { ++ inode_unref(inode); ++ error = ENOMEM; ++ goto done; ++ } ++ ++ /* pl_inode_from_loc() already increments ref count for inode, so ++ * we only assign here our reference. */ ++ pl_inode->inode = inode; ++ ++ timespec_now(&now); ++ ++ pthread_mutex_lock(&pl_inode->mutex); ++ ++ if (pl_inode->removed) { ++ error = ESTALE; ++ goto unlock; ++ } ++ ++ if (pl_inode_has_owners(xl, frame->root->client, pl_inode, &now, contend)) { ++ error = -1; ++ /* We skip the unlock here because the caller must create a stub when ++ * we return -1 and do a call to pl_inode_remove_complete(), which ++ * assumes the lock is still acquired and will release it once ++ * everything else is prepared. */ ++ goto done; ++ } ++ ++ pl_inode->is_locked = _gf_true; ++ pl_inode->remove_running++; ++ ++unlock: ++ pthread_mutex_unlock(&pl_inode->mutex); ++ ++done: ++ *ppl_inode = pl_inode; ++ ++ return error; ++} ++ ++int32_t ++pl_inode_remove_complete(xlator_t *xl, pl_inode_t *pl_inode, call_stub_t *stub, ++ struct list_head *contend) ++{ ++ pl_inode_lock_t *lock; ++ int32_t error = -1; ++ ++ if (stub != NULL) { ++ list_add_tail(&stub->list, &pl_inode->waiting); ++ pl_inode->is_locked = _gf_true; ++ } else { ++ error = ENOMEM; ++ ++ while (!list_empty(contend)) { ++ lock = list_first_entry(contend, pl_inode_lock_t, list); ++ list_del_init(&lock->list); ++ __pl_inodelk_unref(lock); ++ } ++ } ++ ++ pthread_mutex_unlock(&pl_inode->mutex); ++ ++ if (error < 0) { ++ inodelk_contention_notify(xl, contend); ++ } ++ ++ inode_unref(pl_inode->inode); ++ ++ return error; ++} ++ ++void ++pl_inode_remove_wake(struct list_head *list) ++{ ++ call_stub_t *stub; ++ ++ while (!list_empty(list)) { ++ stub = list_first_entry(list, call_stub_t, list); ++ list_del_init(&stub->list); ++ ++ call_resume(stub); ++ } ++} ++ ++void ++pl_inode_remove_cbk(xlator_t *xl, pl_inode_t *pl_inode, int32_t error) ++{ ++ struct list_head contend, granted; ++ struct timespec now; ++ pl_dom_list_t *dom; ++ ++ if (pl_inode == NULL) { ++ return; ++ } ++ ++ INIT_LIST_HEAD(&contend); ++ INIT_LIST_HEAD(&granted); ++ timespec_now(&now); ++ ++ pthread_mutex_lock(&pl_inode->mutex); ++ ++ if (error == 0) { ++ if (pl_inode->links >= 0) { ++ pl_inode->links--; ++ } ++ if (pl_inode->links == 0) { ++ pl_inode->removed = _gf_true; ++ } ++ } ++ ++ pl_inode->remove_running--; ++ ++ if ((pl_inode->remove_running == 0) && list_empty(&pl_inode->waiting)) { ++ pl_inode->is_locked = _gf_false; ++ ++ list_for_each_entry(dom, &pl_inode->dom_list, inode_list) ++ { ++ __grant_blocked_inode_locks(xl, pl_inode, &granted, dom, &now, ++ &contend); ++ } ++ } ++ ++ pthread_mutex_unlock(&pl_inode->mutex); ++ ++ unwind_granted_inodes(xl, pl_inode, &granted); ++ ++ inodelk_contention_notify(xl, &contend); ++ ++ inode_unref(pl_inode->inode); ++} ++ ++void ++pl_inode_remove_unlocked(xlator_t *xl, pl_inode_t *pl_inode, ++ struct list_head *list) ++{ ++ call_stub_t *stub, *tmp; ++ ++ if (!pl_inode->is_locked) { ++ return; ++ } ++ ++ list_for_each_entry_safe(stub, tmp, &pl_inode->waiting, list) ++ { ++ if (!pl_inode_has_owners(xl, stub->frame->root->client, pl_inode, NULL, ++ NULL)) { ++ list_move_tail(&stub->list, list); ++ } ++ } ++} ++ ++/* This function determines if an inodelk attempt can be done now or it needs ++ * to wait. ++ * ++ * Possible return values: ++ * < 0: An error occurred. Currently only -ESTALE can be returned if the ++ * inode has been deleted previously by unlink/rmdir/rename ++ * = 0: The lock can be attempted. ++ * > 0: The lock needs to wait because a conflicting remove operation is ++ * ongoing. ++ */ ++int32_t ++pl_inode_remove_inodelk(pl_inode_t *pl_inode, pl_inode_lock_t *lock) ++{ ++ pl_dom_list_t *dom; ++ pl_inode_lock_t *ilock; ++ ++ /* If the inode has been deleted, we won't allow any lock. */ ++ if (pl_inode->removed) { ++ return -ESTALE; ++ } ++ ++ /* We only synchronize with locks made for regular operations coming from ++ * the user. Locks done for internal purposes are hard to control and could ++ * lead to long delays or deadlocks quite easily. */ ++ if (lock->client_pid < 0) { ++ return 0; ++ } ++ if (!pl_inode->is_locked) { ++ return 0; ++ } ++ if (pl_inode->remove_running > 0) { ++ return 1; ++ } ++ ++ list_for_each_entry(dom, &pl_inode->dom_list, inode_list) ++ { ++ list_for_each_entry(ilock, &dom->inodelk_list, list) ++ { ++ /* If a lock from the same client is already granted, we allow this ++ * one to continue. This is necessary to prevent deadlocks when ++ * multiple locks are taken for the same operation. ++ * ++ * On the other side it's unlikely that the same client sends ++ * completely unrelated locks for the same inode. ++ */ ++ if (ilock->client == lock->client) { ++ return 0; ++ } ++ } ++ } ++ ++ return 1; ++} +diff --git a/xlators/features/locks/src/common.h b/xlators/features/locks/src/common.h +index ea86b96..6c81ac3 100644 +--- a/xlators/features/locks/src/common.h ++++ b/xlators/features/locks/src/common.h +@@ -105,6 +105,15 @@ void + __pl_inodelk_unref(pl_inode_lock_t *lock); + + void ++__grant_blocked_inode_locks(xlator_t *this, pl_inode_t *pl_inode, ++ struct list_head *granted, pl_dom_list_t *dom, ++ struct timespec *now, struct list_head *contend); ++ ++void ++unwind_granted_inodes(xlator_t *this, pl_inode_t *pl_inode, ++ struct list_head *granted); ++ ++void + grant_blocked_entry_locks(xlator_t *this, pl_inode_t *pl_inode, + pl_dom_list_t *dom, struct timespec *now, + struct list_head *contend); +@@ -204,6 +213,16 @@ pl_metalock_is_active(pl_inode_t *pl_inode); + void + __pl_queue_lock(pl_inode_t *pl_inode, posix_lock_t *reqlock); + ++void ++inodelk_contention_notify_check(xlator_t *xl, pl_inode_lock_t *lock, ++ struct timespec *now, ++ struct list_head *contend); ++ ++void ++entrylk_contention_notify_check(xlator_t *xl, pl_entry_lock_t *lock, ++ struct timespec *now, ++ struct list_head *contend); ++ + gf_boolean_t + pl_does_monkey_want_stuck_lock(); + +@@ -216,4 +235,28 @@ pl_clean_local(pl_local_t *local); + int + pl_local_init(call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd); + ++gf_boolean_t ++pl_is_lk_owner_valid(gf_lkowner_t *owner, client_t *client); ++ ++int32_t ++pl_inode_remove_prepare(xlator_t *xl, call_frame_t *frame, loc_t *loc, ++ pl_inode_t **ppl_inode, struct list_head *contend); ++ ++int32_t ++pl_inode_remove_complete(xlator_t *xl, pl_inode_t *pl_inode, call_stub_t *stub, ++ struct list_head *contend); ++ ++void ++pl_inode_remove_wake(struct list_head *list); ++ ++void ++pl_inode_remove_cbk(xlator_t *xl, pl_inode_t *pl_inode, int32_t error); ++ ++void ++pl_inode_remove_unlocked(xlator_t *xl, pl_inode_t *pl_inode, ++ struct list_head *list); ++ ++int32_t ++pl_inode_remove_inodelk(pl_inode_t *pl_inode, pl_inode_lock_t *lock); ++ + #endif /* __COMMON_H__ */ +diff --git a/xlators/features/locks/src/entrylk.c b/xlators/features/locks/src/entrylk.c +index 93c649c..b97836f 100644 +--- a/xlators/features/locks/src/entrylk.c ++++ b/xlators/features/locks/src/entrylk.c +@@ -197,9 +197,9 @@ out: + return revoke_lock; + } + +-static gf_boolean_t +-__entrylk_needs_contention_notify(xlator_t *this, pl_entry_lock_t *lock, +- struct timespec *now) ++void ++entrylk_contention_notify_check(xlator_t *this, pl_entry_lock_t *lock, ++ struct timespec *now, struct list_head *contend) + { + posix_locks_private_t *priv; + int64_t elapsed; +@@ -209,7 +209,7 @@ __entrylk_needs_contention_notify(xlator_t *this, pl_entry_lock_t *lock, + /* If this lock is in a list, it means that we are about to send a + * notification for it, so no need to do anything else. */ + if (!list_empty(&lock->contend)) { +- return _gf_false; ++ return; + } + + elapsed = now->tv_sec; +@@ -218,7 +218,7 @@ __entrylk_needs_contention_notify(xlator_t *this, pl_entry_lock_t *lock, + elapsed--; + } + if (elapsed < priv->notify_contention_delay) { +- return _gf_false; ++ return; + } + + /* All contention notifications will be sent outside of the locked +@@ -231,7 +231,7 @@ __entrylk_needs_contention_notify(xlator_t *this, pl_entry_lock_t *lock, + + lock->contention_time = *now; + +- return _gf_true; ++ list_add_tail(&lock->contend, contend); + } + + void +@@ -325,9 +325,7 @@ __entrylk_grantable(xlator_t *this, pl_dom_list_t *dom, pl_entry_lock_t *lock, + break; + } + } +- if (__entrylk_needs_contention_notify(this, tmp, now)) { +- list_add_tail(&tmp->contend, contend); +- } ++ entrylk_contention_notify_check(this, tmp, now, contend); + } + } + +@@ -690,10 +688,9 @@ __grant_blocked_entry_locks(xlator_t *this, pl_inode_t *pl_inode, + bl_ret = __lock_entrylk(bl->this, pl_inode, bl, 0, dom, now, contend); + + if (bl_ret == 0) { +- list_add(&bl->blocked_locks, granted); ++ list_add_tail(&bl->blocked_locks, granted); + } + } +- return; + } + + /* Grants locks if possible which are blocked on a lock */ +diff --git a/xlators/features/locks/src/inodelk.c b/xlators/features/locks/src/inodelk.c +index 24dee49..1a07243 100644 +--- a/xlators/features/locks/src/inodelk.c ++++ b/xlators/features/locks/src/inodelk.c +@@ -231,9 +231,9 @@ out: + return revoke_lock; + } + +-static gf_boolean_t +-__inodelk_needs_contention_notify(xlator_t *this, pl_inode_lock_t *lock, +- struct timespec *now) ++void ++inodelk_contention_notify_check(xlator_t *this, pl_inode_lock_t *lock, ++ struct timespec *now, struct list_head *contend) + { + posix_locks_private_t *priv; + int64_t elapsed; +@@ -243,7 +243,7 @@ __inodelk_needs_contention_notify(xlator_t *this, pl_inode_lock_t *lock, + /* If this lock is in a list, it means that we are about to send a + * notification for it, so no need to do anything else. */ + if (!list_empty(&lock->contend)) { +- return _gf_false; ++ return; + } + + elapsed = now->tv_sec; +@@ -252,7 +252,7 @@ __inodelk_needs_contention_notify(xlator_t *this, pl_inode_lock_t *lock, + elapsed--; + } + if (elapsed < priv->notify_contention_delay) { +- return _gf_false; ++ return; + } + + /* All contention notifications will be sent outside of the locked +@@ -265,7 +265,7 @@ __inodelk_needs_contention_notify(xlator_t *this, pl_inode_lock_t *lock, + + lock->contention_time = *now; + +- return _gf_true; ++ list_add_tail(&lock->contend, contend); + } + + void +@@ -353,9 +353,7 @@ __inodelk_grantable(xlator_t *this, pl_dom_list_t *dom, pl_inode_lock_t *lock, + break; + } + } +- if (__inodelk_needs_contention_notify(this, l, now)) { +- list_add_tail(&l->contend, contend); +- } ++ inodelk_contention_notify_check(this, l, now, contend); + } + } + +@@ -435,12 +433,17 @@ __lock_inodelk(xlator_t *this, pl_inode_t *pl_inode, pl_inode_lock_t *lock, + struct list_head *contend) + { + pl_inode_lock_t *conf = NULL; +- int ret = -EINVAL; ++ int ret; + +- conf = __inodelk_grantable(this, dom, lock, now, contend); +- if (conf) { +- ret = __lock_blocked_add(this, dom, lock, can_block); +- goto out; ++ ret = pl_inode_remove_inodelk(pl_inode, lock); ++ if (ret < 0) { ++ return ret; ++ } ++ if (ret == 0) { ++ conf = __inodelk_grantable(this, dom, lock, now, contend); ++ } ++ if ((ret > 0) || (conf != NULL)) { ++ return __lock_blocked_add(this, dom, lock, can_block); + } + + /* To prevent blocked locks starvation, check if there are any blocked +@@ -462,17 +465,13 @@ __lock_inodelk(xlator_t *this, pl_inode_t *pl_inode, pl_inode_lock_t *lock, + "starvation"); + } + +- ret = __lock_blocked_add(this, dom, lock, can_block); +- goto out; ++ return __lock_blocked_add(this, dom, lock, can_block); + } + __pl_inodelk_ref(lock); + gettimeofday(&lock->granted_time, NULL); + list_add(&lock->list, &dom->inodelk_list); + +- ret = 0; +- +-out: +- return ret; ++ return 0; + } + + /* Return true if the two inodelks have exactly same lock boundaries */ +@@ -529,12 +528,11 @@ out: + return conf; + } + +-static void ++void + __grant_blocked_inode_locks(xlator_t *this, pl_inode_t *pl_inode, + struct list_head *granted, pl_dom_list_t *dom, + struct timespec *now, struct list_head *contend) + { +- int bl_ret = 0; + pl_inode_lock_t *bl = NULL; + pl_inode_lock_t *tmp = NULL; + +@@ -547,52 +545,48 @@ __grant_blocked_inode_locks(xlator_t *this, pl_inode_t *pl_inode, + { + list_del_init(&bl->blocked_locks); + +- bl_ret = __lock_inodelk(this, pl_inode, bl, 1, dom, now, contend); ++ bl->status = __lock_inodelk(this, pl_inode, bl, 1, dom, now, contend); + +- if (bl_ret == 0) { +- list_add(&bl->blocked_locks, granted); ++ if (bl->status != -EAGAIN) { ++ list_add_tail(&bl->blocked_locks, granted); + } + } +- return; + } + +-/* Grant all inodelks blocked on a lock */ + void +-grant_blocked_inode_locks(xlator_t *this, pl_inode_t *pl_inode, +- pl_dom_list_t *dom, struct timespec *now, +- struct list_head *contend) ++unwind_granted_inodes(xlator_t *this, pl_inode_t *pl_inode, ++ struct list_head *granted) + { +- struct list_head granted; + pl_inode_lock_t *lock; + pl_inode_lock_t *tmp; ++ int32_t op_ret; ++ int32_t op_errno; + +- INIT_LIST_HEAD(&granted); +- +- pthread_mutex_lock(&pl_inode->mutex); +- { +- __grant_blocked_inode_locks(this, pl_inode, &granted, dom, now, +- contend); +- } +- pthread_mutex_unlock(&pl_inode->mutex); +- +- list_for_each_entry_safe(lock, tmp, &granted, blocked_locks) ++ list_for_each_entry_safe(lock, tmp, granted, blocked_locks) + { +- gf_log(this->name, GF_LOG_TRACE, +- "%s (pid=%d) (lk-owner=%s) %" PRId64 " - %" PRId64 " => Granted", +- lock->fl_type == F_UNLCK ? "Unlock" : "Lock", lock->client_pid, +- lkowner_utoa(&lock->owner), lock->user_flock.l_start, +- lock->user_flock.l_len); +- ++ if (lock->status == 0) { ++ op_ret = 0; ++ op_errno = 0; ++ gf_log(this->name, GF_LOG_TRACE, ++ "%s (pid=%d) (lk-owner=%s) %" PRId64 " - %" PRId64 ++ " => Granted", ++ lock->fl_type == F_UNLCK ? "Unlock" : "Lock", ++ lock->client_pid, lkowner_utoa(&lock->owner), ++ lock->user_flock.l_start, lock->user_flock.l_len); ++ } else { ++ op_ret = -1; ++ op_errno = -lock->status; ++ } + pl_trace_out(this, lock->frame, NULL, NULL, F_SETLKW, &lock->user_flock, +- 0, 0, lock->volume); ++ op_ret, op_errno, lock->volume); + +- STACK_UNWIND_STRICT(inodelk, lock->frame, 0, 0, NULL); ++ STACK_UNWIND_STRICT(inodelk, lock->frame, op_ret, op_errno, NULL); + lock->frame = NULL; + } + + pthread_mutex_lock(&pl_inode->mutex); + { +- list_for_each_entry_safe(lock, tmp, &granted, blocked_locks) ++ list_for_each_entry_safe(lock, tmp, granted, blocked_locks) + { + list_del_init(&lock->blocked_locks); + __pl_inodelk_unref(lock); +@@ -601,6 +595,26 @@ grant_blocked_inode_locks(xlator_t *this, pl_inode_t *pl_inode, + pthread_mutex_unlock(&pl_inode->mutex); + } + ++/* Grant all inodelks blocked on a lock */ ++void ++grant_blocked_inode_locks(xlator_t *this, pl_inode_t *pl_inode, ++ pl_dom_list_t *dom, struct timespec *now, ++ struct list_head *contend) ++{ ++ struct list_head granted; ++ ++ INIT_LIST_HEAD(&granted); ++ ++ pthread_mutex_lock(&pl_inode->mutex); ++ { ++ __grant_blocked_inode_locks(this, pl_inode, &granted, dom, now, ++ contend); ++ } ++ pthread_mutex_unlock(&pl_inode->mutex); ++ ++ unwind_granted_inodes(this, pl_inode, &granted); ++} ++ + static void + pl_inodelk_log_cleanup(pl_inode_lock_t *lock) + { +@@ -662,7 +676,7 @@ pl_inodelk_client_cleanup(xlator_t *this, pl_ctx_t *ctx) + * and blocked lists, then this means that a parallel + * unlock on another inodelk (L2 say) may have 'granted' + * L1 and added it to 'granted' list in +- * __grant_blocked_node_locks() (although using the ++ * __grant_blocked_inode_locks() (although using the + * 'blocked_locks' member). In that case, the cleanup + * codepath must try and grant other overlapping + * blocked inodelks from other clients, now that L1 is +@@ -747,6 +761,7 @@ pl_inode_setlk(xlator_t *this, pl_ctx_t *ctx, pl_inode_t *pl_inode, + gf_boolean_t need_inode_unref = _gf_false; + struct list_head *pcontend = NULL; + struct list_head contend; ++ struct list_head wake; + struct timespec now = {}; + short fl_type; + +@@ -798,6 +813,8 @@ pl_inode_setlk(xlator_t *this, pl_ctx_t *ctx, pl_inode_t *pl_inode, + timespec_now(&now); + } + ++ INIT_LIST_HEAD(&wake); ++ + if (ctx) + pthread_mutex_lock(&ctx->lock); + pthread_mutex_lock(&pl_inode->mutex); +@@ -820,18 +837,17 @@ pl_inode_setlk(xlator_t *this, pl_ctx_t *ctx, pl_inode_t *pl_inode, + lock->fl_type == F_UNLCK ? "Unlock" : "Lock", + lock->client_pid, lkowner_utoa(&lock->owner), + lock->user_flock.l_start, lock->user_flock.l_len); +- if (can_block) ++ if (can_block) { + unref = _gf_false; +- /* For all but the case where a non-blocking +- * lock attempt fails, the extra ref taken at +- * the start of this function must be negated. +- */ +- else +- need_inode_unref = _gf_true; ++ } + } +- +- if (ctx && (!ret || can_block)) ++ /* For all but the case where a non-blocking lock attempt fails ++ * with -EAGAIN, the extra ref taken at the start of this function ++ * must be negated. */ ++ need_inode_unref = (ret != 0) && ((ret != -EAGAIN) || !can_block); ++ if (ctx && !need_inode_unref) { + list_add_tail(&lock->client_list, &ctx->inodelk_lockers); ++ } + } else { + /* Irrespective of whether unlock succeeds or not, + * the extra inode ref that was done at the start of +@@ -849,6 +865,8 @@ pl_inode_setlk(xlator_t *this, pl_ctx_t *ctx, pl_inode_t *pl_inode, + list_del_init(&retlock->client_list); + __pl_inodelk_unref(retlock); + ++ pl_inode_remove_unlocked(this, pl_inode, &wake); ++ + ret = 0; + } + out: +@@ -859,6 +877,8 @@ pl_inode_setlk(xlator_t *this, pl_ctx_t *ctx, pl_inode_t *pl_inode, + if (ctx) + pthread_mutex_unlock(&ctx->lock); + ++ pl_inode_remove_wake(&wake); ++ + /* The following (extra) unref corresponds to the ref that + * was done at the time the lock was granted. + */ +@@ -1033,10 +1053,14 @@ pl_common_inodelk(call_frame_t *frame, xlator_t *this, const char *volume, + inode); + + if (ret < 0) { +- if ((can_block) && (F_UNLCK != lock_type)) { +- goto out; ++ if (ret == -EAGAIN) { ++ if (can_block && (F_UNLCK != lock_type)) { ++ goto out; ++ } ++ gf_log(this->name, GF_LOG_TRACE, "returning EAGAIN"); ++ } else { ++ gf_log(this->name, GF_LOG_TRACE, "returning %d", ret); + } +- gf_log(this->name, GF_LOG_TRACE, "returning EAGAIN"); + op_errno = -ret; + goto unwind; + } +diff --git a/xlators/features/locks/src/locks.h b/xlators/features/locks/src/locks.h +index aa267de..6666feb 100644 +--- a/xlators/features/locks/src/locks.h ++++ b/xlators/features/locks/src/locks.h +@@ -102,6 +102,9 @@ struct __pl_inode_lock { + + struct list_head client_list; /* list of all locks from a client */ + short fl_type; ++ ++ int32_t status; /* Error code when we try to grant a lock in blocked ++ state */ + }; + typedef struct __pl_inode_lock pl_inode_lock_t; + +@@ -164,13 +167,14 @@ struct __pl_inode { + struct list_head rw_list; /* list of waiting r/w requests */ + struct list_head reservelk_list; /* list of reservelks */ + struct list_head blocked_reservelks; /* list of blocked reservelks */ +- struct list_head +- blocked_calls; /* List of blocked lock calls while a reserve is held*/ +- struct list_head metalk_list; /* Meta lock list */ +- /* This is to store the incoming lock +- requests while meta lock is enabled */ +- struct list_head queued_locks; +- int mandatory; /* if mandatory locking is enabled */ ++ struct list_head blocked_calls; /* List of blocked lock calls while a ++ reserve is held*/ ++ struct list_head metalk_list; /* Meta lock list */ ++ struct list_head queued_locks; /* This is to store the incoming lock ++ requests while meta lock is enabled */ ++ struct list_head waiting; /* List of pending fops waiting to unlink/rmdir ++ the inode. */ ++ int mandatory; /* if mandatory locking is enabled */ + + inode_t *refkeeper; /* hold refs on an inode while locks are + held to prevent pruning */ +@@ -197,6 +201,11 @@ struct __pl_inode { + */ + int fop_wind_count; + pthread_cond_t check_fop_wind_count; ++ ++ int32_t links; /* Number of hard links the inode has. */ ++ uint32_t remove_running; /* Number of remove operations running. */ ++ gf_boolean_t is_locked; /* Regular locks will be blocked. */ ++ gf_boolean_t removed; /* The inode has been deleted. */ + }; + typedef struct __pl_inode pl_inode_t; + +diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c +index 7887b82..5ae0125 100644 +--- a/xlators/features/locks/src/posix.c ++++ b/xlators/features/locks/src/posix.c +@@ -147,6 +147,29 @@ fetch_pathinfo(xlator_t *, inode_t *, int32_t *, char **); + } \ + } while (0) + ++#define PL_INODE_REMOVE(_fop, _frame, _xl, _loc1, _loc2, _cont, _cbk, \ ++ _args...) \ ++ ({ \ ++ struct list_head contend; \ ++ pl_inode_t *__pl_inode; \ ++ call_stub_t *__stub; \ ++ int32_t __error; \ ++ INIT_LIST_HEAD(&contend); \ ++ __error = pl_inode_remove_prepare(_xl, _frame, _loc2 ? _loc2 : _loc1, \ ++ &__pl_inode, &contend); \ ++ if (__error < 0) { \ ++ __stub = fop_##_fop##_stub(_frame, _cont, ##_args); \ ++ __error = pl_inode_remove_complete(_xl, __pl_inode, __stub, \ ++ &contend); \ ++ } else if (__error == 0) { \ ++ PL_LOCAL_GET_REQUESTS(_frame, _xl, xdata, ((fd_t *)NULL), _loc1, \ ++ _loc2); \ ++ STACK_WIND_COOKIE(_frame, _cbk, __pl_inode, FIRST_CHILD(_xl), \ ++ FIRST_CHILD(_xl)->fops->_fop, ##_args); \ ++ } \ ++ __error; \ ++ }) ++ + gf_boolean_t + pl_has_xdata_requests(dict_t *xdata) + { +@@ -2969,11 +2992,85 @@ out: + return ret; + } + ++static int32_t ++pl_request_link_count(dict_t **pxdata) ++{ ++ dict_t *xdata; ++ ++ xdata = *pxdata; ++ if (xdata == NULL) { ++ xdata = dict_new(); ++ if (xdata == NULL) { ++ return ENOMEM; ++ } ++ } else { ++ dict_ref(xdata); ++ } ++ ++ if (dict_set_uint32(xdata, GET_LINK_COUNT, 0) != 0) { ++ dict_unref(xdata); ++ return ENOMEM; ++ } ++ ++ *pxdata = xdata; ++ ++ return 0; ++} ++ ++static int32_t ++pl_check_link_count(dict_t *xdata) ++{ ++ int32_t count; ++ ++ /* In case we are unable to read the link count from xdata, we take a ++ * conservative approach and return -2, which will prevent the inode from ++ * being considered deleted. In fact it will cause link tracking for this ++ * inode to be disabled completely to avoid races. */ ++ ++ if (xdata == NULL) { ++ return -2; ++ } ++ ++ if (dict_get_int32(xdata, GET_LINK_COUNT, &count) != 0) { ++ return -2; ++ } ++ ++ return count; ++} ++ + int32_t + pl_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, dict_t *xdata, + struct iatt *postparent) + { ++ pl_inode_t *pl_inode; ++ ++ if (op_ret >= 0) { ++ pl_inode = pl_inode_get(this, inode, NULL); ++ if (pl_inode == NULL) { ++ PL_STACK_UNWIND(lookup, xdata, frame, -1, ENOMEM, NULL, NULL, NULL, ++ NULL); ++ return 0; ++ } ++ ++ pthread_mutex_lock(&pl_inode->mutex); ++ ++ /* We only update the link count if we previously didn't know it. ++ * Doing it always can lead to races since lookup is not executed ++ * atomically most of the times. */ ++ if (pl_inode->links == -2) { ++ pl_inode->links = pl_check_link_count(xdata); ++ if (buf->ia_type == IA_IFDIR) { ++ /* Directories have at least 2 links. To avoid special handling ++ * for directories, we simply decrement the value here to make ++ * them equivalent to regular files. */ ++ pl_inode->links--; ++ } ++ } ++ ++ pthread_mutex_unlock(&pl_inode->mutex); ++ } ++ + PL_STACK_UNWIND(lookup, xdata, frame, op_ret, op_errno, inode, buf, xdata, + postparent); + return 0; +@@ -2982,9 +3079,17 @@ pl_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t + pl_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) + { +- PL_LOCAL_GET_REQUESTS(frame, this, xdata, ((fd_t *)NULL), loc, NULL); +- STACK_WIND(frame, pl_lookup_cbk, FIRST_CHILD(this), +- FIRST_CHILD(this)->fops->lookup, loc, xdata); ++ int32_t error; ++ ++ error = pl_request_link_count(&xdata); ++ if (error == 0) { ++ PL_LOCAL_GET_REQUESTS(frame, this, xdata, ((fd_t *)NULL), loc, NULL); ++ STACK_WIND(frame, pl_lookup_cbk, FIRST_CHILD(this), ++ FIRST_CHILD(this)->fops->lookup, loc, xdata); ++ dict_unref(xdata); ++ } else { ++ STACK_UNWIND_STRICT(lookup, frame, -1, error, NULL, NULL, NULL, NULL); ++ } + return 0; + } + +@@ -3792,6 +3897,10 @@ unlock: + gf_proc_dump_write("posixlk-count", "%d", count); + __dump_posixlks(pl_inode); + } ++ ++ gf_proc_dump_write("links", "%d", pl_inode->links); ++ gf_proc_dump_write("removes_pending", "%u", pl_inode->remove_running); ++ gf_proc_dump_write("removed", "%u", pl_inode->removed); + } + pthread_mutex_unlock(&pl_inode->mutex); + +@@ -4137,8 +4246,11 @@ pl_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + struct iatt *postoldparent, struct iatt *prenewparent, + struct iatt *postnewparent, dict_t *xdata) + { ++ pl_inode_remove_cbk(this, cookie, op_ret < 0 ? op_errno : 0); ++ + PL_STACK_UNWIND(rename, xdata, frame, op_ret, op_errno, buf, preoldparent, + postoldparent, prenewparent, postnewparent, xdata); ++ + return 0; + } + +@@ -4146,10 +4258,15 @@ int32_t + pl_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) + { +- PL_LOCAL_GET_REQUESTS(frame, this, xdata, ((fd_t *)NULL), oldloc, newloc); ++ int32_t error; ++ ++ error = PL_INODE_REMOVE(rename, frame, this, oldloc, newloc, pl_rename, ++ pl_rename_cbk, oldloc, newloc, xdata); ++ if (error > 0) { ++ STACK_UNWIND_STRICT(rename, frame, -1, error, NULL, NULL, NULL, NULL, ++ NULL, NULL); ++ } + +- STACK_WIND(frame, pl_rename_cbk, FIRST_CHILD(this), +- FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata); + return 0; + } + +@@ -4273,8 +4390,11 @@ pl_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) + { ++ pl_inode_remove_cbk(this, cookie, op_ret < 0 ? op_errno : 0); ++ + PL_STACK_UNWIND(unlink, xdata, frame, op_ret, op_errno, preparent, + postparent, xdata); ++ + return 0; + } + +@@ -4282,9 +4402,14 @@ int32_t + pl_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata) + { +- PL_LOCAL_GET_REQUESTS(frame, this, xdata, ((fd_t *)NULL), loc, NULL); +- STACK_WIND(frame, pl_unlink_cbk, FIRST_CHILD(this), +- FIRST_CHILD(this)->fops->unlink, loc, xflag, xdata); ++ int32_t error; ++ ++ error = PL_INODE_REMOVE(unlink, frame, this, loc, NULL, pl_unlink, ++ pl_unlink_cbk, loc, xflag, xdata); ++ if (error > 0) { ++ STACK_UNWIND_STRICT(unlink, frame, -1, error, NULL, NULL, NULL); ++ } ++ + return 0; + } + +@@ -4351,8 +4476,11 @@ pl_rmdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) + { ++ pl_inode_remove_cbk(this, cookie, op_ret < 0 ? op_errno : 0); ++ + PL_STACK_UNWIND_FOR_CLIENT(rmdir, xdata, frame, op_ret, op_errno, preparent, + postparent, xdata); ++ + return 0; + } + +@@ -4360,9 +4488,14 @@ int + pl_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, + dict_t *xdata) + { +- PL_LOCAL_GET_REQUESTS(frame, this, xdata, ((fd_t *)NULL), loc, NULL); +- STACK_WIND(frame, pl_rmdir_cbk, FIRST_CHILD(this), +- FIRST_CHILD(this)->fops->rmdir, loc, xflags, xdata); ++ int32_t error; ++ ++ error = PL_INODE_REMOVE(rmdir, frame, this, loc, NULL, pl_rmdir, ++ pl_rmdir_cbk, loc, xflags, xdata); ++ if (error > 0) { ++ STACK_UNWIND_STRICT(rmdir, frame, -1, error, NULL, NULL, NULL); ++ } ++ + return 0; + } + +@@ -4392,6 +4525,19 @@ pl_link_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, dict_t *xdata) + { ++ pl_inode_t *pl_inode = (pl_inode_t *)cookie; ++ ++ if (op_ret >= 0) { ++ pthread_mutex_lock(&pl_inode->mutex); ++ ++ /* TODO: can happen pl_inode->links == 0 ? */ ++ if (pl_inode->links >= 0) { ++ pl_inode->links++; ++ } ++ ++ pthread_mutex_unlock(&pl_inode->mutex); ++ } ++ + PL_STACK_UNWIND_FOR_CLIENT(link, xdata, frame, op_ret, op_errno, inode, buf, + preparent, postparent, xdata); + return 0; +@@ -4401,9 +4547,18 @@ int + pl_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) + { ++ pl_inode_t *pl_inode; ++ ++ pl_inode = pl_inode_get(this, oldloc->inode, NULL); ++ if (pl_inode == NULL) { ++ STACK_UNWIND_STRICT(link, frame, -1, ENOMEM, NULL, NULL, NULL, NULL, ++ NULL); ++ return 0; ++ } ++ + PL_LOCAL_GET_REQUESTS(frame, this, xdata, ((fd_t *)NULL), oldloc, newloc); +- STACK_WIND(frame, pl_link_cbk, FIRST_CHILD(this), +- FIRST_CHILD(this)->fops->link, oldloc, newloc, xdata); ++ STACK_WIND_COOKIE(frame, pl_link_cbk, pl_inode, FIRST_CHILD(this), ++ FIRST_CHILD(this)->fops->link, oldloc, newloc, xdata); + return 0; + } + +-- +1.8.3.1 + diff --git a/0456-add-clean-local-after-grant-lock.patch b/0456-add-clean-local-after-grant-lock.patch new file mode 100644 index 0000000..6b8210b --- /dev/null +++ b/0456-add-clean-local-after-grant-lock.patch @@ -0,0 +1,74 @@ +From c38b38249fdf951565f6501ce8e9a4d01142d43e Mon Sep 17 00:00:00 2001 +From: l17zhou +Date: Tue, 3 Dec 2019 07:43:35 +0200 +Subject: [PATCH 456/456] add clean local after grant lock + +found by flock test, without correct ref number of fd, +lock will not be correctly released. + +Upstream patch: +> Upstream patch link: https://review.gluster.org/c/glusterfs/+/23794 +> Fixes: bz#1779089 +> Change-Id: I3e466b17c852eb219c8778e43af8ad670a8449cc +> Signed-off-by: l17zhou + +BUG: 1854165 +Change-Id: I3e466b17c852eb219c8778e43af8ad670a8449cc +Signed-off-by: Xavi Hernandez +Reviewed-on: https://code.engineering.redhat.com/gerrit/206673 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + xlators/features/locks/src/common.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/xlators/features/locks/src/common.c b/xlators/features/locks/src/common.c +index 0c52853..cddbfa6 100644 +--- a/xlators/features/locks/src/common.c ++++ b/xlators/features/locks/src/common.c +@@ -961,7 +961,7 @@ grant_blocked_locks(xlator_t *this, pl_inode_t *pl_inode) + struct list_head granted_list; + posix_lock_t *tmp = NULL; + posix_lock_t *lock = NULL; +- ++ pl_local_t *local = NULL; + INIT_LIST_HEAD(&granted_list); + + pthread_mutex_lock(&pl_inode->mutex); +@@ -976,9 +976,9 @@ grant_blocked_locks(xlator_t *this, pl_inode_t *pl_inode) + + pl_trace_out(this, lock->frame, NULL, NULL, F_SETLKW, &lock->user_flock, + 0, 0, NULL); +- +- STACK_UNWIND_STRICT(lk, lock->frame, 0, 0, &lock->user_flock, NULL); +- ++ local = lock->frame->local; ++ PL_STACK_UNWIND_AND_FREE(local, lk, lock->frame, 0, 0, ++ &lock->user_flock, NULL); + __destroy_lock(lock); + } + +@@ -997,6 +997,7 @@ pl_send_prelock_unlock(xlator_t *this, pl_inode_t *pl_inode, + struct list_head granted_list; + posix_lock_t *tmp = NULL; + posix_lock_t *lock = NULL; ++ pl_local_t *local = NULL; + + int ret = -1; + +@@ -1024,9 +1025,9 @@ pl_send_prelock_unlock(xlator_t *this, pl_inode_t *pl_inode, + + pl_trace_out(this, lock->frame, NULL, NULL, F_SETLKW, &lock->user_flock, + 0, 0, NULL); +- +- STACK_UNWIND_STRICT(lk, lock->frame, 0, 0, &lock->user_flock, NULL); +- ++ local = lock->frame->local; ++ PL_STACK_UNWIND_AND_FREE(local, lk, lock->frame, 0, 0, ++ &lock->user_flock, NULL); + __destroy_lock(lock); + } + +-- +1.8.3.1 + diff --git a/glusterfs.spec b/glusterfs.spec index 02fc5f0..fef1771 100644 --- a/glusterfs.spec +++ b/glusterfs.spec @@ -237,7 +237,7 @@ Release: 0.1%{?prereltag:.%{prereltag}}%{?dist} %else Name: glusterfs Version: 6.0 -Release: 39%{?dist} +Release: 40%{?dist} ExcludeArch: i686 %endif License: GPLv2 or LGPLv3+ @@ -766,6 +766,11 @@ Patch0448: 0448-Posix-Use-simple-approach-to-close-fd.patch Patch0449: 0449-test-Test-case-brick-mux-validation-in-cluster.t-is-.patch Patch0450: 0450-tests-basic-ctime-enable-ctime-before-testing.patch Patch0451: 0451-extras-Modify-group-virt-to-include-network-related-.patch +Patch0452: 0452-Tier-DHT-Handle-the-pause-case-missed-out.patch +Patch0453: 0453-glusterd-add-brick-command-failure.patch +Patch0454: 0454-features-locks-avoid-use-after-freed-of-frame-for-bl.patch +Patch0455: 0455-locks-prevent-deletion-of-locked-entries.patch +Patch0456: 0456-add-clean-local-after-grant-lock.patch %description GlusterFS is a distributed file-system capable of scaling to several @@ -2506,6 +2511,9 @@ fi %endif %changelog +* Tue Jul 21 2020 Deepshikha Khandelwal - 6.0-40 +- fixes bugs bz#1812789 bz#1844359 bz#1847081 bz#1854165 + * Wed Jun 17 2020 Deepshikha Khandelwal - 6.0-39 - fixes bugs bz#1844359 bz#1845064