From b72bc58ecc108a2fddbdb6f606cd86a57ca5a68f Mon Sep 17 00:00:00 2001 From: Jiffin Tony Thottan Date: Wed, 25 Mar 2015 15:04:19 +0530 Subject: features/trash : Notify CTR translator if an unlink happens to a file This implementation is same as the posix_unlink_cbk() where CTR sends a request during a unlink to send the number of links to the inode and posix obliges sending it using the unwind xdata dict. For Trash xlator a unlink is stat + mkdir(if parent is not present) + rename. And hence this is handled in trash_unlink_rename_cbk(). Change-Id: I402e83567b88e3c9fe171379693c82937af567f9 BUG: 1205545 Signed-off-by: Jiffin Tony Thottan Signed-off-by: Joseph Fernandes Signed-off-by: Anoop C S Reviewed-on: http://review.gluster.org/9989 Tested-by: NetBSD Build System Tested-by: Joseph Fernandes Reviewed-by: Joseph Fernandes Tested-by: Gluster Build System Reviewed-by: Niels de Vos Reviewed-by: Vijay Bellur --- .../tier/bug-1205545-CTR-and-trash-integration.t | 71 ++++++++++++++++++++++ .../changetimerecorder/src/changetimerecorder.c | 22 +++---- xlators/features/trash/src/trash.c | 66 ++++++++++++++++++++ xlators/features/trash/src/trash.h | 1 + xlators/storage/posix/src/posix-helpers.c | 3 + xlators/storage/posix/src/posix.c | 12 +++- 6 files changed, 159 insertions(+), 16 deletions(-) create mode 100644 tests/bugs/tier/bug-1205545-CTR-and-trash-integration.t diff --git a/tests/bugs/tier/bug-1205545-CTR-and-trash-integration.t b/tests/bugs/tier/bug-1205545-CTR-and-trash-integration.t new file mode 100644 index 00000000000..979c3e8c83a --- /dev/null +++ b/tests/bugs/tier/bug-1205545-CTR-and-trash-integration.t @@ -0,0 +1,71 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc + +LAST_BRICK=3 +CACHE_BRICK_FIRST=4 +CACHE_BRICK_LAST=5 + +cleanup + +# Start glusterd [1-2] +TEST glusterd +TEST pidof glusterd + +# Set-up tier cluster [3-4] +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0..$LAST_BRICK} +TEST $CLI volume attach-tier $V0 replica 2 $H0:$B0/${V0}$CACHE_BRICK_FIRST $H0:$B0/${V0}$CACHE_BRICK_LAST + +# Start and mount the volume after enabling CTR and trash [5-8] +TEST $CLI volume set $V0 features.ctr-enabled on +TEST $CLI volume set $V0 features.trash on +TEST $CLI volume start $V0 +TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0; + +# Create an empty file +touch $M0/foo + +# gf_file_tb and gf_flink_tb should contain one entry each [9] +ENTRY_COUNT=$(echo "select * from gf_file_tb; select * from gf_flink_tb;" | \ + sqlite3 $B0/${V0}5/.glusterfs/${V0}5.db | wc -l ) +TEST [ $ENTRY_COUNT -eq 2 ] + +# Create two hard links +ln $M0/foo $M0/lnk1 +ln $M0/foo $M0/lnk2 + +# Now gf_flink_tb should contain 3 entries [10] +ENTRY_COUNT=$(echo "select * from gf_flink_tb;" | \ + sqlite3 $B0/${V0}5/.glusterfs/${V0}5.db | wc -l ) +TEST [ $ENTRY_COUNT -eq 3 ] + +# Delete the hard link +rm -rf $M0/lnk1 + +# Corresponding hard link entry must be removed from gf_flink_tb +# but gf_file_tb should still contain the file entry [11] +ENTRY_COUNT=$(echo "select * from gf_file_tb; select * from gf_flink_tb;" | \ + sqlite3 $B0/${V0}5/.glusterfs/${V0}5.db | wc -l ) +TEST [ $ENTRY_COUNT -eq 3 ] + +# Remove the file +rm -rf $M0/foo + +# Another hardlink removed [12] +ENTRY_COUNT=$(echo "select * from gf_file_tb; select * from gf_flink_tb;" | \ + sqlite3 $B0/${V0}5/.glusterfs/${V0}5.db | wc -l ) +TEST [ $ENTRY_COUNT -eq 2 ] + +# Remove the last hardlink +rm -rf $M0/lnk2 + +# All entried must be removed from gf_flink_tb and gf_file_tb [13] +ENTRY_COUNT=$(echo "select * from gf_file_tb; select * from gf_flink_tb;" | \ + sqlite3 $B0/${V0}5/.glusterfs/${V0}5.db | wc -l ) +TEST [ $ENTRY_COUNT -eq 0 ] + +cleanup + + + diff --git a/xlators/features/changetimerecorder/src/changetimerecorder.c b/xlators/features/changetimerecorder/src/changetimerecorder.c index 80deefbd4b2..42470a92ef9 100644 --- a/xlators/features/changetimerecorder/src/changetimerecorder.c +++ b/xlators/features/changetimerecorder/src/changetimerecorder.c @@ -451,11 +451,6 @@ ctr_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, remaining_links = -1; } - /*As the xdata is no more required by CTR Xlator.*/ - if (xdata) { - dict_unref (xdata); - } - /*This is not the only link*/ if (remaining_links != 1) { @@ -476,8 +471,6 @@ ctr_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } } - - out: STACK_UNWIND_STRICT (unlink, frame, op_ret, op_errno, preparent, postparent, NULL); @@ -494,6 +487,7 @@ ctr_unlink (call_frame_t *frame, xlator_t *this, gf_ctr_inode_context_t *_inode_cx = &ctr_inode_cx; gf_ctr_link_context_t ctr_link_cx; gf_ctr_link_context_t *_link_cx = &ctr_link_cx; + gf_boolean_t is_xdata_created = _gf_false; GF_ASSERT (frame); @@ -517,8 +511,6 @@ ctr_unlink (call_frame_t *frame, xlator_t *this, "Failed inserting unlink wind"); } - - /* * * Sending CTR_REQUEST_LINK_COUNT_XDATA @@ -526,8 +518,10 @@ ctr_unlink (call_frame_t *frame, xlator_t *this, * * */ /*create xdata if NULL*/ - if (!xdata) + if (!xdata) { xdata = dict_new(); + is_xdata_created = (xdata) ? _gf_true : _gf_false; + } if (!xdata) { gf_log (this->name, GF_LOG_ERROR, "xdata is NULL :" @@ -540,18 +534,20 @@ ctr_unlink (call_frame_t *frame, xlator_t *this, if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed setting CTR_REQUEST_LINK_COUNT_XDATA"); - if (xdata) { + if (is_xdata_created) { dict_unref (xdata); } goto out; } - - out: STACK_WIND (frame, ctr_unlink_cbk, FIRST_CHILD (this), FIRST_CHILD (this)->fops->unlink, loc, xflag, xdata); + + if (is_xdata_created) + dict_unref (xdata); + return 0; } diff --git a/xlators/features/trash/src/trash.c b/xlators/features/trash/src/trash.c index 5cc051004b4..b2dd94ab161 100644 --- a/xlators/features/trash/src/trash.c +++ b/xlators/features/trash/src/trash.c @@ -750,6 +750,7 @@ trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, char *dir_name = NULL; char *tmp_cookie = NULL; loc_t tmp_loc = {0,}; + dict_t *new_xdata = NULL; char *tmp_stat = NULL; char real_path[PATH_MAX] = {0,}; int ret = 0; @@ -829,14 +830,69 @@ trash_unlink_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, goto out; } + /********************************************************************** + * + * CTR Xlator message handling done here! + * + **********************************************************************/ + /** + * If unlink is handled by trash translator, it should inform the + * CTR Xlator. And trash translator only handles the unlink for + * the last hardlink. + * + * Check if there is a CTR_REQUEST_LINK_COUNT_XDATA from CTR Xlator + * + */ + + if (local->ctr_link_count_req) { + + /* Sending back inode link count to ctr_unlink + * (changetimerecoder xlator) via + * "CTR_RESPONSE_LINK_COUNT_XDATA" key using xdata. + * */ + if (xdata) { + ret = dict_set_uint32 (xdata, + CTR_RESPONSE_LINK_COUNT_XDATA, + 1); + if (ret == -1) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to set" + " CTR_RESPONSE_LINK_COUNT_XDATA"); + } + } else { + new_xdata = dict_new (); + if (!new_xdata) { + gf_log (this->name, GF_LOG_WARNING, + "Memory allocation failure while " + "creating new_xdata"); + goto ctr_out; + } + ret = dict_set_uint32 (new_xdata, + CTR_RESPONSE_LINK_COUNT_XDATA, + 1); + if (ret == -1) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to set" + " CTR_RESPONSE_LINK_COUNT_XDATA"); + } +ctr_out: + TRASH_STACK_UNWIND (unlink, frame, 0, op_errno, + &local->preparent, + &local->postparent, new_xdata); + goto out; + } + } /* All other cases, unlink should return success */ TRASH_STACK_UNWIND (unlink, frame, 0, op_errno, &local->preparent, &local->postparent, xdata); out: + if (tmp_str) GF_FREE (tmp_str); if (tmp_cookie) GF_FREE (tmp_cookie); + if (new_xdata) + dict_unref (new_xdata); return ret; } @@ -938,6 +994,7 @@ trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, trash_private_t *priv = NULL; trash_local_t *local = NULL;/* files inside trash */ int32_t match = 0; + int32_t ctr_link_req = 0; char *pathbuf = NULL; int ret = 0; @@ -1034,6 +1091,15 @@ trash_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflags, goto out; } + /* To know whether CTR xlator requested for the link count */ + ret = dict_get_int32 (xdata, CTR_REQUEST_LINK_COUNT_XDATA, + &ctr_link_req); + if (ret) { + local->ctr_link_count_req = _gf_false; + ret = 0; + } else + local->ctr_link_count_req = _gf_true; + LOCK_INIT (&frame->lock); STACK_WIND (frame, trash_unlink_stat_cbk, diff --git a/xlators/features/trash/src/trash.h b/xlators/features/trash/src/trash.h index 3e03edf5474..37d8f7b3d85 100644 --- a/xlators/features/trash/src/trash.h +++ b/xlators/features/trash/src/trash.h @@ -50,6 +50,7 @@ struct trash_struct { int32_t loop_count; struct iatt preparent; struct iatt postparent; + gf_boolean_t ctr_link_count_req; }; typedef struct trash_struct trash_local_t; diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c index f3d6d6c3da7..e1bd5b127fd 100644 --- a/xlators/storage/posix/src/posix-helpers.c +++ b/xlators/storage/posix/src/posix-helpers.c @@ -409,6 +409,9 @@ _posix_xattr_get_set (dict_t *xattr_req, char *key, data_t *data, } else if (fnmatch (marker_contri_key, key, 0) == 0) { ret = _posix_get_marker_quota_contributions (filler, key); + } else if (strcmp(key, CTR_REQUEST_LINK_COUNT_XDATA) == 0) { + ret = dict_set (filler->xattr, + CTR_REQUEST_LINK_COUNT_XDATA, data); } else { ret = _posix_xattr_get_set_from_backend (filler, key); } diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 337f9b95fa2..8cbe2c5a02e 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -1652,11 +1652,12 @@ posix_unlink (call_frame_t *frame, xlator_t *this, if (!unwind_dict) { op_ret = 0; gf_log (this->name, GF_LOG_WARNING, - "Failed to creating unwind_dict"); + "Memory allocation failure while " + "creating unwind_dict"); goto out; } - /* Even if unwind_dict fails to set CTR_RESPONSE_LINK_COUNT_XDATA we will - * not mark the FOP unsuccessful + /* Even if unwind_dict fails to set CTR_RESPONSE_LINK_COUNT_XDATA we + * will not mark the FOP unsuccessful * because this dict is only used by CTR Xlator to clear * all records if link count == 0*/ op_ret = dict_set_uint32 (unwind_dict, CTR_RESPONSE_LINK_COUNT_XDATA, @@ -1678,6 +1679,11 @@ out: close (fd); } + /* unref unwind_dict*/ + if (unwind_dict) { + dict_unref (unwind_dict); + } + return 0; } -- cgit