summaryrefslogtreecommitdiffstats
path: root/xlators/storage/posix/src/posix.c
diff options
context:
space:
mode:
authorAshish Pandey <aspandey@redhat.com>2015-11-26 14:35:49 +0530
committerPranith Kumar Karampuri <pkarampu@redhat.com>2015-12-15 00:35:59 -0800
commitc4f6521dfe6a44cee2f61ae41fc26faaf785372d (patch)
tree2dc31b5470c7a1b3213deb4b544a2fb341c9c353 /xlators/storage/posix/src/posix.c
parentbe438f9aa70cce9d14d72d7cf8ddee89738db36c (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. Change-Id: I8344edb0d340bdb883dc46458c16edbc336916b9 BUG: 1286029 Signed-off-by: Ashish Pandey <aspandey@redhat.com> Reviewed-on: http://review.gluster.org/12816 Reviewed-by: Krutika Dhananjay <kdhananj@redhat.com> Reviewed-by: Xavier Hernandez <xhernandez@datalab.es> Tested-by: NetBSD Build System <jenkins@build.gluster.org> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
Diffstat (limited to 'xlators/storage/posix/src/posix.c')
-rw-r--r--xlators/storage/posix/src/posix.c196
1 files changed, 187 insertions, 9 deletions
diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c
index efb5f03bef1..86ac65a897d 100644
--- a/xlators/storage/posix/src/posix.c
+++ b/xlators/storage/posix/src/posix.c
@@ -101,10 +101,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 */
@@ -1446,16 +1468,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 "
@@ -1469,7 +1568,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;
@@ -1623,7 +1721,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;
}
@@ -6176,6 +6274,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 -
@@ -6587,6 +6756,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;