From 9dfd1f220c92bd484dd2102bf626eac39e799907 Mon Sep 17 00:00:00 2001 From: Rinku Kothiya Date: Fri, 7 Jun 2019 06:07:01 -0400 Subject: [PATCH] autobuild v6.0-4 Resolves: bz#1480907 bz#1702298 bz#1703455 bz#1704181 bz#1704562 Resolves: bz#1707246 bz#1708067 bz#1708116 bz#1708121 bz#1709087 Resolves: bz#1711249 bz#1711296 bz#1714078 bz#1714124 bz#1716385 Resolves: bz#1716626 bz#1716821 bz#1716865 bz#1717927 Signed-off-by: Rinku Kothiya --- ...-value-of-dict-to-avoid-log-flooding.patch | 36 + ...-the-dependency-on-nfs-ganesha-to-2..patch | 42 + ...-contention-notifications-for-partia.patch | 114 ++ ...cess-memory-usage-at-the-time-of-cal.patch | 65 + ...s-are-not-healed-in-case-of-add-bric.patch | 146 ++ ...dict-thread-is-not-handling-all-volu.patch | 80 + ...up-all-files-when-processing-directo.patch | 70 + ...e-code-to-copy-dictionary-in-handsha.patch | 452 ++++++ ...s-define-macros-needed-for-cloudsync.patch | 38 + ...ke-changes-related-to-cloudsync-xlat.patch | 156 ++ ...ix-changes-with-respect-to-cloudsync.patch | 403 +++++ ...s-cloudsync-Added-some-new-functions.patch | 1077 +++++++++++++ ...Cloudsync-plugin-for-commvault-store.patch | 1394 +++++++++++++++++ ...eaddirp-return-stat-info-of-all-the-.patch | 114 ++ ...dsync-Fix-bug-in-cloudsync-fops-c.py.patch | 94 ++ ...y-frame-after-afr_selfheal_entry_gra.patch | 68 + ...up-Protect-graph-object-under-a-lock.patch | 162 ++ 0159-glusterd-add-an-op-version-check.patch | 66 + 0160-geo-rep-Geo-rep-help-text-issue.patch | 41 + ...me-with-existing-destination-with-sa.patch | 289 ++++ 0162-geo-rep-Fix-sync-method-config.patch | 210 +++ 0163-geo-rep-Fix-sync-hang-with-tarssh.patch | 255 +++ ...andling-of-heal-info-cases-without-l.patch | 165 ++ ...ts-shd-Add-test-coverage-for-shd-mux.patch | 442 ++++++ ...sterd_svcs_stop-should-call-individu.patch | 92 ++ ...imize-the-glustershd-manager-to-send.patch | 64 + ...-Fix-directory-perms-during-selfheal.patch | 46 + ...ix-spec-to-enable-rhel8-client-build.patch | 62 + glusterfs.spec | 48 +- 29 files changed, 6283 insertions(+), 8 deletions(-) create mode 100644 0142-lock-check-null-value-of-dict-to-avoid-log-flooding.patch create mode 100644 0143-packaging-Change-the-dependency-on-nfs-ganesha-to-2..patch create mode 100644 0144-cluster-ec-honor-contention-notifications-for-partia.patch create mode 100644 0145-core-Capture-process-memory-usage-at-the-time-of-cal.patch create mode 100644 0146-dht-Custom-xattrs-are-not-healed-in-case-of-add-bric.patch create mode 100644 0147-glusterd-bulkvoldict-thread-is-not-handling-all-volu.patch create mode 100644 0148-cluster-dht-Lookup-all-files-when-processing-directo.patch create mode 100644 0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch create mode 100644 0150-libglusterfs-define-macros-needed-for-cloudsync.patch create mode 100644 0151-mgmt-glusterd-Make-changes-related-to-cloudsync-xlat.patch create mode 100644 0152-storage-posix-changes-with-respect-to-cloudsync.patch create mode 100644 0153-features-cloudsync-Added-some-new-functions.patch create mode 100644 0154-cloudsync-cvlt-Cloudsync-plugin-for-commvault-store.patch create mode 100644 0155-cloudsync-Make-readdirp-return-stat-info-of-all-the-.patch create mode 100644 0156-cloudsync-Fix-bug-in-cloudsync-fops-c.py.patch create mode 100644 0157-afr-frame-Destroy-frame-after-afr_selfheal_entry_gra.patch create mode 100644 0158-glusterfsd-cleanup-Protect-graph-object-under-a-lock.patch create mode 100644 0159-glusterd-add-an-op-version-check.patch create mode 100644 0160-geo-rep-Geo-rep-help-text-issue.patch create mode 100644 0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch create mode 100644 0162-geo-rep-Fix-sync-method-config.patch create mode 100644 0163-geo-rep-Fix-sync-hang-with-tarssh.patch create mode 100644 0164-cluster-ec-Fix-handling-of-heal-info-cases-without-l.patch create mode 100644 0165-tests-shd-Add-test-coverage-for-shd-mux.patch create mode 100644 0166-glusterd-svc-glusterd_svcs_stop-should-call-individu.patch create mode 100644 0167-glusterd-shd-Optimize-the-glustershd-manager-to-send.patch create mode 100644 0168-cluster-dht-Fix-directory-perms-during-selfheal.patch create mode 100644 0169-Build-Fix-spec-to-enable-rhel8-client-build.patch diff --git a/0142-lock-check-null-value-of-dict-to-avoid-log-flooding.patch b/0142-lock-check-null-value-of-dict-to-avoid-log-flooding.patch new file mode 100644 index 0000000..ec6ed8a --- /dev/null +++ b/0142-lock-check-null-value-of-dict-to-avoid-log-flooding.patch @@ -0,0 +1,36 @@ +From e44b75fdb86dcf759204816c873b4f9f4efbefa8 Mon Sep 17 00:00:00 2001 +From: Susant Palai +Date: Tue, 21 May 2019 16:17:09 +0530 +Subject: [PATCH 142/169] lock: check null value of dict to avoid log flooding + +> updates: bz#1712322 +> Change-Id: I120a1d23506f9ebcf88c7ea2f2eff4978a61cf4a +> Signed-off-by: Susant Palai +(backport of fix https://review.gluster.org/#/c/glusterfs/+/22756/) + +BUG: bz#1704181 +Change-Id: I2a192236328ebb39666ffef1146df312c08a377d +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/171325 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + xlators/features/locks/src/posix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c +index 3f1c7a7..adb0df5 100644 +--- a/xlators/features/locks/src/posix.c ++++ b/xlators/features/locks/src/posix.c +@@ -121,7 +121,7 @@ fetch_pathinfo(xlator_t *, inode_t *, int32_t *, char **); + + #define PL_CHECK_LOCK_ENFORCE_KEY(frame, dict, name, this, loc, fd, priv) \ + do { \ +- if (dict_get(dict, GF_ENFORCE_MANDATORY_LOCK) || \ ++ if ((dict && (dict_get(dict, GF_ENFORCE_MANDATORY_LOCK))) || \ + (name && (strcmp(name, GF_ENFORCE_MANDATORY_LOCK) == 0))) { \ + inode_t *__inode = (loc ? loc->inode : fd->inode); \ + pl_inode_t *__pl_inode = pl_inode_get(this, __inode, NULL); \ +-- +1.8.3.1 + diff --git a/0143-packaging-Change-the-dependency-on-nfs-ganesha-to-2..patch b/0143-packaging-Change-the-dependency-on-nfs-ganesha-to-2..patch new file mode 100644 index 0000000..fd25a69 --- /dev/null +++ b/0143-packaging-Change-the-dependency-on-nfs-ganesha-to-2..patch @@ -0,0 +1,42 @@ +From 43fb1d9d3890c44108b466d308177428fb8217aa Mon Sep 17 00:00:00 2001 +From: Jiffin Tony Thottan +Date: Mon, 27 May 2019 10:11:39 +0530 +Subject: [PATCH 143/169] packaging : Change the dependency on nfs-ganesha to + 2.7 for glusterfs-ganesha + +Change-Id: I16a3f32eddfcbf745d67de9dc7440e2fc6ef2315 +fixes: bz#1714078 +Signed-off-by: Jiffin Tony Thottan +Reviewed-on: https://code.engineering.redhat.com/gerrit/171471 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + glusterfs.spec.in | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/glusterfs.spec.in b/glusterfs.spec.in +index 86a1527..ed58356 100644 +--- a/glusterfs.spec.in ++++ b/glusterfs.spec.in +@@ -460,7 +460,7 @@ Summary: NFS-Ganesha configuration + Group: Applications/File + + Requires: %{name}-server%{?_isa} = %{version}-%{release} +-Requires: nfs-ganesha-gluster >= 2.4.1 ++Requires: nfs-ganesha-gluster >= 2.7.3 + Requires: pcs, dbus + %if ( 0%{?rhel} && 0%{?rhel} == 6 ) + Requires: cman, pacemaker, corosync +@@ -1933,6 +1933,9 @@ fi + %endif + + %changelog ++* Mon May 27 2019 Jiffin Tony Thottan ++- Change the dependency to 2.7.3 on nfs-ganesha for glusterfs-ganesha (#1714078) ++ + * Sun Apr 7 2019 Jiffin Tony Thottan + - DOWNSTREAM ONLY - revert of 83abcb(gnfs in an optional subpackage) + +-- +1.8.3.1 + diff --git a/0144-cluster-ec-honor-contention-notifications-for-partia.patch b/0144-cluster-ec-honor-contention-notifications-for-partia.patch new file mode 100644 index 0000000..40a6aa8 --- /dev/null +++ b/0144-cluster-ec-honor-contention-notifications-for-partia.patch @@ -0,0 +1,114 @@ +From ff8a74250209f4279f67dd89c3e57b2289a1b7d1 Mon Sep 17 00:00:00 2001 +From: Xavi Hernandez +Date: Thu, 9 May 2019 11:07:18 +0200 +Subject: [PATCH 144/169] cluster/ec: honor contention notifications for + partially acquired locks + +EC was ignoring lock contention notifications received while a lock was +being acquired. When a lock is partially acquired (some bricks have +granted the lock but some others not yet) we can receive notifications +from acquired bricks, which should be honored, since we may not receive +more notifications after that. + +Since EC was ignoring them, once the lock was acquired, it was not +released until the eager-lock timeout, causing unnecessary delays on +other clients. + +This fix takes into consideration the notifications received before +having completed the full lock acquisition. After that, the lock will +be releaed as soon as possible. + +Upstream patch: +> BUG: 1708156 +> Upstream patch link: https://review.gluster.org/c/glusterfs/+/22690 +> Change-Id: I2a306dbdb29fb557dcab7788a258bd75d826cc12 +> Signed-off-by: Xavi Hernandez + +Fixes: bz#1703455 +Change-Id: I2a306dbdb29fb557dcab7788a258bd75d826cc12 +Signed-off-by: Xavi Hernandez +Reviewed-on: https://code.engineering.redhat.com/gerrit/171525 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + ...or-inodelk-contention-notify-on-partial-locks.t | 54 ++++++++++++++++++++++ + xlators/cluster/ec/src/ec-common.c | 2 +- + 2 files changed, 55 insertions(+), 1 deletion(-) + create mode 100644 tests/bugs/ec/bug-1708156-honor-inodelk-contention-notify-on-partial-locks.t + +diff --git a/tests/bugs/ec/bug-1708156-honor-inodelk-contention-notify-on-partial-locks.t b/tests/bugs/ec/bug-1708156-honor-inodelk-contention-notify-on-partial-locks.t +new file mode 100644 +index 0000000..67fdb18 +--- /dev/null ++++ b/tests/bugs/ec/bug-1708156-honor-inodelk-contention-notify-on-partial-locks.t +@@ -0,0 +1,54 @@ ++#!/bin/bash ++ ++. $(dirname $0)/../../include.rc ++. $(dirname $0)/../../volume.rc ++ ++function do_ls() { ++ local dir="${1}" ++ local i ++ ++ for i in {1..50}; do ++ ls -l $M0/${dir} >/dev/null & ++ ls -l $M1/${dir} >/dev/null & ++ ls -l $M2/${dir} >/dev/null & ++ ls -l $M3/${dir} >/dev/null & ++ done ++ wait ++} ++ ++function measure_time() { ++ { ++ LC_ALL=C ++ time -p "${@}" ++ } 2>&1 | awk '/^real/ { print $2 * 1000 }' ++} ++ ++cleanup ++ ++TEST glusterd ++TEST pidof glusterd ++TEST $CLI volume create $V0 disperse 6 redundancy 2 $H0:$B0/${V0}{0..5} ++ ++TEST $CLI volume set $V0 disperse.eager-lock on ++TEST $CLI volume set $V0 disperse.other-eager-lock on ++TEST $CLI volume set $V0 features.locks-notify-contention on ++TEST $CLI volume set $V0 disperse.eager-lock-timeout 10 ++TEST $CLI volume set $V0 disperse.other-eager-lock-timeout 10 ++ ++TEST $CLI volume start $V0 ++TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0 ++TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M1 ++TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M2 ++TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M3 ++EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 $M0 ++EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 $M1 ++EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 $M2 ++EXPECT_WITHIN $CHILD_UP_TIMEOUT "6" ec_child_up_count $V0 0 $M3 ++TEST mkdir $M0/dir ++TEST touch $M0/dir/file.{1..10} ++ ++# Run multiple 'ls' concurrently from multiple clients so that they collide and ++# cause partial locks. ++TEST [[ $(measure_time do_ls dir) -lt 10000 ]] ++ ++cleanup +diff --git a/xlators/cluster/ec/src/ec-common.c b/xlators/cluster/ec/src/ec-common.c +index b1ba5e9..e85aa8b 100644 +--- a/xlators/cluster/ec/src/ec-common.c ++++ b/xlators/cluster/ec/src/ec-common.c +@@ -2497,7 +2497,7 @@ ec_lock_release(ec_t *ec, inode_t *inode) + goto done; + } + lock = ctx->inode_lock; +- if ((lock == NULL) || !lock->acquired || lock->release) { ++ if ((lock == NULL) || lock->release) { + goto done; + } + +-- +1.8.3.1 + diff --git a/0145-core-Capture-process-memory-usage-at-the-time-of-cal.patch b/0145-core-Capture-process-memory-usage-at-the-time-of-cal.patch new file mode 100644 index 0000000..398f460 --- /dev/null +++ b/0145-core-Capture-process-memory-usage-at-the-time-of-cal.patch @@ -0,0 +1,65 @@ +From 55d47524c0c8a88204129c3a94d71779aae00beb Mon Sep 17 00:00:00 2001 +From: Mohit Agrawal +Date: Tue, 28 May 2019 08:18:12 +0530 +Subject: [PATCH 145/169] core: Capture process memory usage at the time of + call gf_msg_nomem + +Problem: All gluster processes call gf_mgm_nomem while calloc/malloc/realloc + throw an error but the message does not capture current memory usage of + gluster process + +Solution: Call getrusage to capture current memory usage of gluster + process + +> Change-Id: I2e0319da1f33b177fa042fdc9e7268068576c9c3 +> fixes: bz#1708051 +> Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/22688/ +> Cherry pick from commit 8e1d53f14730ac1b1ca0ce9d9a0ccb32578fd4fb + +BUG: 1709087 +Change-Id: I2e0319da1f33b177fa042fdc9e7268068576c9c3 +Signed-off-by: Mohit Agrawal +Reviewed-on: https://code.engineering.redhat.com/gerrit/171587 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + libglusterfs/src/logging.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/libglusterfs/src/logging.c b/libglusterfs/src/logging.c +index 5d46916..7f0eff6 100644 +--- a/libglusterfs/src/logging.c ++++ b/libglusterfs/src/logging.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #ifdef HAVE_BACKTRACE + #include +@@ -1196,6 +1197,7 @@ _gf_msg_nomem(const char *domain, const char *file, const char *function, + glusterfs_ctx_t *ctx = NULL; + int wlen = 0; + int priority; ++ struct rusage r_usage; + + this = THIS; + ctx = this->ctx; +@@ -1231,10 +1233,11 @@ _gf_msg_nomem(const char *domain, const char *file, const char *function, + "]" + " [%s:%d:%s] %s: no memory " + "available for size (%" GF_PRI_SIZET +- ")" ++ ") current memory usage in kilobytes %ld" + " [call stack follows]\n", + timestr, gf_level_strings[level], (uint64_t)0, basename, +- line, function, domain, size); ++ line, function, domain, size, ++ (!getrusage(RUSAGE_SELF, &r_usage) ? r_usage.ru_maxrss : 0)); + if (-1 == ret) { + goto out; + } +-- +1.8.3.1 + diff --git a/0146-dht-Custom-xattrs-are-not-healed-in-case-of-add-bric.patch b/0146-dht-Custom-xattrs-are-not-healed-in-case-of-add-bric.patch new file mode 100644 index 0000000..50747cc --- /dev/null +++ b/0146-dht-Custom-xattrs-are-not-healed-in-case-of-add-bric.patch @@ -0,0 +1,146 @@ +From 8cc721ee43ac8038eecb712278378710ad0745ed Mon Sep 17 00:00:00 2001 +From: root +Date: Sun, 7 Apr 2019 19:31:17 +0530 +Subject: [PATCH 146/169] dht: Custom xattrs are not healed in case of + add-brick + +Problem: If any custom xattrs are set on the directory before + add a brick, xattrs are not healed on the directory + after adding a brick. + +Solution: xattr are not healed because dht_selfheal_dir_mkdir_lookup_cbk + checks the value of MDS and if MDS value is not negative + selfheal code path does not take reference of MDS xattrs.Change the + condition to take reference of MDS xattr so that custom xattrs are + populated on newly added brick + +> Updates: bz#1702299 +> Change-Id: Id14beedb98cce6928055f294e1594b22132e811c +> Signed-off-by: Mohit Agrawal +> (Cherry pick from commit aa52259de7b50625b754ce9fb5c0f38e22d79dd6) +> (Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/22520/) + +BUG: 1702298 +Change-Id: Id14beedb98cce6928055f294e1594b22132e811c +Signed-off-by: Mohit Agrawal +Reviewed-on: https://code.engineering.redhat.com/gerrit/171591 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + tests/bugs/bug-1702299.t | 67 ++++++++++++++++++++++++++++++++++ + xlators/cluster/dht/src/dht-selfheal.c | 9 +---- + 2 files changed, 68 insertions(+), 8 deletions(-) + create mode 100644 tests/bugs/bug-1702299.t + +diff --git a/tests/bugs/bug-1702299.t b/tests/bugs/bug-1702299.t +new file mode 100644 +index 0000000..1cff2ed +--- /dev/null ++++ b/tests/bugs/bug-1702299.t +@@ -0,0 +1,67 @@ ++#!/bin/bash ++. $(dirname $0)/../include.rc ++. $(dirname $0)/../volume.rc ++. $(dirname $0)/../dht.rc ++cleanup; ++ ++function get_getfattr { ++ local path=$1 ++ echo `getfattr -n user.foo $path` | cut -f2 -d"=" | sed -e 's/^"//' -e 's/"$//' ++} ++ ++function set_fattr { ++ for i in `seq 1 10` ++ do ++ setfattr -n user.foo -v "newabc" ./tmp${i} ++ if [ "$?" = "0" ] ++ then ++ succ=$((succ+1)) ++ else ++ fail=$((fail+1)) ++ fi ++ done ++} ++ ++ ++ ++TEST glusterd ++TEST pidof glusterd ++TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1,2,3} ++TEST $CLI volume start $V0 ++ ++TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 --attribute-timeout=0 $M0; ++ ++cd $M0 ++TEST mkdir tmp{1..10} ++ ++succ=fail=0 ++## set user.foo xattr with value newabc after kill one brick ++set_fattr ++count=10 ++EXPECT "$succ" echo $count ++count=0 ++EXPECT "$fail" echo $count ++ ++cd - ++ ++# Add-brick ++TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{4,5} ++ ++cd $M0 ++## At this point dht code will heal xattr on down brick only for those dirs ++## hashed subvol was up at the time of update xattr ++TEST stat ./tmp{1..10} ++ ++ ++## Count the user.foo xattr value with newabc on brick and compare with succ value ++count=`getfattr -n user.foo $B0/${V0}4/tmp{1..10} | grep "user.foo" | grep -iw "newabc" | wc -l` ++EXPECT "$succ" echo $count ++ ++## Count the user.foo xattr value with newabc on brick and compare with succ value ++count=`getfattr -n user.foo $B0/${V0}5/tmp{1..10} | grep "user.foo" | grep -iw "newabc" | wc -l` ++EXPECT "$succ" echo $count ++ ++ ++cd - ++TEST umount $M0 ++cleanup +diff --git a/xlators/cluster/dht/src/dht-selfheal.c b/xlators/cluster/dht/src/dht-selfheal.c +index 5420fca..f5dfff9 100644 +--- a/xlators/cluster/dht/src/dht-selfheal.c ++++ b/xlators/cluster/dht/src/dht-selfheal.c +@@ -1310,12 +1310,8 @@ dht_selfheal_dir_mkdir_lookup_cbk(call_frame_t *frame, void *cookie, + int this_call_cnt = 0; + int missing_dirs = 0; + dht_layout_t *layout = NULL; +- dht_conf_t *conf = 0; + xlator_t *prev = 0; + loc_t *loc = NULL; +- int check_mds = 0; +- int errst = 0; +- int32_t mds_xattr_val[1] = {0}; + char gfid_local[GF_UUID_BUF_SIZE] = {0}; + int index = -1; + +@@ -1324,7 +1320,6 @@ dht_selfheal_dir_mkdir_lookup_cbk(call_frame_t *frame, void *cookie, + local = frame->local; + layout = local->layout; + loc = &local->loc; +- conf = this->private; + prev = cookie; + + if (!gf_uuid_is_null(local->gfid)) +@@ -1347,9 +1342,7 @@ dht_selfheal_dir_mkdir_lookup_cbk(call_frame_t *frame, void *cookie, + + if (!op_ret) { + dht_iatt_merge(this, &local->stbuf, stbuf); +- check_mds = dht_dict_get_array(xattr, conf->mds_xattr_key, +- mds_xattr_val, 1, &errst); +- if (dict_get(xattr, conf->mds_xattr_key) && check_mds && !errst) { ++ if (prev == local->mds_subvol) { + dict_unref(local->xattr); + local->xattr = dict_ref(xattr); + } +-- +1.8.3.1 + diff --git a/0147-glusterd-bulkvoldict-thread-is-not-handling-all-volu.patch b/0147-glusterd-bulkvoldict-thread-is-not-handling-all-volu.patch new file mode 100644 index 0000000..27f8a4e --- /dev/null +++ b/0147-glusterd-bulkvoldict-thread-is-not-handling-all-volu.patch @@ -0,0 +1,80 @@ +From d7795a592883cfb01da76b6905a7c9eb1e912bef Mon Sep 17 00:00:00 2001 +From: Mohit Agrawal +Date: Tue, 28 May 2019 08:28:29 +0530 +Subject: [PATCH 147/169] glusterd: bulkvoldict thread is not handling all + volumes + +Problem: In commit ac70f66c5805e10b3a1072bd467918730c0aeeb4 I + missed one condition to populate volume dictionary in + multiple threads while brick_multiplex is enabled.Due + to that glusterd is not sending volume dictionary for + all volumes to peer. + +Solution: Update the condition in code as well as update test case + also to avoid the issue + +> Change-Id: I06522dbdfee4f7e995d9cc7b7098fdf35340dc52 +> fixes: bz#1711250 +> Cherry pick from commit 4a5fb52eb1c5387a0fb8bfa1253e5227c7c255e8 +> Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/22739/ + +BUG: 1711249 +Change-Id: I06522dbdfee4f7e995d9cc7b7098fdf35340dc52 +Signed-off-by: Mohit Agrawal +Reviewed-on: https://code.engineering.redhat.com/gerrit/171589 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + tests/bugs/glusterd/bug-1699339.t | 16 ++++++++++------ + xlators/mgmt/glusterd/src/glusterd-utils.c | 2 +- + 2 files changed, 11 insertions(+), 7 deletions(-) + +diff --git a/tests/bugs/glusterd/bug-1699339.t b/tests/bugs/glusterd/bug-1699339.t +index 3e950f4..bb8d4f4 100644 +--- a/tests/bugs/glusterd/bug-1699339.t ++++ b/tests/bugs/glusterd/bug-1699339.t +@@ -52,18 +52,22 @@ done + + TEST kill_glusterd 1 + +-vol1=$(printf "%s-vol%02d" $V0 1) ++TESTS_EXPECTED_IN_LOOP=4 ++for i in `seq 1 3 15` ++do ++vol1=$(printf "%s-vol%02d" $V0 $i) + TEST $CLI_2 volume set $vol1 performance.readdir-ahead on +-vol2=$(printf "%s-vol%02d" $V0 2) +-TEST $CLI_2 volume set $vol2 performance.readdir-ahead on ++done + + # Bring back 1st glusterd + TEST $glusterd_1 + EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count + ++TESTS_EXPECTED_IN_LOOP=4 ++for i in `seq 1 3 15` ++do ++vol1=$(printf "%s-vol%02d" $V0 $i) + EXPECT_WITHIN $PROBE_TIMEOUT "on" volinfo_field_1 $vol1 performance.readdir-ahead +- +-vol_name=$(printf "%s-vol%02d" $V0 2) +-EXPECT_WITHIN $PROBE_TIMEOUT "on" volinfo_field_1 $vol2 performance.readdir-ahead ++done + + cleanup +diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c +index efa5a86..8f1525e 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-utils.c ++++ b/xlators/mgmt/glusterd/src/glusterd-utils.c +@@ -3542,7 +3542,7 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data) + if ((i + 1) != totthread) { + arg->end = ((i + 1) * vol_per_thread_limit); + } else { +- arg->end = ((i * vol_per_thread_limit) + endindex); ++ arg->end = (((i + 1) * vol_per_thread_limit) + endindex); + } + th_ret = gf_thread_create_detached( + &th_id, glusterd_add_bulk_volumes_create_thread, arg, +-- +1.8.3.1 + diff --git a/0148-cluster-dht-Lookup-all-files-when-processing-directo.patch b/0148-cluster-dht-Lookup-all-files-when-processing-directo.patch new file mode 100644 index 0000000..b1a5651 --- /dev/null +++ b/0148-cluster-dht-Lookup-all-files-when-processing-directo.patch @@ -0,0 +1,70 @@ +From 92aadb6a5eeec75edf7f5a11a0ebd861dd85ca6b Mon Sep 17 00:00:00 2001 +From: N Balachandran +Date: Mon, 20 May 2019 15:23:42 +0530 +Subject: [PATCH 148/169] cluster/dht: Lookup all files when processing + directory + +A rebalance process currently only looks up files +that it is supposed to migrate. This could cause issues +when lookup-optimize is enabled as the dir layout can be +updated with the commit hash before all files are looked up. +This is expecially problematic if one of the rebalance processes +fails to complete as clients will try to access files whose +linkto files might not have been created. +Each process will now lookup every file in the directory it is +processing. +Pros: Less likely that files will be inaccessible. +Cons: More lookup requests sent to the bricks and a potential +performance hit. +Note: this does not handle races such as when a layout is updated on disk +just as the create fop is sent by the client. + +upstream : https://review.gluster.org/#/c/glusterfs/+/22746/ + +>Change-Id: I22b55846effc08d3b827c3af9335229335f67fb8 +>fixes: bz#1711764 + +BUG#1714124 + +Change-Id: Ica6a9459befe53957f080001a2dda525b3b14d1c +Signed-off-by: N Balachandran +Reviewed-on: https://code.engineering.redhat.com/gerrit/172080 +Tested-by: RHGS Build Bot +Reviewed-by: Mohit Agrawal +--- + xlators/cluster/dht/src/dht-rebalance.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/xlators/cluster/dht/src/dht-rebalance.c b/xlators/cluster/dht/src/dht-rebalance.c +index efbe8a4..559f046 100644 +--- a/xlators/cluster/dht/src/dht-rebalance.c ++++ b/xlators/cluster/dht/src/dht-rebalance.c +@@ -2741,12 +2741,6 @@ gf_defrag_migrate_single_file(void *opaque) + goto out; + } + +- if (!gf_defrag_should_i_migrate(this, rebal_entry->local_subvol_index, +- entry->d_stat.ia_gfid)) { +- gf_msg_debug(this->name, 0, "Don't migrate %s ", entry_loc.path); +- goto out; +- } +- + gf_uuid_copy(entry_loc.gfid, entry->d_stat.ia_gfid); + + gf_uuid_copy(entry_loc.pargfid, loc->gfid); +@@ -2772,6 +2766,12 @@ gf_defrag_migrate_single_file(void *opaque) + goto out; + } + ++ if (!gf_defrag_should_i_migrate(this, rebal_entry->local_subvol_index, ++ entry->d_stat.ia_gfid)) { ++ gf_msg_debug(this->name, 0, "Don't migrate %s ", entry_loc.path); ++ goto out; ++ } ++ + iatt_ptr = &iatt; + + hashed_subvol = dht_subvol_get_hashed(this, &entry_loc); +-- +1.8.3.1 + diff --git a/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch b/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch new file mode 100644 index 0000000..5caf3d4 --- /dev/null +++ b/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch @@ -0,0 +1,452 @@ +From 86eee7e829bb33cac9b611da511ecbd2f03fab25 Mon Sep 17 00:00:00 2001 +From: Mohit Agrawal +Date: Fri, 17 May 2019 19:26:48 +0530 +Subject: [PATCH 149/169] glusterd: Optimize code to copy dictionary in + handshake code path + +Problem: While high no. of volumes are configured around 2000 + glusterd has bottleneck during handshake at the time + of copying dictionary + +Solution: To avoid the bottleneck serialize a dictionary instead + of copying key-value pair one by one + +> Change-Id: I9fb332f432e4f915bc3af8dcab38bed26bda2b9a +> fixes: bz#1711297 +> Cherry picked from commit f8f09178bb890924a8050b466cc2e7a0a30e35a7 +> (Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/22742/) + +BUG: 1711296 +Change-Id: I9fb332f432e4f915bc3af8dcab38bed26bda2b9a +Signed-off-by: Mohit Agrawal +Reviewed-on: https://code.engineering.redhat.com/gerrit/172255 +Reviewed-by: Atin Mukherjee +Tested-by: RHGS Build Bot +--- + libglusterfs/src/dict.c | 6 +- + libglusterfs/src/glusterfs/dict.h | 6 + + libglusterfs/src/libglusterfs.sym | 1 + + xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 27 ++-- + xlators/mgmt/glusterd/src/glusterd-utils.c | 187 +++++++++++++++++++++++---- + xlators/mgmt/glusterd/src/glusterd-utils.h | 3 +- + xlators/mgmt/glusterd/src/glusterd.h | 5 + + 7 files changed, 194 insertions(+), 41 deletions(-) + +diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c +index 4cd1fcf..6917df9 100644 +--- a/libglusterfs/src/dict.c ++++ b/libglusterfs/src/dict.c +@@ -2799,10 +2799,6 @@ dict_rename_key(dict_t *this, char *key, char *replace_key) + * 4 4 4 + */ + +-#define DICT_HDR_LEN 4 +-#define DICT_DATA_HDR_KEY_LEN 4 +-#define DICT_DATA_HDR_VAL_LEN 4 +- + /** + * dict_serialized_length_lk - return the length of serialized dict. This + * procedure has to be called with this->lock held. +@@ -2812,7 +2808,7 @@ dict_rename_key(dict_t *this, char *key, char *replace_key) + * : failure: -errno + */ + +-static int ++int + dict_serialized_length_lk(dict_t *this) + { + int ret = -EINVAL; +diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h +index 52b833f..022f564 100644 +--- a/libglusterfs/src/glusterfs/dict.h ++++ b/libglusterfs/src/glusterfs/dict.h +@@ -91,6 +91,9 @@ typedef struct _data_pair data_pair_t; + #define DICT_MAX_FLAGS 256 + #define DICT_FLAG_SET 1 + #define DICT_FLAG_CLEAR 0 ++#define DICT_HDR_LEN 4 ++#define DICT_DATA_HDR_KEY_LEN 4 ++#define DICT_DATA_HDR_VAL_LEN 4 + + struct _data { + char *data; +@@ -412,4 +415,7 @@ are_dicts_equal(dict_t *one, dict_t *two, + gf_boolean_t (*value_ignore)(char *k)); + int + dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result); ++ ++int ++dict_serialized_length_lk(dict_t *this); + #endif +diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym +index cf5757c..ec474e7 100644 +--- a/libglusterfs/src/libglusterfs.sym ++++ b/libglusterfs/src/libglusterfs.sym +@@ -405,6 +405,7 @@ dict_rename_key + dict_reset + dict_serialize + dict_serialized_length ++dict_serialized_length_lk + dict_serialize_value_with_delim + dict_set + dict_setn +diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +index 4ec9700..45f8f17 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c ++++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +@@ -1528,11 +1528,9 @@ glusterd_rpc_friend_add(call_frame_t *frame, xlator_t *this, void *data) + + RCU_READ_UNLOCK; + +- ret = glusterd_add_volumes_to_export_dict(&peer_data); +- if (ret) { +- gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, +- "Unable to add list of volumes " +- "in the peer_data dict for handshake"); ++ peer_data = dict_new(); ++ if (!peer_data) { ++ errno = ENOMEM; + goto out; + } + +@@ -1563,10 +1561,23 @@ glusterd_rpc_friend_add(call_frame_t *frame, xlator_t *this, void *data) + } + } + +- ret = dict_allocate_and_serialize(peer_data, &req.vols.vols_val, +- &req.vols.vols_len); +- if (ret) ++ /* Don't add any key-value in peer_data dictionary after call this function ++ */ ++ ret = glusterd_add_volumes_to_export_dict(peer_data, &req.vols.vols_val, ++ &req.vols.vols_len); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, ++ "Unable to add list of volumes " ++ "in the peer_data dict for handshake"); + goto out; ++ } ++ ++ if (!req.vols.vols_len) { ++ ret = dict_allocate_and_serialize(peer_data, &req.vols.vols_val, ++ &req.vols.vols_len); ++ if (ret) ++ goto out; ++ } + + ret = glusterd_submit_request( + peerinfo->rpc, &req, frame, peerinfo->peer, GLUSTERD_FRIEND_ADD, NULL, +diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c +index 8f1525e..2bc4836 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-utils.c ++++ b/xlators/mgmt/glusterd/src/glusterd-utils.c +@@ -3466,11 +3466,118 @@ out: + return NULL; + } + ++int ++glusterd_dict_searialize(dict_t *dict_arr[], int count, int totcount, char *buf) ++{ ++ int i = 0; ++ int32_t keylen = 0; ++ int64_t netword = 0; ++ data_pair_t *pair = NULL; ++ int dict_count = 0; ++ int ret = 0; ++ ++ netword = hton32(totcount); ++ memcpy(buf, &netword, sizeof(netword)); ++ buf += DICT_HDR_LEN; ++ ++ for (i = 0; i < count; i++) { ++ if (dict_arr[i]) { ++ dict_count = dict_arr[i]->count; ++ pair = dict_arr[i]->members_list; ++ while (dict_count) { ++ if (!pair) { ++ gf_msg("glusterd", GF_LOG_ERROR, 0, ++ LG_MSG_PAIRS_LESS_THAN_COUNT, ++ "less than count data pairs found!"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (!pair->key) { ++ gf_msg("glusterd", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, ++ "pair->key is null!"); ++ ret = -1; ++ goto out; ++ } ++ ++ keylen = strlen(pair->key); ++ netword = hton32(keylen); ++ memcpy(buf, &netword, sizeof(netword)); ++ buf += DICT_DATA_HDR_KEY_LEN; ++ if (!pair->value) { ++ gf_msg("glusterd", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, ++ "pair->value is null!"); ++ ret = -1; ++ goto out; ++ } ++ ++ netword = hton32(pair->value->len); ++ memcpy(buf, &netword, sizeof(netword)); ++ buf += DICT_DATA_HDR_VAL_LEN; ++ ++ memcpy(buf, pair->key, keylen); ++ buf += keylen; ++ *buf++ = '\0'; ++ ++ if (pair->value->data) { ++ memcpy(buf, pair->value->data, pair->value->len); ++ buf += pair->value->len; ++ } ++ ++ pair = pair->next; ++ dict_count--; ++ } ++ } ++ } ++ ++out: ++ for (i = 0; i < count; i++) { ++ if (dict_arr[i]) ++ dict_unref(dict_arr[i]); ++ } ++ return ret; ++} ++ ++int ++glusterd_dict_arr_serialize(dict_t *dict_arr[], int count, char **buf, ++ u_int *length) ++{ ++ ssize_t len = 0; ++ int i = 0; ++ int totcount = 0; ++ int ret = 0; ++ ++ for (i = 0; i < count; i++) { ++ if (dict_arr[i]) { ++ len += dict_serialized_length_lk(dict_arr[i]); ++ totcount += dict_arr[i]->count; ++ } ++ } ++ ++ // Subtract HDR_LEN except one dictionary ++ len = len - ((count - 1) * DICT_HDR_LEN); ++ ++ *buf = GF_MALLOC(len, gf_common_mt_char); ++ if (*buf == NULL) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (length != NULL) { ++ *length = len; ++ } ++ ++ ret = glusterd_dict_searialize(dict_arr, count, totcount, *buf); ++ ++out: ++ return ret; ++} ++ + int32_t +-glusterd_add_volumes_to_export_dict(dict_t **peer_data) ++glusterd_add_volumes_to_export_dict(dict_t *peer_data, char **buf, ++ u_int *length) + { + int32_t ret = -1; +- dict_t *dict = NULL; + dict_t *dict_arr[128] = { + 0, + }; +@@ -3496,10 +3603,6 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data) + priv = this->private; + GF_ASSERT(priv); + +- dict = dict_new(); +- if (!dict) +- goto out; +- + /* Count the total number of volumes */ + cds_list_for_each_entry(volinfo, &priv->volumes, vol_list) volcnt++; + +@@ -3520,14 +3623,15 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data) + cds_list_for_each_entry(volinfo, &priv->volumes, vol_list) + { + count++; +- ret = glusterd_add_volume_to_dict(volinfo, dict, count, "volume"); ++ ret = glusterd_add_volume_to_dict(volinfo, peer_data, count, ++ "volume"); + if (ret) + goto out; + + if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA)) + continue; + +- ret = glusterd_vol_add_quota_conf_to_dict(volinfo, dict, count, ++ ret = glusterd_vol_add_quota_conf_to_dict(volinfo, peer_data, count, + "volume"); + if (ret) + goto out; +@@ -3569,34 +3673,34 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data) + + gf_log(this->name, GF_LOG_INFO, + "Finished dictionary popluation in all threads"); +- for (i = 0; i < totthread; i++) { +- dict_copy_with_ref(dict_arr[i], dict); +- dict_unref(dict_arr[i]); +- } +- gf_log(this->name, GF_LOG_INFO, +- "Finished merger of all dictionraies into single one"); + } + +- ret = dict_set_int32n(dict, "count", SLEN("count"), volcnt); ++ ret = dict_set_int32n(peer_data, "count", SLEN("count"), volcnt); + if (ret) + goto out; + +- ctx.dict = dict; ++ ctx.dict = peer_data; + ctx.prefix = "global"; + ctx.opt_count = 1; + ctx.key_name = "key"; + ctx.val_name = "val"; + dict_foreach(priv->opts, _add_dict_to_prdict, &ctx); + ctx.opt_count--; +- ret = dict_set_int32n(dict, "global-opt-count", SLEN("global-opt-count"), +- ctx.opt_count); ++ ret = dict_set_int32n(peer_data, "global-opt-count", ++ SLEN("global-opt-count"), ctx.opt_count); + if (ret) + goto out; + +- *peer_data = dict; ++ if (totthread) { ++ gf_log(this->name, GF_LOG_INFO, ++ "Finished merger of all dictionraies into single one"); ++ dict_arr[totthread++] = peer_data; ++ ret = glusterd_dict_arr_serialize(dict_arr, totthread, buf, length); ++ gf_log(this->name, GF_LOG_INFO, ++ "Serialize dictionary data return is %d", ret); ++ } ++ + out: +- if (ret) +- dict_unref(dict); + + gf_msg_trace(this->name, 0, "Returning %d", ret); + return ret; +@@ -4940,6 +5044,7 @@ glusterd_import_friend_volumes_synctask(void *opaque) + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + dict_t *peer_data = NULL; ++ glusterd_friend_synctask_args_t *arg = NULL; + + this = THIS; + GF_ASSERT(this); +@@ -4947,8 +5052,20 @@ glusterd_import_friend_volumes_synctask(void *opaque) + conf = this->private; + GF_ASSERT(conf); + +- peer_data = (dict_t *)opaque; +- GF_ASSERT(peer_data); ++ arg = opaque; ++ if (!arg) ++ goto out; ++ ++ peer_data = dict_new(); ++ if (!peer_data) { ++ goto out; ++ } ++ ++ ret = dict_unserialize(arg->dict_buf, arg->dictlen, &peer_data); ++ if (ret) { ++ errno = ENOMEM; ++ goto out; ++ } + + ret = dict_get_int32n(peer_data, "count", SLEN("count"), &count); + if (ret) +@@ -4980,6 +5097,11 @@ glusterd_import_friend_volumes_synctask(void *opaque) + out: + if (peer_data) + dict_unref(peer_data); ++ if (arg) { ++ if (arg->dict_buf) ++ GF_FREE(arg->dict_buf); ++ GF_FREE(arg); ++ } + + gf_msg_debug("glusterd", 0, "Returning with %d", ret); + return ret; +@@ -5146,7 +5268,7 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname) + gf_boolean_t update = _gf_false; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; +- dict_t *peer_data_copy = NULL; ++ glusterd_friend_synctask_args_t *arg = NULL; + + this = THIS; + GF_ASSERT(this); +@@ -5188,12 +5310,23 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname) + * first brick to come up before attaching the subsequent bricks + * in case brick multiplexing is enabled + */ +- peer_data_copy = dict_copy_with_ref(peer_data, NULL); +- glusterd_launch_synctask(glusterd_import_friend_volumes_synctask, +- peer_data_copy); ++ arg = GF_CALLOC(1, sizeof(*arg), gf_common_mt_char); ++ ret = dict_allocate_and_serialize(peer_data, &arg->dict_buf, ++ &arg->dictlen); ++ if (ret < 0) { ++ gf_log(this->name, GF_LOG_ERROR, ++ "dict_serialize failed while handling " ++ " import friend volume request"); ++ goto out; ++ } ++ ++ glusterd_launch_synctask(glusterd_import_friend_volumes_synctask, arg); + } + + out: ++ if (ret && arg) { ++ GF_FREE(arg); ++ } + gf_msg_debug(this->name, 0, "Returning with ret: %d, status: %d", ret, + *status); + return ret; +diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h +index 3647c34..6ad8062 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-utils.h ++++ b/xlators/mgmt/glusterd/src/glusterd-utils.h +@@ -227,7 +227,8 @@ glusterd_volume_brickinfo_get_by_brick(char *brick, glusterd_volinfo_t *volinfo, + gf_boolean_t construct_real_path); + + int32_t +-glusterd_add_volumes_to_export_dict(dict_t **peer_data); ++glusterd_add_volumes_to_export_dict(dict_t *peer_data, char **buf, ++ u_int *length); + + int32_t + glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, +diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h +index 2ea8560..f96bca3 100644 +--- a/xlators/mgmt/glusterd/src/glusterd.h ++++ b/xlators/mgmt/glusterd/src/glusterd.h +@@ -240,6 +240,11 @@ typedef struct glusterd_add_dict_args { + int end; + } glusterd_add_dict_args_t; + ++typedef struct glusterd_friend_synctask_args { ++ char *dict_buf; ++ u_int dictlen; ++} glusterd_friend_synctask_args_t; ++ + typedef enum gf_brick_status { + GF_BRICK_STOPPED, + GF_BRICK_STARTED, +-- +1.8.3.1 + diff --git a/0150-libglusterfs-define-macros-needed-for-cloudsync.patch b/0150-libglusterfs-define-macros-needed-for-cloudsync.patch new file mode 100644 index 0000000..b5fbef2 --- /dev/null +++ b/0150-libglusterfs-define-macros-needed-for-cloudsync.patch @@ -0,0 +1,38 @@ +From 4c410d99792808b0c8deb601d50c66df19f73ca7 Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Thu, 25 Oct 2018 17:23:10 -0400 +Subject: [PATCH 150/169] libglusterfs: define macros needed for cloudsync + +backport of patch: https://review.gluster.org/#/c/glusterfs/+/21585/ + +> Change-Id: Iec5ce7f17fbf899f881a58cd20c4c967e3b71668 +> fixes: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: I79e5d955559acdec7cbeb8f35c8482b3b6ff8b0f +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172189 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + libglusterfs/src/glusterfs/glusterfs.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h +index fb727fc..516b497 100644 +--- a/libglusterfs/src/glusterfs/glusterfs.h ++++ b/libglusterfs/src/glusterfs/glusterfs.h +@@ -364,6 +364,10 @@ enum gf_internal_fop_indicator { + } while (0) + + #define GF_CS_OBJECT_SIZE "trusted.glusterfs.cs.object_size" ++#define GF_CS_BLOCK_SIZE "trusted.glusterfs.cs.block_size" ++#define GF_CS_NUM_BLOCKS "trusted.glusterfs.cs.num_blocks" ++ ++#define GF_CS_XATTR_ARCHIVE_UUID "trusted.cloudsync.uuid" + + #define GF_CS_OBJECT_UPLOAD_COMPLETE "trusted.glusterfs.csou.complete" + #define GF_CS_OBJECT_REMOTE "trusted.glusterfs.cs.remote" +-- +1.8.3.1 + diff --git a/0151-mgmt-glusterd-Make-changes-related-to-cloudsync-xlat.patch b/0151-mgmt-glusterd-Make-changes-related-to-cloudsync-xlat.patch new file mode 100644 index 0000000..d95db3d --- /dev/null +++ b/0151-mgmt-glusterd-Make-changes-related-to-cloudsync-xlat.patch @@ -0,0 +1,156 @@ +From bffdcce7119f3ed68694df918e504cc241502835 Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Mon, 19 Nov 2018 17:57:18 -0800 +Subject: [PATCH 151/169] mgmt/glusterd: Make changes related to cloudsync + xlator + +1) The placement of cloudsync xlator has been changed +to make it shard xlator's child. If cloudsync has to +work with shard in the graph, it needs to be child of shard. + +backport of: https://review.gluster.org/#/c/glusterfs/+/21681/ + +> Change-Id: Ib55424fdcb7ce8edae9f19b8a6e3d3ba86c1f0c4 +> fixes: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: I68fd43b2c559cc2d9f05e1ab19784b174233d690 +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172190 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + tests/basic/glusterd/check-cloudsync-ancestry.t | 48 +++++++++++++++++++++++++ + tests/volume.rc | 21 +++++++++++ + xlators/mgmt/glusterd/src/glusterd-volgen.c | 24 ++++++------- + 3 files changed, 81 insertions(+), 12 deletions(-) + create mode 100644 tests/basic/glusterd/check-cloudsync-ancestry.t + +diff --git a/tests/basic/glusterd/check-cloudsync-ancestry.t b/tests/basic/glusterd/check-cloudsync-ancestry.t +new file mode 100644 +index 0000000..ff6ffee +--- /dev/null ++++ b/tests/basic/glusterd/check-cloudsync-ancestry.t +@@ -0,0 +1,48 @@ ++#!/bin/bash ++ ++. $(dirname $0)/../../include.rc ++. $(dirname $0)/../../volume.rc ++ ++# When shard and cloudsync xlators enabled on a volume, shard xlator ++# should be an ancestor of cloudsync. This testcase is to check this condition. ++ ++cleanup; ++TEST glusterd ++TEST pidof glusterd ++TEST $CLI volume create $V0 $H0:$B0/b1 $H0:$B0/b2 $H0:$B0/b3 ++ ++volfile=$(gluster system:: getwd)"/vols/$V0/trusted-$V0.tcp-fuse.vol" ++ ++#Test that both shard and cloudsync are not loaded ++EXPECT "N" volgen_volume_exists $volfile $V0-shard features shard ++EXPECT "N" volgen_volume_exists $volfile $V0-cloudsync features cloudsync ++ ++#Enable shard and cloudsync in that order and check if volfile is correct ++TEST $CLI volume set $V0 shard on ++TEST $CLI volume set $V0 cloudsync on ++ ++#Test that both shard and cloudsync are loaded ++EXPECT "Y" volgen_volume_exists $volfile $V0-shard features shard ++EXPECT "Y" volgen_volume_exists $volfile $V0-cloudsync features cloudsync ++ ++EXPECT "Y" volgen_check_ancestry $volfile features shard features cloudsync ++ ++#Disable shard and cloudsync ++TEST $CLI volume set $V0 shard off ++TEST $CLI volume set $V0 cloudsync off ++ ++#Test that both shard and cloudsync are not loaded ++EXPECT "N" volgen_volume_exists $volfile $V0-shard features shard ++EXPECT "N" volgen_volume_exists $volfile $V0-cloudsync features cloudsync ++ ++#Enable cloudsync and shard in that order and check if volfile is correct ++TEST $CLI volume set $V0 cloudsync on ++TEST $CLI volume set $V0 shard on ++ ++#Test that both shard and cloudsync are loaded ++EXPECT "Y" volgen_volume_exists $volfile $V0-shard features shard ++EXPECT "Y" volgen_volume_exists $volfile $V0-cloudsync features cloudsync ++ ++EXPECT "Y" volgen_check_ancestry $volfile features shard features cloudsync ++ ++cleanup; +diff --git a/tests/volume.rc b/tests/volume.rc +index b326098..a0ea3b8 100644 +--- a/tests/volume.rc ++++ b/tests/volume.rc +@@ -891,3 +891,24 @@ function check_changelog_op { + + $PYTHON $(dirname $0)/../../utils/changelogparser.py ${clog_path}/CHANGELOG | grep "$op" | wc -l + } ++ ++function volgen_check_ancestry { ++ #Returns Y if ancestor_xl is an ancestor of $child_xl according to the volfile ++ local volfile="$1" ++ ++ local child_xl_type="$2" ++ local child_xl="$3" ++ ++ local ancestor_xl_type="$4" ++ local ancestor_xl="$5" ++ ++ child_linenum=$(awk '/type $child_xl_type\/$child_xl/ {print FNR}' $volfile) ++ ancestor_linenum=$(awk '/type $ancestor_xl_type\/$ancestor_xl/ {print FNR}' $volfile) ++ ++ if [ $child_linenum -lt $ancestor_linenum ]; ++ then ++ echo "Y" ++ else ++ echo "N" ++ fi ++} +diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c +index 77aa705..8b58d40 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c ++++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c +@@ -4360,6 +4360,18 @@ client_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + "tcp", set_dict); + } + ++ ret = dict_get_str_boolean(set_dict, "features.cloudsync", _gf_false); ++ if (ret == -1) ++ goto out; ++ ++ if (ret) { ++ xl = volgen_graph_add(graph, "features/cloudsync", volname); ++ if (!xl) { ++ ret = -1; ++ goto out; ++ } ++ } ++ + ret = dict_get_str_boolean(set_dict, "features.shard", _gf_false); + if (ret == -1) + goto out; +@@ -4567,18 +4579,6 @@ client_graph_builder(volgen_graph_t *graph, glusterd_volinfo_t *volinfo, + if (ret) + return -1; + +- ret = dict_get_str_boolean(set_dict, "features.cloudsync", _gf_false); +- if (ret == -1) +- goto out; +- +- if (ret) { +- xl = volgen_graph_add(graph, "features/cloudsync", volname); +- if (!xl) { +- ret = -1; +- goto out; +- } +- } +- + /* if the client is part of 'gfproxyd' server, then we need to keep the + volume name as 'gfproxyd-', for better portmapper options */ + subvol = volname; +-- +1.8.3.1 + diff --git a/0152-storage-posix-changes-with-respect-to-cloudsync.patch b/0152-storage-posix-changes-with-respect-to-cloudsync.patch new file mode 100644 index 0000000..1610009 --- /dev/null +++ b/0152-storage-posix-changes-with-respect-to-cloudsync.patch @@ -0,0 +1,403 @@ +From 10e9f850017d58fcd813ccce253784280326f1d0 Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Tue, 20 Nov 2018 13:15:26 -0800 +Subject: [PATCH 152/169] storage/posix: changes with respect to cloudsync + +Main changes include logic to update iatt buf +with file size from extended attributes in posix +rather than having this logic in cloudsync xlator. + +backport of:https://review.gluster.org/#/c/glusterfs/+/21694/ + +> Change-Id: I44f5f8df7a01e496372557fe2f4eff368dbdaa33 +> fixes: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: I34880d856fb3add4ce88d64021d08d95405fc1c1 +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172191 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + xlators/storage/posix/src/posix-entry-ops.c | 1 + + xlators/storage/posix/src/posix-helpers.c | 50 +++++++++ + xlators/storage/posix/src/posix-inode-fd-ops.c | 139 ++++++++++++++++++++++--- + xlators/storage/posix/src/posix.h | 2 + + 4 files changed, 177 insertions(+), 15 deletions(-) + +diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c +index fbd83c4..b24a052 100644 +--- a/xlators/storage/posix/src/posix-entry-ops.c ++++ b/xlators/storage/posix/src/posix-entry-ops.c +@@ -272,6 +272,7 @@ posix_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) + } + } + ++ posix_update_iatt_buf(&buf, -1, real_path, xdata); + if (priv->update_pgfid_nlinks) { + if (!gf_uuid_is_null(loc->pargfid) && !IA_ISDIR(buf.ia_type)) { + MAKE_PGFID_XATTR_KEY(pgfid_xattr_key, PGFID_XATTR_KEY_PREFIX, +diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c +index 37e33a9..d0fd45a 100644 +--- a/xlators/storage/posix/src/posix-helpers.c ++++ b/xlators/storage/posix/src/posix-helpers.c +@@ -3453,3 +3453,53 @@ posix_check_dev_file(xlator_t *this, inode_t *inode, char *fop, int *op_errno) + out: + return ret; + } ++ ++void ++posix_update_iatt_buf(struct iatt *buf, int fd, char *loc, dict_t *xattr_req) ++{ ++ int ret = 0; ++ char val[4096] = { ++ 0, ++ }; ++ ++ if (!xattr_req) ++ return; ++ ++ if (!(dict_getn(xattr_req, GF_CS_OBJECT_STATUS, ++ strlen(GF_CS_OBJECT_STATUS)))) ++ return; ++ ++ if (fd != -1) { ++ ret = sys_fgetxattr(fd, GF_CS_OBJECT_SIZE, &val, sizeof(val)); ++ if (ret > 0) { ++ buf->ia_size = atoll(val); ++ } else { ++ /* Safe to assume that the other 2 xattrs are also not set*/ ++ return; ++ } ++ ret = sys_fgetxattr(fd, GF_CS_BLOCK_SIZE, &val, sizeof(val)); ++ if (ret > 0) { ++ buf->ia_blksize = atoll(val); ++ } ++ ret = sys_fgetxattr(fd, GF_CS_NUM_BLOCKS, &val, sizeof(val)); ++ if (ret > 0) { ++ buf->ia_blocks = atoll(val); ++ } ++ } else { ++ ret = sys_lgetxattr(loc, GF_CS_OBJECT_SIZE, &val, sizeof(val)); ++ if (ret > 0) { ++ buf->ia_size = atoll(val); ++ } else { ++ /* Safe to assume that the other 2 xattrs are also not set*/ ++ return; ++ } ++ ret = sys_lgetxattr(loc, GF_CS_BLOCK_SIZE, &val, sizeof(val)); ++ if (ret > 0) { ++ buf->ia_blksize = atoll(val); ++ } ++ ret = sys_lgetxattr(loc, GF_CS_NUM_BLOCKS, &val, sizeof(val)); ++ if (ret > 0) { ++ buf->ia_blocks = atoll(val); ++ } ++ } ++} +diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c +index 7dbbd3d..065fced 100644 +--- a/xlators/storage/posix/src/posix-inode-fd-ops.c ++++ b/xlators/storage/posix/src/posix-inode-fd-ops.c +@@ -108,6 +108,63 @@ extern char *marker_xattrs[]; + static char *disallow_removexattrs[] = {GF_XATTR_VOL_ID_KEY, GFID_XATTR_KEY, + NULL}; + ++void ++posix_cs_build_xattr_rsp(xlator_t *this, dict_t **rsp, dict_t *req, int fd, ++ char *loc) ++{ ++ int ret = 0; ++ uuid_t uuid; ++ ++ if (!(dict_getn(req, GF_CS_OBJECT_STATUS, strlen(GF_CS_OBJECT_STATUS)))) ++ return; ++ ++ if (!(*rsp)) { ++ *rsp = dict_new(); ++ if (!(*rsp)) { ++ return; ++ } ++ } ++ ++ if (fd != -1) { ++ if (dict_getn(req, GF_CS_XATTR_ARCHIVE_UUID, ++ strlen(GF_CS_XATTR_ARCHIVE_UUID))) { ++ ret = sys_fgetxattr(fd, GF_CS_XATTR_ARCHIVE_UUID, uuid, 16); ++ if (ret > 0) { ++ ret = dict_set_gfuuid(*rsp, GF_CS_XATTR_ARCHIVE_UUID, uuid, ++ true); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_DICT_SET_FAILED, ++ "%s: Failed to set " ++ "dictionary value for %s for fd %d", ++ uuid_utoa(uuid), GF_CS_XATTR_ARCHIVE_UUID, fd); ++ } ++ } else { ++ gf_msg_debug(this->name, 0, "getxattr failed on %s for fd %d", ++ GF_CS_XATTR_ARCHIVE_UUID, fd); ++ } ++ } ++ } else { ++ if (dict_getn(req, GF_CS_XATTR_ARCHIVE_UUID, ++ strlen(GF_CS_XATTR_ARCHIVE_UUID))) { ++ ret = sys_lgetxattr(loc, GF_CS_XATTR_ARCHIVE_UUID, uuid, 16); ++ if (ret > 0) { ++ ret = dict_set_gfuuid(*rsp, GF_CS_XATTR_ARCHIVE_UUID, uuid, ++ true); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_DICT_SET_FAILED, ++ "%s: Failed to set " ++ "dictionary value for %s for loc %s", ++ uuid_utoa(uuid), GF_CS_XATTR_ARCHIVE_UUID, loc); ++ } ++ } else { ++ gf_msg_debug(this->name, 0, "getxattr failed on %s for %s", ++ GF_CS_XATTR_ARCHIVE_UUID, loc); ++ } ++ } ++ } ++ return; ++} ++ + int32_t + posix_stat(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) + { +@@ -150,8 +207,11 @@ posix_stat(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) + + posix_cs_maintenance(this, NULL, loc, NULL, &buf, real_path, xdata, + &xattr_rsp, _gf_true); ++ ++ posix_cs_build_xattr_rsp(this, &xattr_rsp, xdata, -1, real_path); + } + ++ posix_update_iatt_buf(&buf, -1, real_path, xdata); + op_ret = 0; + + out: +@@ -422,6 +482,8 @@ posix_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + if (xdata) + xattr_rsp = posix_xattr_fill(this, real_path, loc, NULL, -1, xdata, + &statpost); ++ posix_update_iatt_buf(&statpre, -1, real_path, xdata); ++ posix_update_iatt_buf(&statpost, -1, real_path, xdata); + op_ret = 0; + + out: +@@ -898,6 +960,7 @@ posix_do_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + } + } + ++ posix_update_iatt_buf(statpre, pfd->fd, NULL, xdata); + /* See if we can use FALLOC_FL_ZERO_RANGE to perform the zero fill. + * If it fails, fall back to _posix_do_zerofill() and an optional fsync. + */ +@@ -1366,6 +1429,7 @@ posix_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + } + } + ++ posix_update_iatt_buf(&prebuf, -1, real_path, xdata); + op_ret = sys_truncate(real_path, offset); + if (op_ret == -1) { + op_errno = errno; +@@ -1405,6 +1469,10 @@ posix_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + int32_t _fd = -1; + struct posix_fd *pfd = NULL; + struct posix_private *priv = NULL; ++ struct iatt preop = { ++ 0, ++ }; ++ dict_t *rsp_xdata = NULL; + struct iatt stbuf = { + 0, + }; +@@ -1471,6 +1539,18 @@ posix_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + pfd->flags = flags; + pfd->fd = _fd; + ++ if (xdata) { ++ op_ret = posix_fdstat(this, fd->inode, pfd->fd, &preop); ++ if (op_ret == -1) { ++ gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_FSTAT_FAILED, ++ "pre-operation fstat failed on fd=%p", fd); ++ goto out; ++ } ++ ++ posix_cs_maintenance(this, fd, NULL, &pfd->fd, &preop, NULL, xdata, ++ &rsp_xdata, _gf_true); ++ } ++ + op_ret = fd_ctx_set(fd, this, (uint64_t)(long)pfd); + if (op_ret) + gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_FD_PATH_SETTING_FAILED, +@@ -1488,7 +1568,7 @@ out: + + SET_TO_OLD_FS_ID(); + +- STACK_UNWIND_STRICT(open, frame, op_ret, op_errno, fd, NULL); ++ STACK_UNWIND_STRICT(open, frame, op_ret, op_errno, fd, rsp_xdata); + + return 0; + } +@@ -1573,6 +1653,7 @@ posix_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + } + } + ++ posix_update_iatt_buf(&preop, _fd, NULL, xdata); + op_ret = sys_pread(_fd, iobuf->ptr, size, offset); + if (op_ret == -1) { + op_errno = errno; +@@ -1878,6 +1959,7 @@ posix_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, + } + } + ++ posix_update_iatt_buf(&preop, _fd, NULL, xdata); + if (locked && write_append) { + if (preop.ia_size == offset || (fd->flags & O_APPEND)) + is_append = 1; +@@ -2531,10 +2613,8 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + 0, + }; + data_t *tdata = NULL; +- char stime[4096]; +- char sxattr[4096]; ++ char *cs_var = NULL; + gf_cs_obj_state state = -1; +- char remotepath[4096] = {0}; + int i = 0; + int len; + +@@ -2588,10 +2668,11 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + goto unlock; + } + +- sprintf(stime, "%" PRId64, tmp_stbuf.ia_mtime); ++ cs_var = alloca(4096); ++ sprintf(cs_var, "%" PRId64, tmp_stbuf.ia_mtime); + + /*TODO: may be should consider nano-second also */ +- if (strncmp(stime, tdata->data, tdata->len) != 0) { ++ if (strncmp(cs_var, tdata->data, tdata->len) > 0) { + gf_msg(this->name, GF_LOG_ERROR, 0, 0, + "mtime " + "passed is different from seen by file now." +@@ -2601,31 +2682,54 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + goto unlock; + } + +- len = sprintf(sxattr, "%" PRIu64, tmp_stbuf.ia_size); ++ len = sprintf(cs_var, "%" PRIu64, tmp_stbuf.ia_size); + +- ret = sys_lsetxattr(real_path, GF_CS_OBJECT_SIZE, sxattr, len, ++ ret = sys_lsetxattr(real_path, GF_CS_OBJECT_SIZE, cs_var, len, + flags); + if (ret) { ++ op_errno = errno; + gf_msg(this->name, GF_LOG_ERROR, 0, 0, + "setxattr failed. key %s err %d", GF_CS_OBJECT_SIZE, + ret); ++ goto unlock; ++ } ++ ++ len = sprintf(cs_var, "%" PRIu64, tmp_stbuf.ia_blocks); ++ ++ ret = sys_lsetxattr(real_path, GF_CS_NUM_BLOCKS, cs_var, len, ++ flags); ++ if (ret) { + op_errno = errno; ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "setxattr failed. key %s err %d", GF_CS_NUM_BLOCKS, ret); + goto unlock; + } + ++ len = sprintf(cs_var, "%" PRIu32, tmp_stbuf.ia_blksize); ++ ++ ret = sys_lsetxattr(real_path, GF_CS_BLOCK_SIZE, cs_var, len, ++ flags); ++ if (ret) { ++ op_errno = errno; ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "setxattr failed. key %s err %d", GF_CS_BLOCK_SIZE, ret); ++ goto unlock; ++ } ++ ++ memset(cs_var, 0, 4096); + if (loc->path[0] == '/') { + for (i = 1; i < strlen(loc->path); i++) { +- remotepath[i - 1] = loc->path[i]; ++ cs_var[i - 1] = loc->path[i]; + } + +- remotepath[i] = '\0'; +- gf_msg_debug(this->name, GF_LOG_ERROR, "remotepath %s", +- remotepath); ++ cs_var[i] = '\0'; ++ gf_msg_debug(this->name, GF_LOG_ERROR, "remotepath %s", cs_var); + } + +- ret = sys_lsetxattr(real_path, GF_CS_OBJECT_REMOTE, remotepath, +- strlen(loc->path), flags); ++ ret = sys_lsetxattr(real_path, GF_CS_OBJECT_REMOTE, cs_var, ++ strlen(cs_var), flags); + if (ret) { ++ op_errno = errno; + gf_log("POSIX", GF_LOG_ERROR, + "setxattr failed - %s" + " %d", +@@ -2635,13 +2739,14 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + + ret = sys_truncate(real_path, 0); + if (ret) { ++ op_errno = errno; + gf_log("POSIX", GF_LOG_ERROR, + "truncate failed - %s" + " %d", + GF_CS_OBJECT_SIZE, ret); +- op_errno = errno; + ret = sys_lremovexattr(real_path, GF_CS_OBJECT_REMOTE); + if (ret) { ++ op_errno = errno; + gf_log("POSIX", GF_LOG_ERROR, + "removexattr " + "failed post processing- %s" +@@ -2659,6 +2764,7 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + } + unlock: + UNLOCK(&loc->inode->lock); ++ op_ret = ret; + goto out; + } + +@@ -4927,6 +5033,7 @@ posix_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + } + } + ++ posix_update_iatt_buf(&preop, _fd, NULL, xdata); + op_ret = sys_ftruncate(_fd, offset); + + if (op_ret == -1) { +@@ -5008,8 +5115,10 @@ posix_fstat(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) + gf_msg(this->name, GF_LOG_ERROR, 0, 0, + "file state check failed, fd %p", fd); + } ++ posix_cs_build_xattr_rsp(this, &xattr_rsp, xdata, _fd, NULL); + } + ++ posix_update_iatt_buf(&buf, _fd, NULL, xdata); + op_ret = 0; + + out: +diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h +index d5ba08c..1da4d01 100644 +--- a/xlators/storage/posix/src/posix.h ++++ b/xlators/storage/posix/src/posix.h +@@ -664,4 +664,6 @@ posix_check_dev_file(xlator_t *this, inode_t *inode, char *fop, int *op_errno); + int + posix_spawn_ctx_janitor_thread(xlator_t *this); + ++void ++posix_update_iatt_buf(struct iatt *buf, int fd, char *loc, dict_t *xdata); + #endif /* _POSIX_H */ +-- +1.8.3.1 + diff --git a/0153-features-cloudsync-Added-some-new-functions.patch b/0153-features-cloudsync-Added-some-new-functions.patch new file mode 100644 index 0000000..d28a7a5 --- /dev/null +++ b/0153-features-cloudsync-Added-some-new-functions.patch @@ -0,0 +1,1077 @@ +From 90254e4ae9455fa0a126f83700978a9314eb79ea Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Thu, 29 Nov 2018 12:54:21 -0800 +Subject: [PATCH 153/169] features/cloudsync : Added some new functions + +This patch contains the following changes: +1) Store ID info will now be stored in the inode ctx +2) Added new readv type where read is made directly + from the remote store. This choice is made by + volume set operation. +3) cs_forget() was missing. Added it. + +backport of:https://review.gluster.org/#/c/glusterfs/+/21757/ + +> Change-Id: Ie3232b3d7ffb5313a03f011b0553b19793eedfa2 +> fixes: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: I089e5a8c93049cf6bfabf011673796e38e78d7ee +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172192 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + xlators/features/cloudsync/src/cloudsync-common.c | 16 + + xlators/features/cloudsync/src/cloudsync-common.h | 35 ++ + xlators/features/cloudsync/src/cloudsync-fops-c.py | 12 +- + .../features/cloudsync/src/cloudsync-mem-types.h | 1 + + xlators/features/cloudsync/src/cloudsync.c | 600 ++++++++++++++++++--- + xlators/features/cloudsync/src/cloudsync.h | 20 + + xlators/mgmt/glusterd/src/glusterd-volume-set.c | 7 +- + 7 files changed, 597 insertions(+), 94 deletions(-) + +diff --git a/xlators/features/cloudsync/src/cloudsync-common.c b/xlators/features/cloudsync/src/cloudsync-common.c +index aee1f06..445a31b 100644 +--- a/xlators/features/cloudsync/src/cloudsync-common.c ++++ b/xlators/features/cloudsync/src/cloudsync-common.c +@@ -11,6 +11,20 @@ + #include "cloudsync-common.h" + + void ++cs_xattrinfo_wipe(cs_local_t *local) ++{ ++ if (local->xattrinfo.lxattr) { ++ if (local->xattrinfo.lxattr->file_path) ++ GF_FREE(local->xattrinfo.lxattr->file_path); ++ ++ if (local->xattrinfo.lxattr->volname) ++ GF_FREE(local->xattrinfo.lxattr->volname); ++ ++ GF_FREE(local->xattrinfo.lxattr); ++ } ++} ++ ++void + cs_local_wipe(xlator_t *this, cs_local_t *local) + { + if (!local) +@@ -40,5 +54,7 @@ cs_local_wipe(xlator_t *this, cs_local_t *local) + if (local->remotepath) + GF_FREE(local->remotepath); + ++ cs_xattrinfo_wipe(local); ++ + mem_put(local); + } +diff --git a/xlators/features/cloudsync/src/cloudsync-common.h b/xlators/features/cloudsync/src/cloudsync-common.h +index 7b3520c..11d2334 100644 +--- a/xlators/features/cloudsync/src/cloudsync-common.h ++++ b/xlators/features/cloudsync/src/cloudsync-common.h +@@ -14,9 +14,23 @@ + #include + #include + #include ++#include + #include "cloudsync-mem-types.h" + #include "cloudsync-messages.h" + ++typedef struct cs_loc_xattr { ++ char *file_path; ++ uuid_t uuid; ++ uuid_t gfid; ++ char *volname; ++} cs_loc_xattr_t; ++ ++typedef struct cs_size_xattr { ++ uint64_t size; ++ uint64_t blksize; ++ uint64_t blocks; ++} cs_size_xattr_t; ++ + typedef struct cs_local { + loc_t loc; + fd_t *fd; +@@ -34,10 +48,25 @@ typedef struct cs_local { + int call_cnt; + inode_t *inode; + char *remotepath; ++ ++ struct { ++ /* offset, flags and size are the information needed ++ * by read fop for remote read operation. These will be ++ * populated in cloudsync read fop, before being passed ++ * on to the plugin performing remote read. ++ */ ++ off_t offset; ++ uint32_t flags; ++ size_t size; ++ cs_loc_xattr_t *lxattr; ++ } xattrinfo; ++ + } cs_local_t; + + typedef int (*fop_download_t)(call_frame_t *frame, void *config); + ++typedef int (*fop_remote_read_t)(call_frame_t *, void *); ++ + typedef void *(*store_init)(xlator_t *this); + + typedef int (*store_reconfigure)(xlator_t *this, dict_t *options); +@@ -48,6 +77,7 @@ struct cs_remote_stores { + char *name; /* store name */ + void *config; /* store related information */ + fop_download_t dlfop; /* store specific download function */ ++ fop_remote_read_t rdfop; /* store specific read function */ + store_init init; /* store init to initialize store config */ + store_reconfigure reconfigure; /* reconfigure store config */ + store_fini fini; +@@ -59,11 +89,15 @@ typedef struct cs_private { + struct cs_remote_stores *stores; + gf_boolean_t abortdl; + pthread_spinlock_t lock; ++ gf_boolean_t remote_read; + } cs_private_t; + + void + cs_local_wipe(xlator_t *this, cs_local_t *local); + ++void ++cs_xattrinfo_wipe(cs_local_t *local); ++ + #define CS_STACK_UNWIND(fop, frame, params...) \ + do { \ + cs_local_t *__local = NULL; \ +@@ -90,6 +124,7 @@ cs_local_wipe(xlator_t *this, cs_local_t *local); + + typedef struct store_methods { + int (*fop_download)(call_frame_t *frame, void *config); ++ int (*fop_remote_read)(call_frame_t *, void *); + /* return type should be the store config */ + void *(*fop_init)(xlator_t *this); + int (*fop_reconfigure)(xlator_t *this, dict_t *options); +diff --git a/xlators/features/cloudsync/src/cloudsync-fops-c.py b/xlators/features/cloudsync/src/cloudsync-fops-c.py +index 3122bd3..a7a2201 100755 +--- a/xlators/features/cloudsync/src/cloudsync-fops-c.py ++++ b/xlators/features/cloudsync/src/cloudsync-fops-c.py +@@ -137,15 +137,15 @@ cs_@NAME@_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + } else { + __cs_inode_ctx_update (this, fd->inode, val); + gf_msg (this->name, GF_LOG_INFO, 0, 0, +- " state = %ld", val); ++ " state = %" PRIu64, val); + + if (local->call_cnt == 1 && + (val == GF_CS_REMOTE || + val == GF_CS_DOWNLOADING)) { + gf_msg (this->name, GF_LOG_INFO, 0, + 0, " will repair and download " +- "the file, current state : %ld", +- val); ++ "the file, current state : %" ++ PRIu64, val); + goto repair; + } else { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, +@@ -274,7 +274,7 @@ fd_ops = ['readv', 'writev', 'flush', 'fsync', 'fsyncdir', 'ftruncate', + # These are the current actual lists used to generate the code + + # The following list contains fops which are fd based that modifies data +-fd_data_modify_op_fop_template = ['readv', 'writev', 'flush', 'fsync', ++fd_data_modify_op_fop_template = ['writev', 'flush', 'fsync', + 'ftruncate', 'rchecksum', 'fallocate', + 'discard', 'zerofill', 'seek'] + +@@ -284,8 +284,8 @@ loc_stat_op_fop_template = ['lookup', 'stat', 'discover', 'access', 'setattr', + 'getattr'] + + # These fops need a separate implementation +-special_fops = ['readdirp', 'statfs', 'setxattr', 'unlink', 'getxattr', +- 'truncate', 'fstat'] ++special_fops = ['statfs', 'setxattr', 'unlink', 'getxattr', ++ 'truncate', 'fstat', 'readv'] + + def gen_defaults(): + for name in ops: +diff --git a/xlators/features/cloudsync/src/cloudsync-mem-types.h b/xlators/features/cloudsync/src/cloudsync-mem-types.h +index 9e6837a..2203464 100644 +--- a/xlators/features/cloudsync/src/cloudsync-mem-types.h ++++ b/xlators/features/cloudsync/src/cloudsync-mem-types.h +@@ -16,6 +16,7 @@ enum cs_mem_types_ { + gf_cs_mt_cs_private_t = gf_common_mt_end + 1, + gf_cs_mt_cs_remote_stores_t, + gf_cs_mt_cs_inode_ctx_t, ++ gf_cs_mt_cs_lxattr_t, + gf_cs_mt_end + }; + #endif /* __CLOUDSYNC_MEM_TYPES_H__ */ +diff --git a/xlators/features/cloudsync/src/cloudsync.c b/xlators/features/cloudsync/src/cloudsync.c +index fbdcdf7..2240fc3 100644 +--- a/xlators/features/cloudsync/src/cloudsync.c ++++ b/xlators/features/cloudsync/src/cloudsync.c +@@ -16,6 +16,7 @@ + #include + #include "cloudsync-autogen-fops.h" + ++#include + #include + + void +@@ -72,6 +73,8 @@ cs_init(xlator_t *this) + + this->private = priv; + ++ GF_OPTION_INIT("cloudsync-remote-read", priv->remote_read, bool, out); ++ + /* temp workaround. Should be configurable through glusterd*/ + per_vol = _gf_true; + +@@ -135,6 +138,18 @@ cs_init(xlator_t *this) + + (void)dlerror(); + ++ if (priv->remote_read) { ++ priv->stores->rdfop = store_methods->fop_remote_read; ++ if (!priv->stores->rdfop) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "failed to get" ++ " read fop %s", ++ dlerror()); ++ ret = -1; ++ goto out; ++ } ++ } ++ + priv->stores->dlfop = store_methods->fop_download; + if (!priv->stores->dlfop) { + gf_msg(this->name, GF_LOG_ERROR, 0, 0, +@@ -196,6 +211,22 @@ out: + return ret; + } + ++int ++cs_forget(xlator_t *this, inode_t *inode) ++{ ++ uint64_t ctx_int = 0; ++ cs_inode_ctx_t *ctx = NULL; ++ ++ inode_ctx_del(inode, this, &ctx_int); ++ if (!ctx_int) ++ return 0; ++ ++ ctx = (cs_inode_ctx_t *)(uintptr_t)ctx_int; ++ ++ GF_FREE(ctx); ++ return 0; ++} ++ + void + cs_fini(xlator_t *this) + { +@@ -217,6 +248,9 @@ cs_reconfigure(xlator_t *this, dict_t *options) + goto out; + } + ++ GF_OPTION_RECONF("cloudsync-remote-read", priv->remote_read, options, bool, ++ out); ++ + /* needed only for per volume configuration*/ + ret = priv->stores->reconfigure(this, options); + +@@ -242,59 +276,6 @@ out: + } + + int32_t +-cs_readdirp_cbk(call_frame_t *frame, void *cookie, xlator_t *this, +- int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, +- dict_t *xdata) +-{ +- gf_dirent_t *tmp = NULL; +- char *sxattr = NULL; +- uint64_t ia_size = 0; +- int ret = 0; +- +- list_for_each_entry(tmp, &entries->list, list) +- { +- ret = dict_get_str(tmp->dict, GF_CS_OBJECT_SIZE, &sxattr); +- if (ret) { +- gf_msg_trace(this->name, 0, "size xattr found"); +- continue; +- } +- +- ia_size = atoll(sxattr); +- tmp->d_stat.ia_size = ia_size; +- } +- +- STACK_UNWIND_STRICT(readdirp, frame, op_ret, op_errno, entries, xdata); +- return 0; +-} +- +-int32_t +-cs_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, +- off_t off, dict_t *xdata) +-{ +- int ret = 0; +- int op_errno = ENOMEM; +- +- if (!xdata) { +- xdata = dict_new(); +- if (!xdata) { +- goto err; +- } +- } +- +- ret = dict_set_int32(xdata, GF_CS_OBJECT_SIZE, 1); +- if (ret) { +- goto err; +- } +- +- STACK_WIND(frame, cs_readdirp_cbk, FIRST_CHILD(this), +- FIRST_CHILD(this)->fops->readdirp, fd, size, off, xdata); +- return 0; +-err: +- STACK_UNWIND_STRICT(readdirp, frame, -1, op_errno, NULL, NULL); +- return 0; +-} +- +-int32_t + cs_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +@@ -305,7 +286,6 @@ cs_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + + local = frame->local; + +- /* Do we need lock here? */ + local->call_cnt++; + + if (op_ret == -1) { +@@ -320,13 +300,13 @@ cs_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + goto unwind; + } else { + __cs_inode_ctx_update(this, local->loc.inode, val); +- gf_msg(this->name, GF_LOG_INFO, 0, 0, " state = %ld", val); ++ gf_msg(this->name, GF_LOG_INFO, 0, 0, " state = %" PRIu64, val); + + if (local->call_cnt == 1 && + (val == GF_CS_REMOTE || val == GF_CS_DOWNLOADING)) { + gf_msg(this->name, GF_LOG_WARNING, 0, 0, + "will repair and download " +- "the file, current state : %ld", ++ "the file, current state : %" PRIu64, + val); + goto repair; + } else { +@@ -665,7 +645,7 @@ cs_fstat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + if (op_ret == 0) { + ret = dict_get_uint64(xdata, GF_CS_OBJECT_STATUS, &val); + if (!ret) { +- gf_msg_debug(this->name, 0, "state %ld", val); ++ gf_msg_debug(this->name, 0, "state %" PRIu64, val); + ret = __cs_inode_ctx_update(this, fd->inode, val); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, 0, "ctx update failed"); +@@ -831,7 +811,7 @@ out: + return 0; + } + +-void * ++int + cs_download_task(void *arg) + { + call_frame_t *frame = NULL; +@@ -842,7 +822,6 @@ cs_download_task(void *arg) + fd_t *fd = NULL; + cs_local_t *local = NULL; + dict_t *dict = NULL; +- int *retval = NULL; + + frame = (call_frame_t *)arg; + +@@ -850,13 +829,6 @@ cs_download_task(void *arg) + + priv = this->private; + +- retval = GF_CALLOC(1, sizeof(int), gf_common_mt_int); +- if (!retval) { +- gf_msg(this->name, GF_LOG_ERROR, 0, 0, "insufficient memory"); +- ret = -1; +- goto out; +- } +- + if (!priv->stores) { + gf_msg(this->name, GF_LOG_ERROR, 0, 0, + "No remote store " +@@ -972,20 +944,13 @@ out: + local->dlfd = NULL; + } + +- if (retval) { +- *retval = ret; +- pthread_exit(retval); +- } else { +- pthread_exit(&ret); +- } ++ return ret; + } + + int + cs_download(call_frame_t *frame) + { +- int *retval = NULL; + int ret = 0; +- pthread_t dthread; + cs_local_t *local = NULL; + xlator_t *this = NULL; + +@@ -1000,16 +965,406 @@ cs_download(call_frame_t *frame) + goto out; + } + +- ret = gf_thread_create(&dthread, NULL, &cs_download_task, (void *)frame, +- "downloadthread"); ++ ret = cs_download_task((void *)frame); ++out: ++ return ret; ++} + +- pthread_join(dthread, (void **)&retval); ++int ++cs_set_xattr_req(call_frame_t *frame) ++{ ++ cs_local_t *local = NULL; ++ GF_UNUSED int ret = 0; ++ ++ local = frame->local; ++ ++ /* When remote reads are performed (i.e. reads on remote store), ++ * there needs to be a way to associate a file on gluster volume ++ * with its correspnding file on the remote store. In order to do ++ * that, a unique key can be maintained as an xattr ++ * (GF_CS_XATTR_ARCHIVE_UUID)on the stub file on gluster bricks. ++ * This xattr should be provided to the plugin to ++ * perform the read fop on the correct file. This assumes that the file ++ * hierarchy and name need not be the same on remote store as that of ++ * the gluster volume. ++ */ ++ ret = dict_set_str(local->xattr_req, GF_CS_XATTR_ARCHIVE_UUID, "1"); ++ ++ return 0; ++} + +- ret = *retval; ++int ++cs_update_xattrs(call_frame_t *frame, dict_t *xdata) ++{ ++ cs_local_t *local = NULL; ++ xlator_t *this = NULL; ++ int size = -1; ++ GF_UNUSED int ret = 0; ++ ++ local = frame->local; ++ this = frame->this; ++ ++ local->xattrinfo.lxattr = GF_CALLOC(1, sizeof(cs_loc_xattr_t), ++ gf_cs_mt_cs_lxattr_t); ++ if (!local->xattrinfo.lxattr) { ++ local->op_ret = -1; ++ local->op_errno = ENOMEM; ++ goto err; ++ } ++ ++ gf_uuid_copy(local->xattrinfo.lxattr->gfid, local->loc.gfid); ++ ++ if (local->remotepath) { ++ local->xattrinfo.lxattr->file_path = gf_strdup(local->remotepath); ++ if (!local->xattrinfo.lxattr->file_path) { ++ local->op_ret = -1; ++ local->op_errno = ENOMEM; ++ goto err; ++ } ++ } ++ ++ ret = dict_get_gfuuid(xdata, GF_CS_XATTR_ARCHIVE_UUID, ++ &(local->xattrinfo.lxattr->uuid)); ++ ++ if (ret) { ++ gf_uuid_clear(local->xattrinfo.lxattr->uuid); ++ } ++ size = strlen(this->name) - strlen("-cloudsync") + 1; ++ local->xattrinfo.lxattr->volname = GF_CALLOC(1, size, gf_common_mt_char); ++ if (!local->xattrinfo.lxattr->volname) { ++ local->op_ret = -1; ++ local->op_errno = ENOMEM; ++ goto err; ++ } ++ strncpy(local->xattrinfo.lxattr->volname, this->name, size - 1); ++ local->xattrinfo.lxattr->volname[size - 1] = '\0'; ++ ++ return 0; ++err: ++ cs_xattrinfo_wipe(local); ++ return -1; ++} ++ ++int ++cs_serve_readv(call_frame_t *frame, off_t offset, size_t size, uint32_t flags) ++{ ++ xlator_t *this = NULL; ++ cs_private_t *priv = NULL; ++ int ret = -1; ++ fd_t *fd = NULL; ++ cs_local_t *local = NULL; ++ ++ local = frame->local; ++ this = frame->this; ++ priv = this->private; ++ ++ if (!local->remotepath) { ++ ret = -1; ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "remote path not" ++ " available. Check posix logs to resolve"); ++ goto out; ++ } ++ ++ if (!priv->stores) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "No remote store " ++ "plugins found"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (local->fd) { ++ fd = fd_anonymous(local->fd->inode); ++ } else { ++ fd = fd_anonymous(local->loc.inode); ++ } ++ ++ local->xattrinfo.size = size; ++ local->xattrinfo.offset = offset; ++ local->xattrinfo.flags = flags; ++ ++ if (!fd) { ++ gf_msg("CS", GF_LOG_ERROR, 0, 0, "fd creation failed"); ++ ret = -1; ++ goto out; ++ } ++ ++ local->dlfd = fd; ++ local->dloffset = offset; ++ ++ /*this calling method is for per volume setting */ ++ ret = priv->stores->rdfop(frame, priv->stores->config); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "read failed" ++ ", remotepath: %s", ++ local->remotepath); ++ ret = -1; ++ goto out; ++ } else { ++ gf_msg(this->name, GF_LOG_INFO, 0, 0, ++ "read success, path" ++ " : %s", ++ local->remotepath); ++ } + + out: +- if (retval) +- GF_FREE(retval); ++ if (fd) { ++ fd_unref(fd); ++ local->dlfd = NULL; ++ } ++ return ret; ++} ++ ++int32_t ++cs_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, ++ int32_t op_errno, struct iovec *vector, int32_t count, ++ struct iatt *stbuf, struct iobref *iobref, dict_t *xdata) ++{ ++ cs_local_t *local = NULL; ++ int ret = 0; ++ uint64_t val = 0; ++ fd_t *fd = NULL; ++ ++ local = frame->local; ++ fd = local->fd; ++ ++ local->call_cnt++; ++ ++ if (op_ret == -1) { ++ ret = dict_get_uint64(xdata, GF_CS_OBJECT_STATUS, &val); ++ if (ret == 0) { ++ if (val == GF_CS_ERROR) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "could not get file state, unwinding"); ++ op_ret = -1; ++ op_errno = EIO; ++ goto unwind; ++ } else { ++ __cs_inode_ctx_update(this, fd->inode, val); ++ gf_msg(this->name, GF_LOG_INFO, 0, 0, " state = %" PRIu64, val); ++ ++ if (local->call_cnt == 1 && ++ (val == GF_CS_REMOTE || val == GF_CS_DOWNLOADING)) { ++ gf_msg(this->name, GF_LOG_INFO, 0, 0, ++ " will read from remote : %" PRIu64, val); ++ goto repair; ++ } else { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "second readv, Unwinding"); ++ goto unwind; ++ } ++ } ++ } else { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "file state " ++ "could not be figured, unwinding"); ++ goto unwind; ++ } ++ } else { ++ /* successful readv => file is local */ ++ __cs_inode_ctx_update(this, fd->inode, GF_CS_LOCAL); ++ gf_msg(this->name, GF_LOG_INFO, 0, 0, ++ "state : GF_CS_LOCAL" ++ ", readv successful"); ++ ++ goto unwind; ++ } ++ ++repair: ++ ret = locate_and_execute(frame); ++ if (ret) { ++ goto unwind; ++ } ++ ++ return 0; ++ ++unwind: ++ CS_STACK_UNWIND(readv, frame, op_ret, op_errno, vector, count, stbuf, ++ iobref, xdata); ++ ++ return 0; ++} ++ ++int32_t ++cs_resume_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, ++ off_t offset, uint32_t flags, dict_t *xdata) ++{ ++ int ret = 0; ++ ++ ret = cs_resume_postprocess(this, frame, fd->inode); ++ if (ret) { ++ goto unwind; ++ } ++ ++ cs_inodelk_unlock(frame); ++ ++ STACK_WIND(frame, cs_readv_cbk, FIRST_CHILD(this), ++ FIRST_CHILD(this)->fops->readv, fd, size, offset, flags, xdata); ++ ++ return 0; ++ ++unwind: ++ cs_inodelk_unlock(frame); ++ ++ cs_common_cbk(frame); ++ ++ return 0; ++} ++ ++int32_t ++cs_resume_remote_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, ++ size_t size, off_t offset, uint32_t flags, dict_t *xdata) ++{ ++ int ret = 0; ++ cs_local_t *local = NULL; ++ gf_cs_obj_state state = -1; ++ cs_inode_ctx_t *ctx = NULL; ++ ++ cs_inodelk_unlock(frame); ++ ++ local = frame->local; ++ if (!local) { ++ ret = -1; ++ goto unwind; ++ } ++ ++ __cs_inode_ctx_get(this, fd->inode, &ctx); ++ ++ state = __cs_get_file_state(this, fd->inode, ctx); ++ if (state == GF_CS_ERROR) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "status is GF_CS_ERROR." ++ " Aborting readv"); ++ local->op_ret = -1; ++ local->op_errno = EREMOTE; ++ ret = -1; ++ goto unwind; ++ } ++ ++ /* Serve readv from remote store only if it is remote. */ ++ gf_msg_debug(this->name, 0, "status of file %s is %d", ++ local->remotepath ? local->remotepath : "", state); ++ ++ /* We will reach this condition if local inode ctx had REMOTE ++ * state when the control was in cs_readv but after stat ++ * we got an updated state saying that the file is LOCAL. ++ */ ++ if (state == GF_CS_LOCAL) { ++ STACK_WIND(frame, cs_readv_cbk, FIRST_CHILD(this), ++ FIRST_CHILD(this)->fops->readv, fd, size, offset, flags, ++ xdata); ++ } else if (state == GF_CS_REMOTE) { ++ ret = cs_resume_remote_readv_postprocess(this, frame, fd->inode, offset, ++ size, flags); ++ /* Failed to submit the remote readv fop to plugin */ ++ if (ret) { ++ local->op_ret = -1; ++ local->op_errno = EREMOTE; ++ goto unwind; ++ } ++ /* When the file is in any other intermediate state, ++ * we should not perform remote reads. ++ */ ++ } else { ++ local->op_ret = -1; ++ local->op_errno = EINVAL; ++ goto unwind; ++ } ++ ++ return 0; ++ ++unwind: ++ cs_common_cbk(frame); ++ ++ return 0; ++} ++ ++int32_t ++cs_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, ++ off_t offset, uint32_t flags, dict_t *xdata) ++{ ++ int op_errno = -1; ++ cs_local_t *local = NULL; ++ int ret = 0; ++ cs_inode_ctx_t *ctx = NULL; ++ gf_cs_obj_state state = -1; ++ cs_private_t *priv = NULL; ++ ++ VALIDATE_OR_GOTO(frame, err); ++ VALIDATE_OR_GOTO(this, err); ++ VALIDATE_OR_GOTO(fd, err); ++ ++ priv = this->private; ++ ++ local = cs_local_init(this, frame, NULL, fd, GF_FOP_READ); ++ if (!local) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, "local init failed"); ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ __cs_inode_ctx_get(this, fd->inode, &ctx); ++ ++ if (ctx) ++ state = __cs_get_file_state(this, fd->inode, ctx); ++ else ++ state = GF_CS_LOCAL; ++ ++ local->xattr_req = xdata ? dict_ref(xdata) : (xdata = dict_new()); ++ ++ ret = dict_set_uint32(local->xattr_req, GF_CS_OBJECT_STATUS, 1); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "dict_set failed key:" ++ " %s", ++ GF_CS_OBJECT_STATUS); ++ goto err; ++ } ++ ++ if (priv->remote_read) { ++ local->stub = fop_readv_stub(frame, cs_resume_remote_readv, fd, size, ++ offset, flags, xdata); ++ } else { ++ local->stub = fop_readv_stub(frame, cs_resume_readv, fd, size, offset, ++ flags, xdata); ++ } ++ if (!local->stub) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, "insufficient memory"); ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ if (state == GF_CS_LOCAL) { ++ STACK_WIND(frame, cs_readv_cbk, FIRST_CHILD(this), ++ FIRST_CHILD(this)->fops->readv, fd, size, offset, flags, ++ xdata); ++ } else { ++ local->call_cnt++; ++ ret = locate_and_execute(frame); ++ if (ret) { ++ op_errno = ENOMEM; ++ goto err; ++ } ++ } ++ ++ return 0; ++ ++err: ++ CS_STACK_UNWIND(readv, frame, -1, op_errno, NULL, -1, NULL, NULL, NULL); ++ ++ return 0; ++} ++ ++int ++cs_resume_remote_readv_postprocess(xlator_t *this, call_frame_t *frame, ++ inode_t *inode, off_t offset, size_t size, ++ uint32_t flags) ++{ ++ int ret = 0; ++ ++ ret = cs_serve_readv(frame, offset, size, flags); + + return ret; + } +@@ -1059,7 +1414,7 @@ cs_stat_check_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + goto err; + } else { + ret = __cs_inode_ctx_update(this, inode, val); +- gf_msg_debug(this->name, 0, "status : %lu", val); ++ gf_msg_debug(this->name, 0, "status : %" PRIu64, val); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, 0, "ctx update failed"); + local->op_ret = -1; +@@ -1087,6 +1442,10 @@ cs_stat_check_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + gf_msg_debug(this->name, 0, "NULL filepath"); + } + ++ ret = cs_update_xattrs(frame, xdata); ++ if (ret) ++ goto err; ++ + local->op_ret = 0; + local->xattr_rsp = dict_ref(xdata); + memcpy(&local->stbuf, stbuf, sizeof(struct iatt)); +@@ -1121,6 +1480,8 @@ cs_do_stat_check(call_frame_t *main_frame) + goto err; + } + ++ cs_set_xattr_req(main_frame); ++ + if (local->fd) { + STACK_WIND(main_frame, cs_stat_check_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fstat, local->fd, local->xattr_req); +@@ -1177,6 +1538,10 @@ cs_common_cbk(call_frame_t *frame) + NULL, NULL, NULL); + break; + ++ case GF_FOP_TRUNCATE: ++ CS_STACK_UNWIND(truncate, frame, local->op_ret, local->op_errno, ++ NULL, NULL, NULL); ++ break; + default: + break; + } +@@ -1427,7 +1792,7 @@ __cs_inode_ctx_get(xlator_t *this, inode_t *inode, cs_inode_ctx_t **ctx) + if (ret) + *ctx = NULL; + else +- *ctx = (cs_inode_ctx_t *)ctxint; ++ *ctx = (cs_inode_ctx_t *)(uintptr_t)ctxint; + + return; + } +@@ -1452,7 +1817,7 @@ __cs_inode_ctx_update(xlator_t *this, inode_t *inode, uint64_t val) + + ctx->state = val; + +- ctxint = (uint64_t)ctx; ++ ctxint = (uint64_t)(uintptr_t)ctx; + + ret = __inode_ctx_set(inode, this, &ctxint); + if (ret) { +@@ -1460,7 +1825,7 @@ __cs_inode_ctx_update(xlator_t *this, inode_t *inode, uint64_t val) + goto out; + } + } else { +- ctx = (cs_inode_ctx_t *)ctxint; ++ ctx = (cs_inode_ctx_t *)(uintptr_t)ctxint; + + ctx->state = val; + } +@@ -1483,7 +1848,7 @@ cs_inode_ctx_reset(xlator_t *this, inode_t *inode) + return 0; + } + +- ctx = (cs_inode_ctx_t *)ctxint; ++ ctx = (cs_inode_ctx_t *)(uintptr_t)ctxint; + + GF_FREE(ctx); + return 0; +@@ -1532,6 +1897,57 @@ cs_resume_postprocess(xlator_t *this, call_frame_t *frame, inode_t *inode) + out: + return ret; + } ++ ++int32_t ++__cs_get_dict_str(char **str, dict_t *xattr, const char *name, int *errnum) ++{ ++ data_t *data = NULL; ++ int ret = -1; ++ ++ assert(str != NULL); ++ ++ data = dict_get(xattr, (char *)name); ++ if (!data) { ++ *errnum = ENODATA; ++ goto out; ++ } ++ ++ *str = GF_CALLOC(data->len + 1, sizeof(char), gf_common_mt_char); ++ if (!(*str)) { ++ *errnum = ENOMEM; ++ goto out; ++ } ++ ++ memcpy(*str, data->data, sizeof(char) * (data->len)); ++ return 0; ++ ++out: ++ return ret; ++} ++ ++int32_t ++__cs_get_dict_uuid(uuid_t uuid, dict_t *xattr, const char *name, int *errnum) ++{ ++ data_t *data = NULL; ++ int ret = -1; ++ ++ assert(uuid != NULL); ++ ++ data = dict_get(xattr, (char *)name); ++ if (!data) { ++ *errnum = ENODATA; ++ goto out; ++ } ++ ++ assert(data->len == sizeof(uuid_t)); ++ ++ gf_uuid_copy(uuid, (unsigned char *)data->data); ++ return 0; ++ ++out: ++ return ret; ++} ++ + int32_t + cs_fdctx_to_dict(xlator_t *this, fd_t *fd, dict_t *dict) + { +@@ -1606,7 +2022,6 @@ cs_notify(xlator_t *this, int event, void *data, ...) + + struct xlator_fops cs_fops = { + .stat = cs_stat, +- .readdirp = cs_readdirp, + .truncate = cs_truncate, + .seek = cs_seek, + .statfs = cs_statfs, +@@ -1627,7 +2042,9 @@ struct xlator_fops cs_fops = { + .zerofill = cs_zerofill, + }; + +-struct xlator_cbks cs_cbks = {}; ++struct xlator_cbks cs_cbks = { ++ .forget = cs_forget, ++}; + + struct xlator_dumpops cs_dumpops = { + .fdctx_to_dict = cs_fdctx_to_dict, +@@ -1647,6 +2064,15 @@ struct volume_options cs_options[] = { + {.key = {"cloudsync-storetype"}, + .type = GF_OPTION_TYPE_STR, + .description = "Defines which remote store is enabled"}, ++ {.key = {"cloudsync-remote-read"}, ++ .type = GF_OPTION_TYPE_BOOL, ++ .description = "Defines a remote read fop when on"}, ++ {.key = {"cloudsync-store-id"}, ++ .type = GF_OPTION_TYPE_STR, ++ .description = "Defines a volume wide store id"}, ++ {.key = {"cloudsync-product-id"}, ++ .type = GF_OPTION_TYPE_STR, ++ .description = "Defines a volume wide product id"}, + {.key = {NULL}}, + }; + +diff --git a/xlators/features/cloudsync/src/cloudsync.h b/xlators/features/cloudsync/src/cloudsync.h +index dbdb207..0cb800a 100644 +--- a/xlators/features/cloudsync/src/cloudsync.h ++++ b/xlators/features/cloudsync/src/cloudsync.h +@@ -19,6 +19,7 @@ + #include "cloudsync-common.h" + #include "cloudsync-autogen-fops.h" + ++#define ALIGN_SIZE 4096 + #define CS_LOCK_DOMAIN "cs.protect.file.stat" + typedef struct cs_dlstore { + off_t off; +@@ -29,6 +30,7 @@ typedef struct cs_dlstore { + } cs_dlstore; + + typedef struct cs_inode_ctx { ++ cs_loc_xattr_t locxattr; + gf_cs_obj_state state; + } cs_inode_ctx_t; + +@@ -100,4 +102,22 @@ cs_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t + cs_resume_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, + off_t offset, dict_t *xattr_req); ++ ++int32_t ++cs_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, ++ int32_t op_errno, struct iovec *vector, int32_t count, ++ struct iatt *stbuf, struct iobref *iobref, dict_t *xdata); ++int32_t ++cs_resume_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, ++ off_t offset, uint32_t flags, dict_t *xdata); ++int32_t ++cs_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, ++ off_t offset, uint32_t flags, dict_t *xdata); ++ ++int ++cs_resume_remote_readv_postprocess(xlator_t *this, call_frame_t *frame, ++ inode_t *inode, off_t offset, size_t size, ++ uint32_t flags); ++int ++cs_serve_readv(call_frame_t *frame, off_t offset, size_t size, uint32_t flags); + #endif /* __CLOUDSYNC_H__ */ +diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c +index 4b32fb6..73abf37 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c ++++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c +@@ -3693,7 +3693,7 @@ struct volopt_map_entry glusterd_volopt_map[] = { + .op_version = GD_OP_VERSION_5_0, + .description = "enable/disable noatime option with ctime enabled.", + .flags = VOLOPT_FLAG_CLIENT_OPT | VOLOPT_FLAG_XLATOR_OPT}, +- {.key = "feature.cloudsync-storetype", ++ {.key = "features.cloudsync-storetype", + .voltype = "features/cloudsync", + .op_version = GD_OP_VERSION_5_0, + .flags = VOLOPT_FLAG_CLIENT_OPT}, +@@ -3721,4 +3721,9 @@ struct volopt_map_entry glusterd_volopt_map[] = { + .validate_fn = validate_boolean, + .description = "option to enforce mandatory lock on a file", + .flags = VOLOPT_FLAG_XLATOR_OPT}, ++ {.key = "features.cloudsync-remote-read", ++ .voltype = "features/cloudsync", ++ .value = "off", ++ .op_version = GD_OP_VERSION_6_0, ++ .flags = VOLOPT_FLAG_CLIENT_OPT}, + {.key = NULL}}; +-- +1.8.3.1 + diff --git a/0154-cloudsync-cvlt-Cloudsync-plugin-for-commvault-store.patch b/0154-cloudsync-cvlt-Cloudsync-plugin-for-commvault-store.patch new file mode 100644 index 0000000..6068678 --- /dev/null +++ b/0154-cloudsync-cvlt-Cloudsync-plugin-for-commvault-store.patch @@ -0,0 +1,1394 @@ +From b402b89f71a3ebabca24c459f106af1f9610939a Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Fri, 30 Nov 2018 11:23:07 -0800 +Subject: [PATCH 154/169] cloudsync/cvlt: Cloudsync plugin for commvault store + +backport of: https://review.gluster.org/#/c/glusterfs/+/21771/ + +> Change-Id: Icbe53e78e9c4f6699c7a26a806ef4b14b39f5019 +> updates: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: Ib543605daa51fa1cfe77ed475390a30ef14e6452 +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172194 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + configure.ac | 13 + + glusterfs.spec.in | 1 + + libglusterfs/src/glusterfs/glfs-message-id.h | 1 + + .../src/cloudsync-plugins/src/Makefile.am | 6 +- + .../src/cloudsync-plugins/src/cvlt/Makefile.am | 3 + + .../src/cloudsync-plugins/src/cvlt/src/Makefile.am | 12 + + .../cloudsync-plugins/src/cvlt/src/archivestore.h | 203 +++++ + .../cloudsync-plugins/src/cvlt/src/cvlt-messages.h | 30 + + .../src/cvlt/src/libcloudsynccvlt.sym | 1 + + .../src/cvlt/src/libcvlt-mem-types.h | 19 + + .../src/cloudsync-plugins/src/cvlt/src/libcvlt.c | 842 +++++++++++++++++++++ + .../src/cloudsync-plugins/src/cvlt/src/libcvlt.h | 84 ++ + xlators/features/cloudsync/src/cloudsync.c | 6 +- + xlators/mgmt/glusterd/src/glusterd-volume-set.c | 10 +- + 14 files changed, 1228 insertions(+), 3 deletions(-) + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/Makefile.am + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/Makefile.am + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/archivestore.h + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/cvlt-messages.h + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcloudsynccvlt.sym + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt-mem-types.h + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.c + create mode 100644 xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.h + +diff --git a/configure.ac b/configure.ac +index 0e11d4c..f597b86 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -170,6 +170,8 @@ AC_CONFIG_FILES([Makefile + xlators/features/cloudsync/src/cloudsync-plugins/src/Makefile + xlators/features/cloudsync/src/cloudsync-plugins/src/cloudsyncs3/Makefile + xlators/features/cloudsync/src/cloudsync-plugins/src/cloudsyncs3/src/Makefile ++ xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/Makefile ++ xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/Makefile + xlators/playground/Makefile + xlators/playground/template/Makefile + xlators/playground/template/src/Makefile +@@ -937,6 +939,17 @@ AM_CONDITIONAL([BUILD_AMAZONS3_PLUGIN], [test "x$HAVE_AMAZONS3" = "xyes"]) + if test "x$HAVE_AMAZONS3" = "xyes";then + BUILD_CLOUDSYNC="yes" + fi ++BUILD_CVLT_PLUGIN="no" ++case $host_os in ++#enable cvlt plugin only for linux platforms ++ linux*) ++ BUILD_CVLT_PLUGIN="yes" ++ BUILD_CLOUDSYNC="yes" ++ ;; ++ *) ++ ;; ++esac ++AM_CONDITIONAL([BUILD_CVLT_PLUGIN], [test "x$BUILD_CVLT_PLUGIN" = "xyes"]) + AM_CONDITIONAL([BUILD_CLOUDSYNC], [test "x$BUILD_CLOUDSYNC" = "xyes"]) + dnl end cloudsync section + +diff --git a/glusterfs.spec.in b/glusterfs.spec.in +index ed58356..85e75f2 100644 +--- a/glusterfs.spec.in ++++ b/glusterfs.spec.in +@@ -1199,6 +1199,7 @@ exit 0 + %files cloudsync-plugins + %dir %{_libdir}/glusterfs/%{version}%{?prereltag}/cloudsync-plugins + %{_libdir}/glusterfs/%{version}%{?prereltag}/cloudsync-plugins/cloudsyncs3.so ++ %{_libdir}/glusterfs/%{version}%{?prereltag}/cloudsync-plugins/cloudsynccvlt.so + + %files devel + %dir %{_includedir}/glusterfs +diff --git a/libglusterfs/src/glusterfs/glfs-message-id.h b/libglusterfs/src/glusterfs/glfs-message-id.h +index 001f4ab..a1a16ca 100644 +--- a/libglusterfs/src/glusterfs/glfs-message-id.h ++++ b/libglusterfs/src/glusterfs/glfs-message-id.h +@@ -93,6 +93,7 @@ enum _msgid_comp { + GLFS_MSGID_COMP(TEMPLATE, 1), + GLFS_MSGID_COMP(UTIME, 1), + GLFS_MSGID_COMP(SNAPVIEW_SERVER, 1), ++ GLFS_MSGID_COMP(CVLT, 1), + /* --- new segments for messages goes above this line --- */ + + GLFS_MSGID_END +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/Makefile.am b/xlators/features/cloudsync/src/cloudsync-plugins/src/Makefile.am +index 4deefb6..fb6b058 100644 +--- a/xlators/features/cloudsync/src/cloudsync-plugins/src/Makefile.am ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/Makefile.am +@@ -2,6 +2,10 @@ if BUILD_AMAZONS3_PLUGIN + AMAZONS3_DIR = cloudsyncs3 + endif + +-SUBDIRS = ${AMAZONS3_DIR} ++if BUILD_CVLT_PLUGIN ++ CVLT_DIR = cvlt ++endif ++ ++SUBDIRS = ${AMAZONS3_DIR} ${CVLT_DIR} + + CLEANFILES = +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/Makefile.am b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/Makefile.am +new file mode 100644 +index 0000000..a985f42 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/Makefile.am +@@ -0,0 +1,3 @@ ++SUBDIRS = src ++ ++CLEANFILES = +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/Makefile.am b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/Makefile.am +new file mode 100644 +index 0000000..b512464 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/Makefile.am +@@ -0,0 +1,12 @@ ++csp_LTLIBRARIES = cloudsynccvlt.la ++cspdir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/cloudsync-plugins ++ ++cloudsynccvlt_la_SOURCES = libcvlt.c $(top_srcdir)/xlators/features/cloudsync/src/cloudsync-common.c ++cloudsynccvlt_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la ++cloudsynccvlt_la_LDFLAGS = -module -avoid-version -export-symbols $(top_srcdir)/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcloudsynccvlt.sym ++AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src ++noinst_HEADERS = archivestore.h libcvlt.h libcvlt-mem-types.h cvlt-messages.h ++AM_CFLAGS = -Wall -fno-strict-aliasing $(GF_CFLAGS) -I$(top_srcdir)/xlators/features/cloudsync/src ++CLEANFILES = ++ ++EXTRA_DIST = libcloudsynccvlt.sym +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/archivestore.h b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/archivestore.h +new file mode 100644 +index 0000000..7230ef7 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/archivestore.h +@@ -0,0 +1,203 @@ ++/* ++ Copyright (c) 2018 Commvault Systems, Inc. ++ This file is part of GlusterFS. ++ ++ This file is licensed to you under your choice of the GNU Lesser ++ General Public License, version 3 or any later version (LGPLv3 or ++ later), or the GNU General Public License, version 2 (GPLv2), in all ++ cases as published by the Free Software Foundation. ++*/ ++ ++#ifndef __ARCHIVESTORE_H__ ++#define __ARCHIVESTORE_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define CS_XATTR_ARCHIVE_UUID "trusted.cloudsync.uuid" ++#define CS_XATTR_PRODUCT_ID "trusted.cloudsync.product-id" ++#define CS_XATTR_STORE_ID "trusted.cloudsync.store-id" ++ ++struct _archstore_methods; ++typedef struct _archstore_methods archstore_methods_t; ++ ++struct _archstore_desc { ++ void *priv; /* Private field for store mgmt. */ ++ /* To be used only by archive store*/ ++}; ++typedef struct _archstore_desc archstore_desc_t; ++ ++struct _archstore_info { ++ char *id; /* Identifier for the archivestore */ ++ uint32_t idlen; /* Length of identifier string */ ++ char *prod; /* Name of the data mgmt. product */ ++ uint32_t prodlen; /* Length of the product string */ ++}; ++typedef struct _archstore_info archstore_info_t; ++ ++struct _archstore_fileinfo { ++ uuid_t uuid; /* uuid of the file */ ++ char *path; /* file path */ ++ uint32_t pathlength; /* length of file path */ ++}; ++typedef struct _archstore_fileinfo archstore_fileinfo_t; ++ ++struct _app_callback_info { ++ archstore_info_t *src_archstore; ++ archstore_fileinfo_t *src_archfile; ++ archstore_info_t *dest_archstore; ++ archstore_fileinfo_t *dest_archfile; ++}; ++typedef struct _app_callback_info app_callback_info_t; ++ ++typedef void (*app_callback_t)(archstore_desc_t *, app_callback_info_t *, ++ void *, int64_t, int32_t); ++ ++enum _archstore_scan_type { FULL = 1, INCREMENTAL = 2 }; ++typedef enum _archstore_scan_type archstore_scan_type_t; ++ ++typedef int32_t archstore_errno_t; ++ ++/* ++ * Initialize archive store. ++ * arg1 pointer to structure containing archive store information ++ * arg2 error number if any generated during the initialization ++ * arg3 name of the log file ++ */ ++typedef int32_t (*init_archstore_t)(archstore_desc_t *, archstore_errno_t *, ++ const char *); ++ ++/* ++ * Clean up archive store. ++ * arg1 pointer to structure containing archive store information ++ * arg2 error number if any generated during the cleanup ++ */ ++typedef int32_t (*term_archstore_t)(archstore_desc_t *, archstore_errno_t *); ++ ++/* ++ * Read the contents of the file from archive store ++ * arg1 pointer to structure containing archive store description ++ * arg2 pointer to structure containing archive store information ++ * arg3 pointer to structure containing information about file to be read ++ * arg4 offset in the file from which data should be read ++ * arg5 buffer where the data should be read ++ * arg6 number of bytes of data to be read ++ * arg7 error number if any generated during the read from file ++ * arg8 callback handler to be invoked after the data is read ++ * arg9 cookie to be passed when callback is invoked ++ */ ++typedef int32_t (*read_archstore_t)(archstore_desc_t *, archstore_info_t *, ++ archstore_fileinfo_t *, off_t, char *, ++ size_t, archstore_errno_t *, app_callback_t, ++ void *); ++ ++/* ++ * Restore the contents of the file from archive store ++ * This is basically in-place restore ++ * arg1 pointer to structure containing archive store description ++ * arg2 pointer to structure containing archive store information ++ * arg3 pointer to structure containing information about file to be restored ++ * arg4 error number if any generated during the file restore ++ * arg5 callback to be invoked after the file is restored ++ * arg6 cookie to be passed when callback is invoked ++ */ ++typedef int32_t (*recall_archstore_t)(archstore_desc_t *, archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_errno_t *, app_callback_t, ++ void *); ++ ++/* ++ * Restore the contents of the file from archive store to a different store ++ * This is basically out-of-place restore ++ * arg1 pointer to structure containing archive store description ++ * arg2 pointer to structure containing source archive store information ++ * arg3 pointer to structure containing information about file to be restored ++ * arg4 pointer to structure containing destination archive store information ++ * arg5 pointer to structure containing information about the location to ++ which the file will be restored ++ * arg6 error number if any generated during the file restore ++ * arg7 callback to be invoked after the file is restored ++ * arg8 cookie to be passed when callback is invoked ++ */ ++typedef int32_t (*restore_archstore_t)(archstore_desc_t *, archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_errno_t *, app_callback_t, ++ void *); ++ ++/* ++ * Archive the contents of the file to archive store ++ * arg1 pointer to structure containing archive store description ++ * arg2 pointer to structure containing source archive store information ++ * arg3 pointer to structure containing information about files to be archived ++ * arg4 pointer to structure containing destination archive store information ++ * arg5 pointer to structure containing information about files that failed ++ * to be archived ++ * arg6 error number if any generated during the file archival ++ * arg7 callback to be invoked after the file is archived ++ * arg8 cookie to be passed when callback is invoked ++ */ ++typedef int32_t (*archive_archstore_t)(archstore_desc_t *, archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_errno_t *, app_callback_t, ++ void *); ++ ++/* ++ * Backup list of files provided in the input file ++ * arg1 pointer to structure containing archive store description ++ * arg2 pointer to structure containing source archive store information ++ * arg3 pointer to structure containing information about files to be backed up ++ * arg4 pointer to structure containing destination archive store information ++ * arg5 pointer to structure containing information about files that failed ++ * to be backed up ++ * arg6 error number if any generated during the file archival ++ * arg7 callback to be invoked after the file is archived ++ * arg8 cookie to be passed when callback is invoked ++ */ ++typedef int32_t (*backup_archstore_t)(archstore_desc_t *, archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_info_t *, ++ archstore_fileinfo_t *, ++ archstore_errno_t *, app_callback_t, ++ void *); ++ ++/* ++ * Scan the contents of a store and determine the files which need to be ++ * backed up. ++ * arg1 pointer to structure containing archive store description ++ * arg2 pointer to structure containing archive store information ++ * arg3 type of scan whether full or incremental ++ * arg4 path to file that contains list of files to be backed up ++ * arg5 error number if any generated during scan operation ++ */ ++typedef int32_t (*scan_archstore_t)(archstore_desc_t *, archstore_info_t *, ++ archstore_scan_type_t, char *, ++ archstore_errno_t *); ++ ++struct _archstore_methods { ++ init_archstore_t init; ++ term_archstore_t fini; ++ backup_archstore_t backup; ++ archive_archstore_t archive; ++ scan_archstore_t scan; ++ restore_archstore_t restore; ++ recall_archstore_t recall; ++ read_archstore_t read; ++}; ++ ++typedef int (*get_archstore_methods_t)(archstore_methods_t *); ++ ++/* ++ * Single function that will be invoked by applications for extracting ++ * the function pointers to all data management functions. ++ */ ++int32_t ++get_archstore_methods(archstore_methods_t *); ++ ++#endif /* End of __ARCHIVESTORE_H__ */ +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/cvlt-messages.h b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/cvlt-messages.h +new file mode 100644 +index 0000000..57c9aa7 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/cvlt-messages.h +@@ -0,0 +1,30 @@ ++/* ++ Copyright (c) 2015 Red Hat, Inc. ++ This file is part of GlusterFS. ++ ++ This file is licensed to you under your choice of the GNU Lesser ++ General Public License, version 3 or any later version (LGPLv3 or ++ later), or the GNU General Public License, version 2 (GPLv2), in all ++ cases as published by the Free Software Foundation. ++ */ ++ ++#ifndef _CVLT_MESSAGES_H_ ++#define _CVLT_MESSAGES_H_ ++ ++#include ++ ++/* To add new message IDs, append new identifiers at the end of the list. ++ * ++ * Never remove a message ID. If it's not used anymore, you can rename it or ++ * leave it as it is, but not delete it. This is to prevent reutilization of ++ * IDs by other messages. ++ * ++ * The component name must match one of the entries defined in ++ * glfs-message-id.h. ++ */ ++ ++GLFS_MSGID(CVLT, CVLT_EXTRACTION_FAILED, CVLT_FREE, ++ CVLT_RESOURCE_ALLOCATION_FAILED, CVLT_RESTORE_FAILED, ++ CVLT_READ_FAILED, CVLT_NO_MEMORY, CVLT_DLOPEN_FAILED); ++ ++#endif /* !_CVLT_MESSAGES_H_ */ +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcloudsynccvlt.sym b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcloudsynccvlt.sym +new file mode 100644 +index 0000000..0bc2736 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcloudsynccvlt.sym +@@ -0,0 +1 @@ ++store_ops +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt-mem-types.h b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt-mem-types.h +new file mode 100644 +index 0000000..c24fab8 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt-mem-types.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (c) 2018 Commvault Systems, Inc. ++ * This file is part of GlusterFS. ++ * ++ * This file is licensed to you under your choice of the GNU Lesser ++ * General Public License, version 3 or any later version (LGPLv3 or ++ * later), or the GNU General Public License, version 2 (GPLv2), in all ++ * cases as published by the Free Software Foundation. ++ */ ++ ++#ifndef __LIBCVLT_MEM_TYPES_H__ ++#define __LIBCVLT_MEM_TYPES_H__ ++ ++#include ++enum libcvlt_mem_types_ { ++ gf_libcvlt_mt_cvlt_private_t = gf_common_mt_end + 1, ++ gf_libcvlt_mt_end ++}; ++#endif /* __LIBCVLT_MEM_TYPES_H__ */ +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.c b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.c +new file mode 100644 +index 0000000..e827882 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.c +@@ -0,0 +1,842 @@ ++#include ++#include ++#include ++#include "libcvlt.h" ++#include "cloudsync-common.h" ++#include "cvlt-messages.h" ++ ++#define LIBARCHIVE_SO "libopenarchive.so" ++#define ALIGN_SIZE 4096 ++#define CVLT_TRAILER "cvltv1" ++ ++store_methods_t store_ops = { ++ .fop_download = cvlt_download, ++ .fop_init = cvlt_init, ++ .fop_reconfigure = cvlt_reconfigure, ++ .fop_fini = cvlt_fini, ++ .fop_remote_read = cvlt_read, ++}; ++ ++static const int32_t num_req = 32; ++static const int32_t num_iatt = 32; ++static char *plugin = "cvlt_cloudSync"; ++ ++int32_t ++mem_acct_init(xlator_t *this) ++{ ++ int ret = -1; ++ ++ if (!this) ++ return ret; ++ ++ ret = xlator_mem_acct_init(this, gf_libcvlt_mt_end + 1); ++ ++ if (ret != 0) { ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static void ++cvlt_free_resources(archive_t *arch) ++{ ++ /* ++ * We will release all the resources that were allocated by the xlator. ++ * Check whether there are any buffers which have not been released ++ * back to a mempool. ++ */ ++ ++ if (arch->handle) { ++ dlclose(arch->handle); ++ } ++ ++ if (arch->iobuf_pool) { ++ iobuf_pool_destroy(arch->iobuf_pool); ++ } ++ ++ if (arch->req_pool) { ++ mem_pool_destroy(arch->req_pool); ++ arch->req_pool = NULL; ++ } ++ ++ return; ++} ++ ++static int32_t ++cvlt_extract_store_fops(xlator_t *this, archive_t *arch) ++{ ++ int32_t op_ret = -1; ++ get_archstore_methods_t get_archstore_methods; ++ ++ /* ++ * libopenarchive.so defines methods for performing data management ++ * operations. We will extract the methods from library and these ++ * methods will be invoked for moving data between glusterfs volume ++ * and the data management product. ++ */ ++ ++ VALIDATE_OR_GOTO(arch, err); ++ ++ arch->handle = dlopen(LIBARCHIVE_SO, RTLD_NOW); ++ if (!arch->handle) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_DLOPEN_FAILED, ++ " failed to open %s ", LIBARCHIVE_SO); ++ return op_ret; ++ } ++ ++ dlerror(); /* Clear any existing error */ ++ ++ get_archstore_methods = dlsym(arch->handle, "get_archstore_methods"); ++ if (!get_archstore_methods) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " Error extracting get_archstore_methods()"); ++ dlclose(arch->handle); ++ arch->handle = NULL; ++ return op_ret; ++ } ++ ++ op_ret = get_archstore_methods(&(arch->fops)); ++ if (op_ret) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " Failed to extract methods in get_archstore_methods"); ++ dlclose(arch->handle); ++ arch->handle = NULL; ++ return op_ret; ++ } ++ ++err: ++ return op_ret; ++} ++ ++static int32_t ++cvlt_alloc_resources(xlator_t *this, archive_t *arch, int num_req, int num_iatt) ++{ ++ /* ++ * Initialize information about all the memory pools that will be ++ * used by this xlator. ++ */ ++ arch->nreqs = 0; ++ ++ arch->req_pool = NULL; ++ ++ arch->handle = NULL; ++ arch->xl = this; ++ ++ arch->req_pool = mem_pool_new(cvlt_request_t, num_req); ++ if (!arch->req_pool) { ++ goto err; ++ } ++ ++ arch->iobuf_pool = iobuf_pool_new(); ++ if (!arch->iobuf_pool) { ++ goto err; ++ } ++ ++ if (cvlt_extract_store_fops(this, arch)) { ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ ++ return -1; ++} ++ ++static void ++cvlt_req_init(cvlt_request_t *req) ++{ ++ sem_init(&(req->sem), 0, 0); ++ ++ return; ++} ++ ++static void ++cvlt_req_destroy(cvlt_request_t *req) ++{ ++ if (req->iobuf) { ++ iobuf_unref(req->iobuf); ++ } ++ ++ if (req->iobref) { ++ iobref_unref(req->iobref); ++ } ++ ++ sem_destroy(&(req->sem)); ++ ++ return; ++} ++ ++static cvlt_request_t * ++cvlt_alloc_req(archive_t *arch) ++{ ++ cvlt_request_t *reqptr = NULL; ++ ++ if (!arch) { ++ goto err; ++ } ++ ++ if (arch->req_pool) { ++ reqptr = mem_get0(arch->req_pool); ++ if (reqptr) { ++ cvlt_req_init(reqptr); ++ } ++ } ++ ++ if (reqptr) { ++ LOCK(&(arch->lock)); ++ arch->nreqs++; ++ UNLOCK(&(arch->lock)); ++ } ++ ++err: ++ return reqptr; ++} ++ ++static int32_t ++cvlt_free_req(archive_t *arch, cvlt_request_t *reqptr) ++{ ++ if (!reqptr) { ++ goto err; ++ } ++ ++ if (!arch) { ++ goto err; ++ } ++ ++ if (arch->req_pool) { ++ /* ++ * Free the request resources if they exist. ++ */ ++ ++ cvlt_req_destroy(reqptr); ++ mem_put(reqptr); ++ ++ LOCK(&(arch->lock)); ++ arch->nreqs--; ++ UNLOCK(&(arch->lock)); ++ } ++ ++ return 0; ++ ++err: ++ return -1; ++} ++ ++static int32_t ++cvlt_init_xlator(xlator_t *this, archive_t *arch, int num_req, int num_iatt) ++{ ++ int32_t ret = -1; ++ int32_t errnum = -1; ++ int32_t locked = 0; ++ ++ /* ++ * Perform all the initializations needed for brining up the xlator. ++ */ ++ if (!arch) { ++ goto err; ++ } ++ ++ LOCK_INIT(&(arch->lock)); ++ LOCK(&(arch->lock)); ++ ++ locked = 1; ++ ++ ret = cvlt_alloc_resources(this, arch, num_req, num_iatt); ++ ++ if (ret) { ++ goto err; ++ } ++ ++ /* ++ * Now that the fops have been extracted initialize the store ++ */ ++ ret = arch->fops.init(&(arch->descinfo), &errnum, plugin); ++ if (ret) { ++ goto err; ++ } ++ ++ UNLOCK(&(arch->lock)); ++ locked = 0; ++ ret = 0; ++ ++ return ret; ++ ++err: ++ cvlt_free_resources(arch); ++ ++ if (locked) { ++ UNLOCK(&(arch->lock)); ++ } ++ ++ return ret; ++} ++ ++static int32_t ++cvlt_term_xlator(archive_t *arch) ++{ ++ int32_t errnum = -1; ++ ++ if (!arch) { ++ goto err; ++ } ++ ++ LOCK(&(arch->lock)); ++ ++ /* ++ * Release the resources that have been allocated inside store ++ */ ++ arch->fops.fini(&(arch->descinfo), &errnum); ++ ++ cvlt_free_resources(arch); ++ ++ UNLOCK(&(arch->lock)); ++ ++ GF_FREE(arch); ++ ++ return 0; ++ ++err: ++ return -1; ++} ++ ++static int32_t ++cvlt_init_store_info(archive_t *priv, archstore_info_t *store_info) ++{ ++ if (!store_info) { ++ return -1; ++ } ++ ++ store_info->prod = priv->product_id; ++ store_info->prodlen = strlen(priv->product_id); ++ ++ store_info->id = priv->store_id; ++ store_info->idlen = strlen(priv->store_id); ++ ++ return 0; ++} ++ ++static int32_t ++cvlt_init_file_info(cs_loc_xattr_t *xattr, archstore_fileinfo_t *file_info) ++{ ++ if (!xattr || !file_info) { ++ return -1; ++ } ++ ++ gf_uuid_copy(file_info->uuid, xattr->uuid); ++ file_info->path = xattr->file_path; ++ file_info->pathlength = strlen(xattr->file_path); ++ ++ return 0; ++} ++ ++static int32_t ++cvlt_init_gluster_store_info(cs_loc_xattr_t *xattr, ++ archstore_info_t *store_info) ++{ ++ static char *product = "glusterfs"; ++ ++ if (!xattr || !store_info) { ++ return -1; ++ } ++ ++ store_info->prod = product; ++ store_info->prodlen = strlen(product); ++ ++ store_info->id = xattr->volname; ++ store_info->idlen = strlen(xattr->volname); ++ ++ return 0; ++} ++ ++static int32_t ++cvlt_init_gluster_file_info(cs_loc_xattr_t *xattr, ++ archstore_fileinfo_t *file_info) ++{ ++ if (!xattr || !file_info) { ++ return -1; ++ } ++ ++ gf_uuid_copy(file_info->uuid, xattr->gfid); ++ file_info->path = xattr->file_path; ++ file_info->pathlength = strlen(xattr->file_path); ++ ++ return 0; ++} ++ ++static void ++cvlt_copy_stat_info(struct iatt *buf, cs_size_xattr_t *xattrs) ++{ ++ /* ++ * If the file was archived then the reported size will not be a ++ * correct one. We need to fix this. ++ */ ++ if (buf && xattrs) { ++ buf->ia_size = xattrs->size; ++ buf->ia_blksize = xattrs->blksize; ++ buf->ia_blocks = xattrs->blocks; ++ } ++ ++ return; ++} ++ ++static void ++cvlt_readv_complete(archstore_desc_t *desc, app_callback_info_t *cbkinfo, ++ void *cookie, int64_t op_ret, int32_t op_errno) ++{ ++ struct iovec iov; ++ xlator_t *this = NULL; ++ struct iatt postbuf = { ++ 0, ++ }; ++ call_frame_t *frame = NULL; ++ cvlt_request_t *req = (cvlt_request_t *)cookie; ++ cs_local_t *local = NULL; ++ cs_private_t *cspriv = NULL; ++ archive_t *priv = NULL; ++ ++ frame = req->frame; ++ this = frame->this; ++ local = frame->local; ++ ++ cspriv = this->private; ++ priv = (archive_t *)cspriv->stores->config; ++ ++ if (strcmp(priv->trailer, CVLT_TRAILER)) { ++ op_ret = -1; ++ op_errno = EINVAL; ++ goto out; ++ } ++ ++ gf_msg_debug(plugin, 0, ++ " Read callback invoked offset:%" PRIu64 "bytes: %" PRIu64 ++ " op : %d ret : %" PRId64 " errno : %d", ++ req->offset, req->bytes, req->op_type, op_ret, op_errno); ++ ++ if (op_ret < 0) { ++ goto out; ++ } ++ ++ req->iobref = iobref_new(); ++ if (!req->iobref) { ++ op_ret = -1; ++ op_errno = ENOMEM; ++ goto out; ++ } ++ ++ iobref_add(req->iobref, req->iobuf); ++ iov.iov_base = iobuf_ptr(req->iobuf); ++ iov.iov_len = op_ret; ++ ++ cvlt_copy_stat_info(&postbuf, &(req->szxattr)); ++ ++ /* ++ * Hack to notify higher layers of EOF. ++ */ ++ if (!postbuf.ia_size || (req->offset + iov.iov_len >= postbuf.ia_size)) { ++ gf_msg_debug(plugin, 0, " signalling end-of-file for uuid=%s", ++ uuid_utoa(req->file_info.uuid)); ++ op_errno = ENOENT; ++ } ++ ++out: ++ ++ STACK_UNWIND_STRICT(readv, frame, op_ret, op_errno, &iov, 1, &postbuf, ++ req->iobref, local->xattr_rsp); ++ ++ if (req) { ++ cvlt_free_req(priv, req); ++ } ++ ++ return; ++} ++ ++static void ++cvlt_download_complete(archstore_desc_t *store, app_callback_info_t *cbk_info, ++ void *cookie, int64_t ret, int errcode) ++{ ++ cvlt_request_t *req = (cvlt_request_t *)cookie; ++ ++ gf_msg_debug(plugin, 0, ++ " Download callback invoked ret : %" PRId64 " errno : %d", ++ ret, errcode); ++ ++ req->op_ret = ret; ++ req->op_errno = errcode; ++ sem_post(&(req->sem)); ++ ++ return; ++} ++ ++void * ++cvlt_init(xlator_t *this) ++{ ++ int ret = 0; ++ archive_t *priv = NULL; ++ ++ if (!this->children || this->children->next) { ++ gf_msg(plugin, GF_LOG_ERROR, ENOMEM, 0, ++ "should have exactly one child"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (!this->parents) { ++ gf_msg(plugin, GF_LOG_ERROR, ENOMEM, 0, ++ "dangling volume. check volfile"); ++ ret = -1; ++ goto out; ++ } ++ ++ priv = GF_CALLOC(1, sizeof(archive_t), gf_libcvlt_mt_cvlt_private_t); ++ if (!priv) { ++ ret = -1; ++ goto out; ++ } ++ ++ priv->trailer = CVLT_TRAILER; ++ if (cvlt_init_xlator(this, priv, num_req, num_iatt)) { ++ gf_msg(plugin, GF_LOG_ERROR, ENOMEM, 0, "xlator init failed"); ++ ret = -1; ++ goto out; ++ } ++ ++ GF_OPTION_INIT("cloudsync-store-id", priv->store_id, str, out); ++ GF_OPTION_INIT("cloudsync-product-id", priv->product_id, str, out); ++ ++ gf_msg(plugin, GF_LOG_INFO, 0, 0, ++ "store id is : %s " ++ "product id is : %s.", ++ priv->store_id, priv->product_id); ++out: ++ if (ret == -1) { ++ cvlt_term_xlator(priv); ++ return (NULL); ++ } ++ return priv; ++} ++ ++int ++cvlt_reconfigure(xlator_t *this, dict_t *options) ++{ ++ cs_private_t *cspriv = NULL; ++ archive_t *priv = NULL; ++ ++ cspriv = this->private; ++ priv = (archive_t *)cspriv->stores->config; ++ ++ if (strcmp(priv->trailer, CVLT_TRAILER)) ++ goto out; ++ ++ GF_OPTION_RECONF("cloudsync-store-id", priv->store_id, options, str, out); ++ ++ GF_OPTION_RECONF("cloudsync-product-id", priv->product_id, options, str, ++ out); ++ gf_msg_debug(plugin, 0, ++ "store id is : %s " ++ "product id is : %s.", ++ priv->store_id, priv->product_id); ++ return 0; ++out: ++ return -1; ++} ++ ++void ++cvlt_fini(void *config) ++{ ++ archive_t *priv = NULL; ++ ++ priv = (archive_t *)config; ++ ++ if (strcmp(priv->trailer, CVLT_TRAILER)) ++ return; ++ ++ cvlt_term_xlator(priv); ++ gf_msg(plugin, GF_LOG_INFO, 0, CVLT_FREE, " released xlator resources"); ++ return; ++} ++ ++int ++cvlt_download(call_frame_t *frame, void *config) ++{ ++ archive_t *parch = NULL; ++ cs_local_t *local = frame->local; ++ cs_loc_xattr_t *locxattr = local->xattrinfo.lxattr; ++ cvlt_request_t *req = NULL; ++ archstore_info_t dest_storeinfo; ++ archstore_fileinfo_t dest_fileinfo; ++ int32_t op_ret, op_errno; ++ ++ parch = (archive_t *)config; ++ ++ if (strcmp(parch->trailer, CVLT_TRAILER)) { ++ op_ret = -1; ++ op_errno = EINVAL; ++ goto err; ++ } ++ ++ gf_msg_debug(plugin, 0, " download invoked for uuid = %s gfid=%s ", ++ locxattr->uuid, uuid_utoa(locxattr->gfid)); ++ ++ if (!(parch->fops.restore)) { ++ op_errno = ELIBBAD; ++ goto err; ++ } ++ ++ /* ++ * Download needs to be processed. Allocate a request. ++ */ ++ req = cvlt_alloc_req(parch); ++ ++ if (!req) { ++ gf_msg(plugin, GF_LOG_ERROR, ENOMEM, CVLT_RESOURCE_ALLOCATION_FAILED, ++ " failed to allocated request for gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ /* ++ * Initialize the request object. ++ */ ++ req->op_type = CVLT_RESTORE_OP; ++ req->frame = frame; ++ ++ /* ++ * The file is currently residing inside a data management store. ++ * To restore the file contents we need to provide the information ++ * about data management store. ++ */ ++ op_ret = cvlt_init_store_info(parch, &(req->store_info)); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " failed to extract store info for gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ op_ret = cvlt_init_file_info(locxattr, &(req->file_info)); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " failed to extract file info for gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ /* ++ * We need t perform in-place restore of the file from data managment ++ * store to gusterfs volume. ++ */ ++ op_ret = cvlt_init_gluster_store_info(locxattr, &dest_storeinfo); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " failed to extract destination store info for gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ op_ret = cvlt_init_gluster_file_info(locxattr, &dest_fileinfo); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " failed to extract file info for gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ /* ++ * Submit the restore request. ++ */ ++ op_ret = parch->fops.restore(&(parch->descinfo), &(req->store_info), ++ &(req->file_info), &dest_storeinfo, ++ &dest_fileinfo, &op_errno, ++ cvlt_download_complete, req); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_RESTORE_FAILED, ++ " failed to restore file gfid=%s from data managment store", ++ uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ /* ++ * Wait for the restore to complete. ++ */ ++ sem_wait(&(req->sem)); ++ ++ if (req->op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_RESTORE_FAILED, ++ " restored failed for gfid=%s", uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ if (req) { ++ cvlt_free_req(parch, req); ++ } ++ ++ return 0; ++ ++err: ++ ++ if (req) { ++ cvlt_free_req(parch, req); ++ } ++ ++ return -1; ++} ++ ++int ++cvlt_read(call_frame_t *frame, void *config) ++{ ++ int32_t op_ret = -1; ++ int32_t op_errno = 0; ++ archive_t *parch = NULL; ++ cvlt_request_t *req = NULL; ++ struct iovec iov = { ++ 0, ++ }; ++ struct iobref *iobref; ++ size_t size = 0; ++ off_t off = 0; ++ ++ cs_local_t *local = frame->local; ++ cs_loc_xattr_t *locxattr = local->xattrinfo.lxattr; ++ ++ size = local->xattrinfo.size; ++ off = local->xattrinfo.offset; ++ ++ parch = (archive_t *)config; ++ ++ if (strcmp(parch->trailer, CVLT_TRAILER)) { ++ op_ret = -1; ++ op_errno = EINVAL; ++ goto err; ++ } ++ ++ gf_msg_debug(plugin, 0, ++ " read invoked for gfid = %s offset = %" PRIu64 ++ " file_size = %" PRIu64, ++ uuid_utoa(locxattr->gfid), off, local->stbuf.ia_size); ++ ++ if (off >= local->stbuf.ia_size) { ++ /* ++ * Hack to notify higher layers of EOF. ++ */ ++ ++ op_errno = ENOENT; ++ op_ret = 0; ++ ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_READ_FAILED, ++ " reporting end-of-file for gfid=%s", uuid_utoa(locxattr->gfid)); ++ ++ goto err; ++ } ++ ++ if (!size) { ++ op_errno = EINVAL; ++ ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_READ_FAILED, ++ " zero size read attempted on gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ goto err; ++ } ++ ++ if (!(parch->fops.read)) { ++ op_errno = ELIBBAD; ++ goto err; ++ } ++ ++ /* ++ * The read request need to be processed. Allocate a request. ++ */ ++ req = cvlt_alloc_req(parch); ++ ++ if (!req) { ++ gf_msg(plugin, GF_LOG_ERROR, ENOMEM, CVLT_NO_MEMORY, ++ " failed to allocated request for gfid=%s", ++ uuid_utoa(locxattr->gfid)); ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ req->iobuf = iobuf_get_page_aligned(parch->iobuf_pool, size, ALIGN_SIZE); ++ if (!req->iobuf) { ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ /* ++ * Initialize the request object. ++ */ ++ req->op_type = CVLT_READ_OP; ++ req->offset = off; ++ req->bytes = size; ++ req->frame = frame; ++ req->szxattr.size = local->stbuf.ia_size; ++ req->szxattr.blocks = local->stbuf.ia_blocks; ++ req->szxattr.blksize = local->stbuf.ia_blksize; ++ ++ /* ++ * The file is currently residing inside a data management store. ++ * To read the file contents we need to provide the information ++ * about data management store. ++ */ ++ op_ret = cvlt_init_store_info(parch, &(req->store_info)); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " failed to extract store info for gfid=%s" ++ " offset=%" PRIu64 " size=%" GF_PRI_SIZET ++ ", " ++ " buf=%p", ++ uuid_utoa(locxattr->gfid), off, size, req->iobuf->ptr); ++ goto err; ++ } ++ ++ op_ret = cvlt_init_file_info(locxattr, &(req->file_info)); ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " failed to extract file info for gfid=%s" ++ " offset=%" PRIu64 " size=%" GF_PRI_SIZET ++ ", " ++ " buf=%p", ++ uuid_utoa(locxattr->gfid), off, size, req->iobuf->ptr); ++ goto err; ++ } ++ ++ /* ++ * Submit the read request. ++ */ ++ op_ret = parch->fops.read(&(parch->descinfo), &(req->store_info), ++ &(req->file_info), off, req->iobuf->ptr, size, ++ &op_errno, cvlt_readv_complete, req); ++ ++ if (op_ret < 0) { ++ gf_msg(plugin, GF_LOG_ERROR, 0, CVLT_EXTRACTION_FAILED, ++ " read failed on gfid=%s" ++ " offset=%" PRIu64 " size=%" GF_PRI_SIZET ++ ", " ++ " buf=%p", ++ uuid_utoa(locxattr->gfid), off, size, req->iobuf->ptr); ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ ++ iobref = iobref_new(); ++ gf_msg_debug(plugin, 0, " read unwinding stack op_ret = %d, op_errno = %d", ++ op_ret, op_errno); ++ ++ STACK_UNWIND_STRICT(readv, frame, op_ret, op_errno, &iov, 1, ++ &(local->stbuf), iobref, local->xattr_rsp); ++ ++ if (iobref) { ++ iobref_unref(iobref); ++ } ++ ++ if (req) { ++ cvlt_free_req(parch, req); ++ } ++ ++ return 0; ++} +diff --git a/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.h b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.h +new file mode 100644 +index 0000000..c45ac94 +--- /dev/null ++++ b/xlators/features/cloudsync/src/cloudsync-plugins/src/cvlt/src/libcvlt.h +@@ -0,0 +1,84 @@ ++/* ++ Copyright (c) 2018 Commvault Systems, Inc. ++ This file is part of GlusterFS. ++ ++ This file is licensed to you under your choice of the GNU Lesser ++ General Public License, version 3 or any later version (LGPLv3 or ++ later), or the GNU General Public License, version 2 (GPLv2), in all ++ cases as published by the Free Software Foundation. ++*/ ++#ifndef _LIBCVLT_H ++#define _LIBCVLT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "cloudsync-common.h" ++#include "libcvlt-mem-types.h" ++#include "archivestore.h" ++ ++enum _cvlt_op { ++ CVLT_READ_OP = 1, ++ CVLT_WRITE_OP = 2, ++ CVLT_RESTORE_OP = 3, ++ CVLT_ARCHIVE_OP = 4, ++ CVLT_LOOKUP_OP = 5, ++ CVLT_XATTR_OP = 6, ++ CVLT_STAT_OP = 7, ++ CVLT_FSTAT_op = 8, ++ CVLT_UNDEF_OP = 127 ++}; ++typedef enum _cvlt_op cvlt_op_t; ++ ++struct _archive; ++struct _cvlt_request { ++ uint64_t offset; ++ uint64_t bytes; ++ struct iobuf *iobuf; ++ struct iobref *iobref; ++ call_frame_t *frame; ++ cvlt_op_t op_type; ++ int32_t op_ret; ++ int32_t op_errno; ++ xlator_t *this; ++ sem_t sem; ++ archstore_info_t store_info; ++ archstore_fileinfo_t file_info; ++ cs_size_xattr_t szxattr; ++}; ++typedef struct _cvlt_request cvlt_request_t; ++ ++struct _archive { ++ gf_lock_t lock; /* lock for controlling access */ ++ xlator_t *xl; /* xlator */ ++ void *handle; /* handle returned from dlopen */ ++ int32_t nreqs; /* num requests active */ ++ struct mem_pool *req_pool; /* pool for requests */ ++ struct iobuf_pool *iobuf_pool; /* iobuff pool */ ++ archstore_desc_t descinfo; /* Archive store descriptor info */ ++ archstore_methods_t fops; /* function pointers */ ++ char *product_id; ++ char *store_id; ++ char *trailer; ++}; ++typedef struct _archive archive_t; ++ ++void * ++cvlt_init(xlator_t *); ++ ++int ++cvlt_reconfigure(xlator_t *, dict_t *); ++ ++void ++cvlt_fini(void *); ++ ++int ++cvlt_download(call_frame_t *, void *); ++ ++int ++cvlt_read(call_frame_t *, void *); ++ ++#endif +diff --git a/xlators/features/cloudsync/src/cloudsync.c b/xlators/features/cloudsync/src/cloudsync.c +index 2240fc3..8026b05 100644 +--- a/xlators/features/cloudsync/src/cloudsync.c ++++ b/xlators/features/cloudsync/src/cloudsync.c +@@ -39,7 +39,11 @@ struct cs_plugin plugins[] = { + {.name = "cloudsyncs3", + .library = "cloudsyncs3.so", + .description = "cloudsync s3 store."}, +- ++#if defined(__linux__) ++ {.name = "cvlt", ++ .library = "cloudsynccvlt.so", ++ .description = "Commvault content store."}, ++#endif + {.name = NULL}, + }; + +diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c +index 73abf37..7a83124 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c ++++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c +@@ -3724,6 +3724,14 @@ struct volopt_map_entry glusterd_volopt_map[] = { + {.key = "features.cloudsync-remote-read", + .voltype = "features/cloudsync", + .value = "off", +- .op_version = GD_OP_VERSION_6_0, ++ .op_version = GD_OP_VERSION_7_0, ++ .flags = VOLOPT_FLAG_CLIENT_OPT}, ++ {.key = "features.cloudsync-store-id", ++ .voltype = "features/cloudsync", ++ .op_version = GD_OP_VERSION_7_0, ++ .flags = VOLOPT_FLAG_CLIENT_OPT}, ++ {.key = "features.cloudsync-product-id", ++ .voltype = "features/cloudsync", ++ .op_version = GD_OP_VERSION_7_0, + .flags = VOLOPT_FLAG_CLIENT_OPT}, + {.key = NULL}}; +-- +1.8.3.1 + diff --git a/0155-cloudsync-Make-readdirp-return-stat-info-of-all-the-.patch b/0155-cloudsync-Make-readdirp-return-stat-info-of-all-the-.patch new file mode 100644 index 0000000..937a772 --- /dev/null +++ b/0155-cloudsync-Make-readdirp-return-stat-info-of-all-the-.patch @@ -0,0 +1,114 @@ +From 693fcf327eace37fe698953b90050d67fc840ac6 Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Wed, 24 Apr 2019 12:06:23 -0700 +Subject: [PATCH 155/169] cloudsync: Make readdirp return stat info of all the + dirents + +This change got missed while the initial changes were sent. +Should have been a part of : + https://review.gluster.org/#/c/glusterfs/+/21757/ + +Gist of the change: + Function that fills in stat info for dirents is +invoked in readdirp in posix when cloudsync populates xdata +request with GF_CS_OBJECT_STATUS. + +backport of:https://review.gluster.org/#/c/glusterfs/+/22616/ + +> Change-Id: Ide0c4e80afb74cd2120f74ba934ed40123152d69 +> updates: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: I77de3f9d8ae01a0280a9d1753f94d74b5e5ce2fd +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172193 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + xlators/features/cloudsync/src/cloudsync-fops-c.py | 2 +- + xlators/features/cloudsync/src/cloudsync.c | 35 ++++++++++++++++++++++ + xlators/storage/posix/src/posix-inode-fd-ops.c | 2 ++ + 3 files changed, 38 insertions(+), 1 deletion(-) + +diff --git a/xlators/features/cloudsync/src/cloudsync-fops-c.py b/xlators/features/cloudsync/src/cloudsync-fops-c.py +index a7a2201..8878b70 100755 +--- a/xlators/features/cloudsync/src/cloudsync-fops-c.py ++++ b/xlators/features/cloudsync/src/cloudsync-fops-c.py +@@ -285,7 +285,7 @@ loc_stat_op_fop_template = ['lookup', 'stat', 'discover', 'access', 'setattr', + + # These fops need a separate implementation + special_fops = ['statfs', 'setxattr', 'unlink', 'getxattr', +- 'truncate', 'fstat', 'readv'] ++ 'truncate', 'fstat', 'readv', 'readdirp'] + + def gen_defaults(): + for name in ops: +diff --git a/xlators/features/cloudsync/src/cloudsync.c b/xlators/features/cloudsync/src/cloudsync.c +index 8026b05..26e512c 100644 +--- a/xlators/features/cloudsync/src/cloudsync.c ++++ b/xlators/features/cloudsync/src/cloudsync.c +@@ -280,6 +280,40 @@ out: + } + + int32_t ++cs_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, ++ off_t off, dict_t *xdata) ++{ ++ int ret = 0; ++ int op_errno = ENOMEM; ++ ++ if (!xdata) { ++ xdata = dict_new(); ++ if (!xdata) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, ENOMEM, ++ "failed to create " ++ "dict"); ++ goto err; ++ } ++ } ++ ++ ret = dict_set_uint32(xdata, GF_CS_OBJECT_STATUS, 1); ++ if (ret) { ++ gf_msg(this->name, GF_LOG_ERROR, 0, 0, ++ "dict_set failed key:" ++ " %s", ++ GF_CS_OBJECT_STATUS); ++ goto err; ++ } ++ ++ STACK_WIND(frame, default_readdirp_cbk, FIRST_CHILD(this), ++ FIRST_CHILD(this)->fops->readdirp, fd, size, off, xdata); ++ return 0; ++err: ++ STACK_UNWIND_STRICT(readdirp, frame, -1, op_errno, NULL, NULL); ++ return 0; ++} ++ ++int32_t + cs_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +@@ -2026,6 +2060,7 @@ cs_notify(xlator_t *this, int event, void *data, ...) + + struct xlator_fops cs_fops = { + .stat = cs_stat, ++ .readdirp = cs_readdirp, + .truncate = cs_truncate, + .seek = cs_seek, + .statfs = cs_statfs, +diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c +index 065fced..2c19ce1 100644 +--- a/xlators/storage/posix/src/posix-inode-fd-ops.c ++++ b/xlators/storage/posix/src/posix-inode-fd-ops.c +@@ -5472,6 +5472,8 @@ posix_readdirp_fill(xlator_t *this, fd_t *fd, gf_dirent_t *entries, + continue; + } + ++ posix_update_iatt_buf(&stbuf, -1, hpath, dict); ++ + if (!inode) + inode = inode_find(itable, stbuf.ia_gfid); + +-- +1.8.3.1 + diff --git a/0156-cloudsync-Fix-bug-in-cloudsync-fops-c.py.patch b/0156-cloudsync-Fix-bug-in-cloudsync-fops-c.py.patch new file mode 100644 index 0000000..1a73388 --- /dev/null +++ b/0156-cloudsync-Fix-bug-in-cloudsync-fops-c.py.patch @@ -0,0 +1,94 @@ +From d8c98e9785e652692d928a2efbbb571703f728b0 Mon Sep 17 00:00:00 2001 +From: Anuradha Talur +Date: Wed, 24 Apr 2019 12:35:08 -0700 +Subject: [PATCH 156/169] cloudsync: Fix bug in cloudsync-fops-c.py + +In some of the fops generated by generator.py, xdata request +was not being wound to the child xlator correctly. + +This was happening because when though the logic in +cloudsync-fops-c.py was correct, generator.py was generating +a resultant code that omits this logic. + +Made changes in cloudsync-fops-c.py so that correct code is +produced. + +backport of: https://review.gluster.org/#/c/glusterfs/+/22617/ + +> Change-Id: I6f25bdb36ede06fd03be32c04087a75639d79150 +> updates: bz#1642168 +> Signed-off-by: Anuradha Talur + +Change-Id: I87cc71e98c2c6cec78a6e84850fc8d82f8dd4dfd +Signed-off-by: Susant Palai +Reviewed-on: https://code.engineering.redhat.com/gerrit/172195 +Tested-by: RHGS Build Bot +Reviewed-by: Atin Mukherjee +--- + xlators/features/cloudsync/src/cloudsync-fops-c.py | 24 +++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +diff --git a/xlators/features/cloudsync/src/cloudsync-fops-c.py b/xlators/features/cloudsync/src/cloudsync-fops-c.py +index 8878b70..c444ea6 100755 +--- a/xlators/features/cloudsync/src/cloudsync-fops-c.py ++++ b/xlators/features/cloudsync/src/cloudsync-fops-c.py +@@ -39,7 +39,15 @@ cs_@NAME@ (call_frame_t *frame, xlator_t *this, + else + state = GF_CS_LOCAL; + +- local->xattr_req = xdata ? dict_ref (xdata) : (xdata = dict_new ()); ++ xdata = xdata ? dict_ref (xdata) : dict_new (); ++ ++ if (!xdata) { ++ gf_msg (this->name, GF_LOG_ERROR, 0, 0, "insufficient memory"); ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ local->xattr_req = xdata; + + ret = dict_set_uint32 (local->xattr_req, GF_CS_OBJECT_STATUS, 1); + if (ret) { +@@ -187,19 +195,29 @@ int32_t + cs_@NAME@ (call_frame_t *frame, xlator_t *this, + @LONG_ARGS@) + { ++ int op_errno = EINVAL; + cs_local_t *local = NULL; + int ret = 0; + + local = cs_local_init (this, frame, loc, NULL, GF_FOP_@UPNAME@); + if (!local) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, "local is NULL"); ++ op_errno = ENOMEM; + goto err; + } + + if (loc->inode->ia_type == IA_IFDIR) + goto wind; + +- local->xattr_req = xdata ? dict_ref (xdata) : dict_new (); ++ xdata = xdata ? dict_ref (xdata) : dict_new (); ++ ++ if (!xdata) { ++ gf_msg (this->name, GF_LOG_ERROR, 0, 0, "insufficient memory"); ++ op_errno = ENOMEM; ++ goto err; ++ } ++ ++ local->xattr_req = xdata; + + ret = dict_set_uint32 (local->xattr_req, GF_CS_OBJECT_STATUS, 1); + if (ret) { +@@ -215,7 +233,7 @@ wind: + + return 0; + err: +- CS_STACK_UNWIND (@NAME@, frame, -1, errno, @CBK_ERROR_ARGS@); ++ CS_STACK_UNWIND (@NAME@, frame, -1, op_errno, @CBK_ERROR_ARGS@); + + return 0; + } +-- +1.8.3.1 + diff --git a/0157-afr-frame-Destroy-frame-after-afr_selfheal_entry_gra.patch b/0157-afr-frame-Destroy-frame-after-afr_selfheal_entry_gra.patch new file mode 100644 index 0000000..185a24a --- /dev/null +++ b/0157-afr-frame-Destroy-frame-after-afr_selfheal_entry_gra.patch @@ -0,0 +1,68 @@ +From 4a72ac20f728aa5c3141359ff89f1b61d4cd210a Mon Sep 17 00:00:00 2001 +From: Mohammed Rafi KC +Date: Fri, 17 May 2019 23:03:35 +0530 +Subject: [PATCH 157/169] afr/frame: Destroy frame after + afr_selfheal_entry_granular + +In function "afr_selfheal_entry_granular", after completing the +heal we are not destroying the frame. This will lead to crash. +when we execute statedump operation, where it tried to access +xlator object. If this xlator object is freed as part of the +graph destroy this will lead to an invalid memory access + +Upstream patch:https://review.gluster.org/22743 + +>Change-Id: I0a5e78e704ef257c3ac0087eab2c310e78fbe36d +>fixes: bz#1708926 +>Signed-off-by: Mohammed Rafi KC + +Change-Id: I326354008e6d98376c8333d270f2f80036ad07f0 +BUG: 1716626 +Signed-off-by: Mohammed Rafi KC +Reviewed-on: https://code.engineering.redhat.com/gerrit/172282 +Reviewed-by: Atin Mukherjee +Tested-by: RHGS Build Bot +--- + xlators/cluster/afr/src/afr-self-heal-entry.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c +index fc09b4c..a6890fa 100644 +--- a/xlators/cluster/afr/src/afr-self-heal-entry.c ++++ b/xlators/cluster/afr/src/afr-self-heal-entry.c +@@ -832,6 +832,8 @@ afr_selfheal_entry_granular(call_frame_t *frame, xlator_t *this, fd_t *fd, + subvol = priv->children[subvol_idx]; + + args.frame = afr_copy_frame(frame); ++ if (!args.frame) ++ goto out; + args.xl = this; + /* args.heal_fd represents the fd associated with the original directory + * on which entry heal is being attempted. +@@ -850,9 +852,10 @@ afr_selfheal_entry_granular(call_frame_t *frame, xlator_t *this, fd_t *fd, + * do not treat heal as failure. + */ + if (is_src) +- return -errno; ++ ret = -errno; + else +- return 0; ++ ret = 0; ++ goto out; + } + + ret = syncop_dir_scan(subvol, &loc, GF_CLIENT_PID_SELF_HEALD, &args, +@@ -862,7 +865,9 @@ afr_selfheal_entry_granular(call_frame_t *frame, xlator_t *this, fd_t *fd, + + if (args.mismatch == _gf_true) + ret = -1; +- ++out: ++ if (args.frame) ++ AFR_STACK_DESTROY(args.frame); + return ret; + } + +-- +1.8.3.1 + diff --git a/0158-glusterfsd-cleanup-Protect-graph-object-under-a-lock.patch b/0158-glusterfsd-cleanup-Protect-graph-object-under-a-lock.patch new file mode 100644 index 0000000..d12e81d --- /dev/null +++ b/0158-glusterfsd-cleanup-Protect-graph-object-under-a-lock.patch @@ -0,0 +1,162 @@ +From 11b64d494c52004002f900888694d20ef8af6df6 Mon Sep 17 00:00:00 2001 +From: Mohammed Rafi KC +Date: Sat, 11 May 2019 22:40:22 +0530 +Subject: [PATCH 158/169] glusterfsd/cleanup: Protect graph object under a lock + +While processing a cleanup_and_exit function, we are +accessing a graph object. But this has not been protected +under a lock. Because a parallel cleanup of a graph is quite +possible which might lead to an invalid memory access + +Upstream patch:https://review.gluster.org/#/c/glusterfs/+/22709/ + +>Change-Id: Id05ca70d5b57e172b0401d07b6a1f5386c044e79 +>fixes: bz#1708926 +>Signed-off-by: Mohammed Rafi KC + +Change-Id: I55ab0525c79baa99a3bd929ee979c5519be5ab21 +BUG: 1716626 +Signed-off-by: Mohammed Rafi KC +Reviewed-on: https://code.engineering.redhat.com/gerrit/172283 +Reviewed-by: Atin Mukherjee +Tested-by: RHGS Build Bot +--- + libglusterfs/src/graph.c | 58 +++++++++++++++---------- + libglusterfs/src/statedump.c | 16 +++++-- + tests/bugs/glusterd/optimized-basic-testcases.t | 4 +- + 3 files changed, 50 insertions(+), 28 deletions(-) + +diff --git a/libglusterfs/src/graph.c b/libglusterfs/src/graph.c +index 4c8b02d..18fb2d9 100644 +--- a/libglusterfs/src/graph.c ++++ b/libglusterfs/src/graph.c +@@ -1392,8 +1392,12 @@ glusterfs_graph_cleanup(void *arg) + } + pthread_mutex_unlock(&ctx->notify_lock); + +- glusterfs_graph_fini(graph); +- glusterfs_graph_destroy(graph); ++ pthread_mutex_lock(&ctx->cleanup_lock); ++ { ++ glusterfs_graph_fini(graph); ++ glusterfs_graph_destroy(graph); ++ } ++ pthread_mutex_unlock(&ctx->cleanup_lock); + out: + return NULL; + } +@@ -1468,31 +1472,37 @@ glusterfs_process_svc_detach(glusterfs_ctx_t *ctx, gf_volfile_t *volfile_obj) + + if (!ctx || !ctx->active || !volfile_obj) + goto out; +- parent_graph = ctx->active; +- graph = volfile_obj->graph; +- if (!graph) +- goto out; +- if (graph->first) +- xl = graph->first; + +- last_xl = graph->last_xl; +- if (last_xl) +- last_xl->next = NULL; +- if (!xl || xl->cleanup_starting) +- goto out; ++ pthread_mutex_lock(&ctx->cleanup_lock); ++ { ++ parent_graph = ctx->active; ++ graph = volfile_obj->graph; ++ if (!graph) ++ goto unlock; ++ if (graph->first) ++ xl = graph->first; ++ ++ last_xl = graph->last_xl; ++ if (last_xl) ++ last_xl->next = NULL; ++ if (!xl || xl->cleanup_starting) ++ goto unlock; + +- xl->cleanup_starting = 1; +- gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_DETACH_STARTED, +- "detaching child %s", volfile_obj->vol_id); ++ xl->cleanup_starting = 1; ++ gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_DETACH_STARTED, ++ "detaching child %s", volfile_obj->vol_id); + +- list_del_init(&volfile_obj->volfile_list); +- glusterfs_mux_xlator_unlink(parent_graph->top, xl); +- parent_graph->last_xl = glusterfs_get_last_xlator(parent_graph); +- parent_graph->xl_count -= graph->xl_count; +- parent_graph->leaf_count -= graph->leaf_count; +- default_notify(xl, GF_EVENT_PARENT_DOWN, xl); +- parent_graph->id++; +- ret = 0; ++ list_del_init(&volfile_obj->volfile_list); ++ glusterfs_mux_xlator_unlink(parent_graph->top, xl); ++ parent_graph->last_xl = glusterfs_get_last_xlator(parent_graph); ++ parent_graph->xl_count -= graph->xl_count; ++ parent_graph->leaf_count -= graph->leaf_count; ++ default_notify(xl, GF_EVENT_PARENT_DOWN, xl); ++ parent_graph->id++; ++ ret = 0; ++ } ++unlock: ++ pthread_mutex_unlock(&ctx->cleanup_lock); + out: + if (!ret) { + list_del_init(&volfile_obj->volfile_list); +diff --git a/libglusterfs/src/statedump.c b/libglusterfs/src/statedump.c +index 0cf80c0..0d58f8f 100644 +--- a/libglusterfs/src/statedump.c ++++ b/libglusterfs/src/statedump.c +@@ -805,11 +805,17 @@ gf_proc_dump_info(int signum, glusterfs_ctx_t *ctx) + int brick_count = 0; + int len = 0; + +- gf_proc_dump_lock(); +- + if (!ctx) + goto out; + ++ /* ++ * Multiplexed daemons can change the active graph when attach/detach ++ * is called. So this has to be protected with the cleanup lock. ++ */ ++ if (mgmt_is_multiplexed_daemon(ctx->cmd_args.process_name)) ++ pthread_mutex_lock(&ctx->cleanup_lock); ++ gf_proc_dump_lock(); ++ + if (!mgmt_is_multiplexed_daemon(ctx->cmd_args.process_name) && + (ctx && ctx->active)) { + top = ctx->active->first; +@@ -923,7 +929,11 @@ gf_proc_dump_info(int signum, glusterfs_ctx_t *ctx) + out: + GF_FREE(dump_options.dump_path); + dump_options.dump_path = NULL; +- gf_proc_dump_unlock(); ++ if (ctx) { ++ gf_proc_dump_unlock(); ++ if (mgmt_is_multiplexed_daemon(ctx->cmd_args.process_name)) ++ pthread_mutex_unlock(&ctx->cleanup_lock); ++ } + + return; + } +diff --git a/tests/bugs/glusterd/optimized-basic-testcases.t b/tests/bugs/glusterd/optimized-basic-testcases.t +index d700b5e..110f1b9 100644 +--- a/tests/bugs/glusterd/optimized-basic-testcases.t ++++ b/tests/bugs/glusterd/optimized-basic-testcases.t +@@ -289,7 +289,9 @@ mkdir -p /xyz/var/lib/glusterd/abc + TEST $CLI volume create "test" $H0:/xyz/var/lib/glusterd/abc + EXPECT 'Created' volinfo_field "test" 'Status'; + +-EXPECT "1" generate_statedump_and_check_for_glusterd_info ++#While taking a statedump, there is a TRY_LOCK on call_frame, which might may cause ++#failure. So Adding a EXPECT_WITHIN ++EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" generate_statedump_and_check_for_glusterd_info + + cleanup_statedump `pidof glusterd` + cleanup +-- +1.8.3.1 + diff --git a/0159-glusterd-add-an-op-version-check.patch b/0159-glusterd-add-an-op-version-check.patch new file mode 100644 index 0000000..323ae95 --- /dev/null +++ b/0159-glusterd-add-an-op-version-check.patch @@ -0,0 +1,66 @@ +From bd087c3d2766b81b25ea7bbe425b55023fd12545 Mon Sep 17 00:00:00 2001 +From: Sanju Rakonde +Date: Wed, 15 May 2019 07:35:45 +0530 +Subject: [PATCH 159/169] glusterd: add an op-version check + +Problem: "gluster v status" is hung in heterogenous cluster +when issued from a non-upgraded node. + +Cause: commit 34e010d64 fixes the txn-opinfo mem leak +in op-sm framework by not setting the txn-opinfo if some +conditions are true. When vol status is issued from a +non-upgraded node, command is hanging in its upgraded peer +as the upgraded node setting the txn-opinfo based on new +conditions where as non-upgraded nodes are following diff +conditions. + +Fix: Add an op-version check, so that all the nodes follow +same set of conditions to set txn-opinfo. + +upstream patch: https://review.gluster.org/#/c/glusterfs/+/22730/ + +BUG: 1707246 + +> fixes: bz#1710159 +> Change-Id: Ie1f353212c5931ddd1b728d2e6949dfe6225c4ab +> Signed-off-by: Sanju Rakonde + +Change-Id: Ie1f353212c5931ddd1b728d2e6949dfe6225c4ab +Signed-off-by: Sanju Rakonde +Reviewed-on: https://code.engineering.redhat.com/gerrit/172307 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + xlators/mgmt/glusterd/src/glusterd-op-sm.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c +index 94a5e1f..d0c1a2c 100644 +--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c ++++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c +@@ -8158,9 +8158,12 @@ glusterd_op_sm() + glusterd_op_sm_event_type_t event_type = GD_OP_EVENT_NONE; + xlator_t *this = NULL; + glusterd_op_info_t txn_op_info; ++ glusterd_conf_t *priv = NULL; + + this = THIS; + GF_ASSERT(this); ++ priv = this->private; ++ GF_ASSERT(priv); + + ret = synclock_trylock(&gd_op_sm_lock); + if (ret) { +@@ -8238,7 +8241,8 @@ glusterd_op_sm() + "Unable to clear " + "transaction's opinfo"); + } else { +- if (!(event_type == GD_OP_EVENT_STAGE_OP && ++ if ((priv->op_version < GD_OP_VERSION_6_0) || ++ !(event_type == GD_OP_EVENT_STAGE_OP && + opinfo.state.state == GD_OP_STATE_STAGED && + opinfo.skip_locking)) { + ret = glusterd_set_txn_opinfo(&event->txn_id, &opinfo); +-- +1.8.3.1 + diff --git a/0160-geo-rep-Geo-rep-help-text-issue.patch b/0160-geo-rep-Geo-rep-help-text-issue.patch new file mode 100644 index 0000000..efba5a4 --- /dev/null +++ b/0160-geo-rep-Geo-rep-help-text-issue.patch @@ -0,0 +1,41 @@ +From 77df6b8930fd4acf3d0c38220fa4317ee97d530f Mon Sep 17 00:00:00 2001 +From: Shwetha K Acharya +Date: Thu, 9 May 2019 10:43:01 +0530 +Subject: [PATCH 160/169] geo-rep: Geo-rep help text issue + +Modified Geo-rep help text for better sanity. + +>fixes: bz#1652887 +>Change-Id: I40ef7ef709eaecf0125ab4b4a7517e2c5d1ef4a0 +>Signed-off-by: Shwetha K Acharya + +backport of https://review.gluster.org/#/c/glusterfs/+/22689/ + +BUG: 1480907 +Change-Id: I40ef7ef709eaecf0125ab4b4a7517e2c5d1ef4a0 +Signed-off-by: Shwetha K Acharya +Reviewed-on: https://code.engineering.redhat.com/gerrit/172316 +Tested-by: RHGS Build Bot +Reviewed-by: Sunil Kumar Heggodu Gopala Acharya +--- + cli/src/cli-cmd-volume.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c +index 3432dbe..564aef7 100644 +--- a/cli/src/cli-cmd-volume.c ++++ b/cli/src/cli-cmd-volume.c +@@ -3422,8 +3422,8 @@ struct cli_cmd volume_cmds[] = { + "reset all the reconfigured options"}, + + #if (SYNCDAEMON_COMPILE) +- {"volume " GEOREP " [] [] {\\\n create [[ssh-port n] " +- "[[no-verify] | [push-pem]]] [force] \\\n" ++ {"volume " GEOREP " [] []::[] {" ++ "\\\n create [[ssh-port n] [[no-verify] \\\n | [push-pem]]] [force] \\\n" + " | start [force] \\\n | stop [force] \\\n | pause [force] \\\n | resume " + "[force] \\\n" + " | config [[[\\!]