features/quota: maintain correct link_count in ancestry building
codepath. Ancestry building codepath can be executed simultaneously when a file has hardlinks. So, following fixes are needed: * modify local->link_count under locks in ancestry building codepath. * before invoking check_limit on newly constructed parents, link_count should not be set, but instead incremented by as many number of new invocations of check_limit. * decrementing link_count and the check whether the count has hit zero to resume the waiting call_stub should be atomic. Change-Id: I6f52e50547362a5ded6bd9f085570223aea372d1 BUG: 969461 Signed-off-by: Raghavendra G <rgowdapp@redhat.com> Reviewed-on: http://review.gluster.org/6491 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
committed by
Vijay Bellur
parent
49eb5ea29c
commit
a10100a4b8
@ -245,7 +245,7 @@ out:
|
||||
}
|
||||
|
||||
inline void
|
||||
quota_resume_fop_if_validation_done (quota_local_t *local)
|
||||
quota_link_count_decrement (quota_local_t *local)
|
||||
{
|
||||
call_stub_t *stub = NULL;
|
||||
int link_count = -1;
|
||||
@ -255,7 +255,7 @@ quota_resume_fop_if_validation_done (quota_local_t *local)
|
||||
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
link_count = local->link_count;
|
||||
link_count = --local->link_count;
|
||||
if (link_count == 0) {
|
||||
stub = local->stub;
|
||||
local->stub = NULL;
|
||||
@ -283,13 +283,11 @@ quota_handle_validate_error (quota_local_t *local, int32_t op_ret,
|
||||
local->op_ret = op_ret;
|
||||
local->op_errno = op_errno;
|
||||
}
|
||||
|
||||
/* we abort checking limits on this path to root */
|
||||
local->link_count--;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_resume_fop_if_validation_done (local);
|
||||
/* we abort checking limits on this path to root */
|
||||
quota_link_count_decrement (local);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@ -795,12 +793,8 @@ quota_check_limit (call_frame_t *frame, inode_t *inode, xlator_t *this,
|
||||
*/
|
||||
if (0 > frame->root->pid) {
|
||||
ret = 0;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
--local->link_count;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
goto resume;
|
||||
quota_link_count_decrement (local);
|
||||
goto done;
|
||||
}
|
||||
|
||||
priv = this->private;
|
||||
@ -883,12 +877,7 @@ quota_check_limit (call_frame_t *frame, inode_t *inode, xlator_t *this,
|
||||
}
|
||||
|
||||
if (__is_root_gfid (_inode->gfid)) {
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
--local->link_count;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_link_count_decrement (local);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -929,8 +918,7 @@ quota_check_limit (call_frame_t *frame, inode_t *inode, xlator_t *this,
|
||||
_inode = NULL;
|
||||
}
|
||||
|
||||
resume:
|
||||
quota_resume_fop_if_validation_done (local);
|
||||
done:
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -1303,13 +1291,18 @@ quota_writev (call_frame_t *frame, xlator_t *this, fd_t *fd,
|
||||
UNLOCK (&ctx->lock);
|
||||
}
|
||||
|
||||
local->delta = size;
|
||||
|
||||
local->link_count = parents;
|
||||
local->stub = stub;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->delta = size;
|
||||
local->link_count = (parents != 0) ? parents : 1;
|
||||
local->stub = stub;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
if (parents == 0) {
|
||||
local->link_count = 1;
|
||||
/* nameless lookup on this inode, allow quota to reconstruct
|
||||
* ancestry as part of check_limit.
|
||||
*/
|
||||
quota_check_limit (frame, fd->inode, this, NULL, NULL);
|
||||
} else {
|
||||
list_for_each_entry_safe (dentry, tmp, &head, next) {
|
||||
@ -1412,9 +1405,13 @@ quota_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->stub = stub;
|
||||
local->delta = 0;
|
||||
local->link_count = 1;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->stub = stub;
|
||||
local->delta = 0;
|
||||
local->link_count = 1;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_check_limit (frame, loc->parent, this, NULL, NULL);
|
||||
return 0;
|
||||
@ -1557,9 +1554,13 @@ quota_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
local->delta = 0;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
local->delta = 0;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_check_limit (frame, loc->parent, this, NULL, NULL);
|
||||
return 0;
|
||||
@ -1829,9 +1830,13 @@ quota_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
local->delta = (ctx != NULL) ? ctx->buf.ia_blocks * 512 : 0;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
local->delta = (ctx != NULL) ? ctx->buf.ia_blocks * 512 : 0;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_check_limit (frame, newloc->parent, this, NULL, NULL);
|
||||
return 0;
|
||||
@ -2072,8 +2077,12 @@ quota_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc,
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
if (QUOTA_REG_OR_LNK_FILE (oldloc->inode->ia_type)) {
|
||||
ret = quota_inode_ctx_get (oldloc->inode, this, &ctx, 0);
|
||||
@ -2248,9 +2257,13 @@ quota_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath,
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->stub = stub;
|
||||
local->delta = strlen (linkpath);
|
||||
local->link_count = 1;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->stub = stub;
|
||||
local->delta = strlen (linkpath);
|
||||
local->link_count = 1;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_check_limit (frame, loc->parent, this, NULL, NULL);
|
||||
return 0;
|
||||
@ -3207,9 +3220,13 @@ quota_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
local->delta = 0;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
local->delta = 0;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
quota_check_limit (frame, loc->parent, this, NULL, NULL);
|
||||
return 0;
|
||||
@ -3655,9 +3672,7 @@ quota_statfs_validate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
UNLOCK (&ctx->lock);
|
||||
|
||||
resume:
|
||||
--local->link_count;
|
||||
|
||||
quota_resume_fop_if_validation_done (local);
|
||||
quota_link_count_decrement (local);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3682,26 +3697,26 @@ quota_statfs (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
|
||||
}
|
||||
frame->local = local;
|
||||
|
||||
local->inode = inode_ref (loc->inode);
|
||||
local->link_count = 1;
|
||||
|
||||
stub = fop_statfs_stub (frame, quota_statfs_helper, loc, xdata);
|
||||
if (!stub) {
|
||||
op_errno = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->stub = stub;
|
||||
LOCK (&local->lock);
|
||||
{
|
||||
local->inode = inode_ref (loc->inode);
|
||||
local->link_count = 1;
|
||||
local->stub = stub;
|
||||
}
|
||||
UNLOCK (&local->lock);
|
||||
|
||||
ret = quota_validate (frame, local->inode, this,
|
||||
quota_statfs_validate_cbk);
|
||||
if (0 > ret) {
|
||||
op_errno = -ret;
|
||||
--local->link_count;
|
||||
quota_handle_validate_error (local, -1, -ret);
|
||||
}
|
||||
|
||||
quota_resume_fop_if_validation_done (local);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user