summaryrefslogtreecommitdiffstats
path: root/xlators/features/quota/src
diff options
context:
space:
mode:
authorRaghavendra G <rgowdapp@redhat.com>2013-10-04 13:37:38 +0530
committerAnand Avati <avati@redhat.com>2013-11-26 10:26:26 -0800
commit3f1ebe0298450cb8770a8753fe3a8a2519f78911 (patch)
tree9629ebb1fda8614032a3f00e0377f2ab92ea106f /xlators/features/quota/src
parent0d5cd92f51c02b8d664000b5a2d22a2ddbbc23b6 (diff)
features/quota: make writes short when the entire write cannot fit into available space.
This patch aims to prevent creation of infinite zero byte sized files due to amount of storage available before exceeding quota limit being less than write sizes. Imagine x bytes of storage is available before we exceed quota limit and quota enforcer is receiving writes of size y and (y > x). In this scenario, if we run a shell script like: # for i in $(seq 1 10); do dd if=/dev/zero of=$i bs=y count=1; done Then, we would end up with 10 zero byte sized files, because we allow only complete writes and all writes will fail because of lack of space. However, creates succeed since a create itself will consume zero bytes. In this pattern of creates and writes, size of volume would never grow and x bytes of space will always be available and we can end up with an infinite number of zero byte sized files. Change-Id: Ice148d6a2207883e41759f7b0be73abaa3198b41 BUG: 1012216 Signed-off-by: Raghavendra G <rgowdapp@redhat.com> Reviewed-on: http://review.gluster.org/6035 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'xlators/features/quota/src')
-rw-r--r--xlators/features/quota/src/quota.c66
-rw-r--r--xlators/features/quota/src/quota.h1
2 files changed, 57 insertions, 10 deletions
diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c
index a50fb1184a9..3c6c31def42 100644
--- a/xlators/features/quota/src/quota.c
+++ b/xlators/features/quota/src/quota.c
@@ -191,8 +191,13 @@ quota_local_new ()
{
quota_local_t *local = NULL;
local = mem_get0 (THIS->local_pool);
- if (local)
- LOCK_INIT (&local->lock);
+ if (local == NULL)
+ goto out;
+
+ LOCK_INIT (&local->lock);
+ local->space_available = -1;
+
+out:
return local;
}
@@ -342,7 +347,7 @@ quota_validate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
}
UNLOCK (&ctx->lock);
- quota_check_limit (frame, local->validate_loc.inode, this, NULL, NULL) ;
+ quota_check_limit (frame, local->validate_loc.inode, this, NULL, NULL);
return 0;
unwind:
@@ -653,6 +658,7 @@ quota_check_limit (call_frame_t *frame, inode_t *inode, xlator_t *this,
char need_validate = 0;
gf_boolean_t hard_limit_exceeded = 0;
int64_t delta = 0, wouldbe_size = 0;
+ int64_t space_available = 0;
uint64_t value = 0;
char just_validated = 0;
uuid_t trav_uuid = {0,};
@@ -742,10 +748,22 @@ quota_check_limit (call_frame_t *frame, inode_t *inode, xlator_t *this,
}
if (hard_limit_exceeded) {
- op_errno = EDQUOT;
- goto err;
- }
+ local->op_ret = -1;
+ local->op_errno = EDQUOT;
+
+ space_available = ctx->hard_lim - ctx->size;
+
+ if (space_available < 0)
+ space_available = 0;
+ if ((local->space_available < 0)
+ || (local->space_available
+ > space_available)){
+ local->space_available
+ = space_available;
+
+ }
+ }
}
if (__is_root_gfid (_inode->gfid)) {
@@ -1139,9 +1157,11 @@ quota_writev_helper (call_frame_t *frame, xlator_t *this, fd_t *fd,
struct iovec *vector, int32_t count, off_t off,
uint32_t flags, struct iobref *iobref, dict_t *xdata)
{
- quota_local_t *local = NULL;
- int32_t op_errno = EINVAL;
- quota_priv_t *priv = NULL;
+ quota_local_t *local = NULL;
+ int32_t op_errno = EINVAL;
+ quota_priv_t *priv = NULL;
+ struct iovec *new_vector = NULL;
+ int32_t new_count = 0;
priv = this->private;
@@ -1153,13 +1173,39 @@ quota_writev_helper (call_frame_t *frame, xlator_t *this, fd_t *fd,
if (local->op_ret == -1) {
op_errno = local->op_errno;
- goto unwind;
+
+ if ((op_errno == EDQUOT) && (local->space_available > 0)) {
+ new_count = iov_subset (vector, count, 0,
+ local->space_available, NULL);
+
+ new_vector = GF_CALLOC (new_count,
+ sizeof (struct iovec),
+ gf_common_mt_iovec);
+ if (new_vector == NULL) {
+ local->op_ret = -1;
+ local->op_errno = ENOMEM;
+ goto unwind;
+ }
+
+ new_count = iov_subset (vector, count, 0,
+ local->space_available,
+ new_vector);
+
+ vector = new_vector;
+ count = new_count;
+ } else {
+ goto unwind;
+ }
}
STACK_WIND (frame,
priv->is_quota_on? quota_writev_cbk: default_writev_cbk,
FIRST_CHILD(this), FIRST_CHILD(this)->fops->writev, fd,
vector, count, off, flags, iobref, xdata);
+
+ if (new_vector != NULL)
+ GF_FREE (new_vector);
+
return 0;
unwind:
diff --git a/xlators/features/quota/src/quota.h b/xlators/features/quota/src/quota.h
index de522e6914f..96c19e77eb8 100644
--- a/xlators/features/quota/src/quota.h
+++ b/xlators/features/quota/src/quota.h
@@ -176,6 +176,7 @@ struct quota_local {
call_stub_t *stub;
struct iobref *iobref;
quota_limit_t limit;
+ int64_t space_available;
};
typedef struct quota_local quota_local_t;