diff options
-rw-r--r-- | xlators/features/marker/src/marker-quota-helper.c | 8 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-quota.c | 168 | ||||
-rw-r--r-- | xlators/features/quota/src/quota.c | 5 |
3 files changed, 162 insertions, 19 deletions
diff --git a/xlators/features/marker/src/marker-quota-helper.c b/xlators/features/marker/src/marker-quota-helper.c index ce8280234ac..1fed9df6d6a 100644 --- a/xlators/features/marker/src/marker-quota-helper.c +++ b/xlators/features/marker/src/marker-quota-helper.c @@ -68,7 +68,13 @@ mq_inode_loc_fill (const char *parent_gfid, inode_t *inode, loc_t *loc) this = THIS; - if ((!inode) || (!loc)) + if (inode == NULL) { + gf_log_callingfn ("marker", GF_LOG_ERROR, "loc fill failed, " + "inode is NULL"); + return ret; + } + + if (loc == NULL) return ret; if ((inode) && __is_root_gfid (inode->gfid)) { diff --git a/xlators/features/marker/src/marker-quota.c b/xlators/features/marker/src/marker-quota.c index 7de0dd57a56..9d2f3d375e5 100644 --- a/xlators/features/marker/src/marker-quota.c +++ b/xlators/features/marker/src/marker-quota.c @@ -164,6 +164,109 @@ out: return -1; } +int +mq_build_ancestry (xlator_t *this, loc_t *loc) +{ + int32_t ret = -1; + fd_t *fd = NULL; + gf_dirent_t entries; + gf_dirent_t *entry = NULL; + dict_t *xdata = NULL; + inode_t *tmp_parent = NULL; + inode_t *tmp_inode = NULL; + inode_t *linked_inode = NULL; + quota_inode_ctx_t *ctx = NULL; + + INIT_LIST_HEAD (&entries.list); + + xdata = dict_new (); + if (xdata == NULL) { + gf_log (this->name, GF_LOG_ERROR, "dict_new failed"); + ret = -ENOMEM; + goto out; + } + + ret = dict_set_int8 (xdata, GET_ANCESTRY_DENTRY_KEY, 1); + if (ret < 0) + goto out; + + fd = fd_anonymous (loc->inode); + if (fd == NULL) { + gf_log (this->name, GF_LOG_ERROR, "fd creation failed"); + ret = -ENOMEM; + goto out; + } + + fd_bind (fd); + + ret = syncop_readdirp (this, fd, 131072, 0, &entries, xdata, NULL); + if (ret < 0) { + gf_log (this->name, (-ret == ENOENT || -ret == ESTALE) + ? GF_LOG_DEBUG:GF_LOG_ERROR, "readdirp failed " + "for %s: %s", loc->path, strerror (-ret)); + goto out; + } + + if (list_empty (&entries.list)) { + ret = -1; + goto out; + } + + list_for_each_entry (entry, &entries.list, list) { + if (__is_root_gfid (entry->inode->gfid)) { + tmp_parent = NULL; + } else { + linked_inode = inode_link (entry->inode, tmp_parent, + entry->d_name, + &entry->d_stat); + if (linked_inode) { + tmp_inode = entry->inode; + entry->inode = linked_inode; + inode_unref (tmp_inode); + } else { + gf_log (this->name, GF_LOG_ERROR, + "inode link failed"); + ret = -EINVAL; + goto out; + } + } + + ctx = mq_inode_ctx_new (entry->inode, this); + if (ctx == NULL) { + gf_log (this->name, GF_LOG_WARNING, "mq_inode_ctx_new " + "failed for %s", + uuid_utoa (entry->inode->gfid)); + ret = -ENOMEM; + goto out; + } + + tmp_parent = entry->inode; + } + + if (loc->parent) + inode_unref (loc->parent); + + loc->parent = inode_parent (loc->inode, 0, NULL); + if (loc->parent == NULL) { + ret = -1; + goto out; + } + + ret = 0; + +out: + gf_dirent_free (&entries); + + if (fd) + fd_unref (fd); + + if (xdata) + dict_unref (xdata); + + return ret; +} + + /* This function should be used only in inspect_directory and inspect_file * function to heal quota xattrs. * Inode quota feature is introduced in 3.7. @@ -1025,13 +1128,8 @@ mq_prevalidate_txn (xlator_t *this, loc_t *origin_loc, loc_t *loc, if (gf_uuid_is_null (loc->gfid)) gf_uuid_copy (loc->gfid, loc->inode->gfid); - if (!loc_is_root(loc) && loc->parent == NULL) { + if (!loc_is_root(loc) && loc->parent == NULL) loc->parent = inode_parent (loc->inode, 0, NULL); - if (loc->parent == NULL) { - ret = -1; - goto out; - } - } ret = mq_inode_ctx_get (loc->inode, this, &ctxtmp); if (ret < 0) { @@ -1128,7 +1226,7 @@ _mq_create_xattrs_txn (xlator_t *this, loc_t *origin_loc, struct iatt *buf, if (ret < 0 || status == _gf_true) goto out; - if (!loc_is_root(&loc)) { + if (!loc_is_root(&loc) && loc.parent) { contribution = mq_add_new_contribution_node (this, ctx, &loc); if (contribution == NULL) { gf_log (this->name, GF_LOG_WARNING, @@ -1206,7 +1304,8 @@ mq_reduce_parent_size_task (void *opaque) ret = mq_inode_loc_fill (NULL, loc->parent, &parent_loc); if (ret < 0) { - gf_log (this->name, GF_LOG_ERROR, "loc fill failed"); + gf_log (this->name, GF_LOG_ERROR, "parent_loc fill failed for " + "child inode %s: ", uuid_utoa (loc->inode->gfid)); goto out; } @@ -1285,7 +1384,8 @@ out: */ ret = mq_inode_ctx_get (parent_loc.inode, this, &parent_ctx); - mq_set_ctx_dirty_status (parent_ctx, _gf_false); + if (ret == 0) + mq_set_ctx_dirty_status (parent_ctx, _gf_false); } else { ret = mq_mark_dirty (this, &parent_loc, 0); } @@ -1328,6 +1428,7 @@ mq_reduce_parent_size_txn (xlator_t *this, loc_t *origin_loc, contri, nlink); out: loc_wipe (&loc); + return ret; } @@ -1382,7 +1483,7 @@ mq_initiate_quota_task (void *opaque) * if one is already in progress for same inode */ if (status == _gf_true) { - /* status will alreday set before txn start, + /* status will already set before txn start, * so it should not be set in first * loop iteration */ @@ -1392,9 +1493,28 @@ mq_initiate_quota_task (void *opaque) goto out; } + if (child_loc.parent == NULL) { + ret = mq_build_ancestry (this, &child_loc); + if (ret < 0 || child_loc.parent == NULL) { + /* If application performs parallel remove + * operations on same set of files/directories + * then we may get ENOENT/ESTALE + */ + gf_log (this->name, + (-ret == ENOENT || -ret == ESTALE) + ? GF_LOG_DEBUG:GF_LOG_ERROR, + "build ancestry failed for inode %s", + uuid_utoa (child_loc.inode->gfid)); + ret = -1; + goto out; + } + } + ret = mq_inode_loc_fill (NULL, child_loc.parent, &parent_loc); if (ret < 0) { - gf_log (this->name, GF_LOG_ERROR, "loc fill failed"); + gf_log (this->name, GF_LOG_ERROR, "parent_loc fill " + "failed for child inode %s: ", + uuid_utoa (child_loc.inode->gfid)); goto out; } @@ -1438,13 +1558,20 @@ mq_initiate_quota_task (void *opaque) wrong parent as it was holding lock on old parent so validate parent once the lock is acquired - For more information on thsi problem, please see + For more information on this problem, please see doc for marker_rename in file marker.c */ contri = mq_get_contribution_node (child_loc.parent, ctx); if (contri == NULL) { tmp_parent = inode_parent (child_loc.inode, 0, NULL); if (tmp_parent == NULL) { + /* This can happen if application performs + * parallel remove operations on same set + * of files/directories + */ + gf_log (this->name, GF_LOG_WARNING, "parent is " + "NULL for inode %s", + uuid_utoa (child_loc.inode->gfid)); ret = -1; goto out; } @@ -1476,7 +1603,6 @@ mq_initiate_quota_task (void *opaque) if (quota_meta_is_null (&delta)) goto out; - prev_dirty = 0; ret = mq_get_set_dirty (this, &parent_loc, 1, &prev_dirty); if (ret < 0) goto out; @@ -1497,8 +1623,14 @@ mq_initiate_quota_task (void *opaque) if (prev_dirty == 0) { ret = mq_mark_dirty (this, &parent_loc, 0); - dirty = _gf_false; + } else { + ret = mq_inode_ctx_get (parent_loc.inode, this, + &parent_ctx); + if (ret == 0) + mq_set_ctx_dirty_status (parent_ctx, _gf_false); } + dirty = _gf_false; + prev_dirty = 0; ret = mq_lock (this, &parent_loc, F_UNLCK); locked = _gf_false; @@ -1529,7 +1661,8 @@ out: */ ret = mq_inode_ctx_get (parent_loc.inode, this, &parent_ctx); - mq_set_ctx_dirty_status (parent_ctx, _gf_false); + if (ret == 0) + mq_set_ctx_dirty_status (parent_ctx, _gf_false); } else { ret = mq_mark_dirty (this, &parent_loc, 0); } @@ -1762,7 +1895,8 @@ out: * can set the status flag and fix the * dirty directory */ - mq_set_ctx_dirty_status (ctx, _gf_false); + if (ctx) + mq_set_ctx_dirty_status (ctx, _gf_false); } else if (dirty) { mq_mark_dirty (this, loc, 0); } @@ -1955,7 +2089,7 @@ mq_xattr_state (xlator_t *this, loc_t *origin_loc, dict_t *dict, inode_contribution_t *contribution = NULL; ret = mq_prevalidate_txn (this, origin_loc, &loc, &ctx, &buf); - if (ret < 0) + if (ret < 0 || loc.parent == NULL) goto out; if (!loc_is_root(&loc)) { diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c index 847c93f37c0..81691f1ca0f 100644 --- a/xlators/features/quota/src/quota.c +++ b/xlators/features/quota/src/quota.c @@ -825,7 +825,10 @@ quota_build_ancestry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, break; } - GF_ASSERT (&entry->list != &entries->list); + /* Getting assertion here, need to investigate + comment for now + GF_ASSERT (&entry->list != &entries->list); + */ quota_add_parent (&parents, entry->d_name, parent->gfid); } |