diff options
author | Ashish Pandey <aspandey@redhat.com> | 2015-11-26 14:35:49 +0530 |
---|---|---|
committer | Pranith Kumar Karampuri <pkarampu@redhat.com> | 2016-01-25 03:37:10 -0800 |
commit | 195548f55b09bf71db92929b7b734407b863093c (patch) | |
tree | 08b113e723811733528e46fb454fb1e397e69820 /xlators/storage/posix/src/posix.c | |
parent | fa6545a323df920768dd25989537e6a350c10432 (diff) |
storage/posix: Implement .unlink directory
Problem: For EC volume, If a file descriptor is open and
file has been unlinked, any further write on that fd will
fail. When a write request comes, EC internally reads some
blocks using anonymous fd. This read will fail as the file
has already been unlinked.
Solution: To solve this issue, we are using .unlink directory
to keep track of unlinked file. If a file is to be unlinked
while its fd is open, move this to .unlink directory and unlink
it from .glusterfs and real path. Once all the fd will be closed,
remove this entry form .unlink directory.
master -
http://review.gluster.org/#/c/12816/
Change-Id: I8344edb0d340bdb883dc46458c16edbc336916b9
BUG: 1291557
Signed-off-by: Ashish Pandey <aspandey@redhat.com>
Reviewed-on: http://review.gluster.org/12968
Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
Tested-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
Smoke: Gluster Build System <jenkins@build.gluster.com>
CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
Diffstat (limited to 'xlators/storage/posix/src/posix.c')
-rw-r--r-- | xlators/storage/posix/src/posix.c | 196 |
1 files changed, 187 insertions, 9 deletions
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 600ebf3f0fa..d57d53d5fca 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -106,10 +106,32 @@ int posix_forget (xlator_t *this, inode_t *inode) { uint64_t tmp_cache = 0; - if (!inode_ctx_del (inode, this, &tmp_cache)) - dict_destroy ((dict_t *)(long)tmp_cache); + int ret = 0; + char *unlink_path = NULL; + struct posix_private *priv_posix = NULL; - return 0; + priv_posix = (struct posix_private *) this->private; + + ret = inode_ctx_del (inode, this, &tmp_cache); + if (ret < 0) { + ret = 0; + goto out; + } + if (tmp_cache == GF_UNLINK_TRUE) { + POSIX_GET_FILE_UNLINK_PATH(priv_posix->base_path, + inode->gfid, unlink_path); + if (!unlink_path) { + gf_msg (this->name, GF_LOG_ERROR, ENOMEM, + P_MSG_UNLINK_FAILED, + "Failed to remove gfid :%s", + uuid_utoa (inode->gfid)); + ret = -1; + goto out; + } + ret = sys_unlink(unlink_path); + } +out: + return ret; } /* Regular fops */ @@ -1461,16 +1483,93 @@ out: return 0; } +int +posix_add_unlink_to_ctx (inode_t *inode, xlator_t *this, char *unlink_path) +{ + uint64_t ctx = GF_UNLINK_FALSE; + int ret = 0; + + if (!unlink_path) { + gf_msg (this->name, GF_LOG_ERROR, ENOMEM, + P_MSG_UNLINK_FAILED, + "Creation of unlink entry failed for gfid: %s", + unlink_path); + ret = -1; + goto out; + } + + ctx = GF_UNLINK_TRUE; + ret = posix_inode_ctx_set (inode, this, ctx); + if (ret < 0) { + goto out; + } + +out: + return ret; +} + +int32_t +posix_move_gfid_to_unlink (xlator_t *this, uuid_t gfid, loc_t *loc) +{ + char *unlink_path = NULL; + char *gfid_path = NULL; + struct stat stbuf = {0, }; + int ret = 0; + struct posix_private *priv_posix = NULL; + + priv_posix = (struct posix_private *) this->private; + + MAKE_HANDLE_GFID_PATH (gfid_path, this, gfid, NULL); + + POSIX_GET_FILE_UNLINK_PATH (priv_posix->base_path, + loc->inode->gfid, unlink_path); + if (!unlink_path) { + ret = -1; + goto out; + } + gf_msg_debug (this->name, 0, + "Moving gfid: %s to unlink_path : %s", + gfid_path, unlink_path); + ret = sys_rename (gfid_path, unlink_path); + if (ret < 0) { + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_UNLINK_FAILED, + "Creation of unlink entry failed for gfid: %s", + unlink_path); + goto out; + } + ret = posix_add_unlink_to_ctx (loc->inode, this, unlink_path); + if (ret < 0) + goto out; + +out: + return ret; +} + int32_t posix_unlink_gfid_handle_and_entry (xlator_t *this, const char *real_path, - struct iatt *stbuf, int32_t *op_errno) + struct iatt *stbuf, int32_t *op_errno, + loc_t *loc) { - int32_t ret = 0; + int32_t ret = 0; + struct posix_private *priv = NULL; + int fd_count = 0; - /* Unlink the gfid_handle_first */ + priv = this->private; + /* Unlink the gfid_handle_first */ if (stbuf && stbuf->ia_nlink == 1) { - ret = posix_handle_unset (this, stbuf->ia_gfid, NULL); + + LOCK (&loc->inode->lock); + + if (loc->inode->fd_count == 0) { + UNLOCK (&loc->inode->lock); + ret = posix_handle_unset (this, stbuf->ia_gfid, NULL); + } else { + UNLOCK (&loc->inode->lock); + ret = posix_move_gfid_to_unlink (this, stbuf->ia_gfid, + loc); + } if (ret) { gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_UNLINK_FAILED, "unlink of gfid handle " @@ -1484,7 +1583,6 @@ posix_unlink_gfid_handle_and_entry (xlator_t *this, const char *real_path, if (ret == -1) { if (op_errno) *op_errno = errno; - gf_msg (this->name, GF_LOG_ERROR, errno, P_MSG_UNLINK_FAILED, "unlink of %s failed", real_path); goto err; @@ -1638,7 +1736,7 @@ posix_unlink (call_frame_t *frame, xlator_t *this, } op_ret = posix_unlink_gfid_handle_and_entry (this, real_path, &stbuf, - &op_errno); + &op_errno, loc); if (op_ret == -1) { goto out; } @@ -6177,6 +6275,77 @@ out: return ret; } +int32_t +posix_create_unlink_dir (xlator_t *this) { + + char *unlink_path = NULL; + char *landfill_path = NULL; + struct posix_private *priv = NULL; + struct stat stbuf; + int ret = -1; + uuid_t gfid = {0}; + char gfid_str[64] = {0}; + + priv = this->private; + + unlink_path = alloca (strlen (priv->base_path) + 1 + + strlen (GF_UNLINK_PATH) + 1); + sprintf (unlink_path, "%s/%s", priv->base_path, + GF_UNLINK_PATH); + + gf_uuid_generate (gfid); + uuid_utoa_r (gfid, gfid_str); + + landfill_path = alloca (strlen (priv->base_path) + 1 + + strlen (GF_LANDFILL_PATH) + 1 + + strlen (gfid_str) + 1); + sprintf (landfill_path, "%s/%s/%s", priv->base_path, + GF_LANDFILL_PATH, gfid_str); + + ret = sys_stat (unlink_path, &stbuf); + switch (ret) { + case -1: + if (errno != ENOENT) { + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_HANDLE_CREATE, + "Checking for %s failed", + unlink_path); + return -1; + } + break; + case 0: + if (!S_ISDIR (stbuf.st_mode)) { + gf_msg (this->name, GF_LOG_ERROR, 0, + P_MSG_HANDLE_CREATE, + "Not a directory: %s", + unlink_path); + return -1; + } + ret = sys_rename (unlink_path, landfill_path); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_HANDLE_CREATE, + "Can not delete directory %s ", + unlink_path); + return -1; + } + break; + default: + break; + } + ret = sys_mkdir (unlink_path, 0600); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_HANDLE_CREATE, + "Creating directory %s failed", + unlink_path); + return -1; + } + + return 0; +} + + /** * init - @@ -6588,6 +6757,15 @@ init (xlator_t *this) goto out; } + op_ret = posix_create_unlink_dir (this); + if (op_ret == -1) { + gf_msg (this->name, GF_LOG_ERROR, 0, + P_MSG_HANDLE_CREATE, + "Creation of unlink directory failed"); + ret = -1; + goto out; + } + _private->aio_init_done = _gf_false; _private->aio_capable = _gf_false; |