summaryrefslogtreecommitdiffstats
path: root/xlators/features/quota/src/quota.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/features/quota/src/quota.c')
-rw-r--r--xlators/features/quota/src/quota.c243
1 files changed, 212 insertions, 31 deletions
diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c
index 7d5f74e9c..c527e7ca7 100644
--- a/xlators/features/quota/src/quota.c
+++ b/xlators/features/quota/src/quota.c
@@ -1,22 +1,12 @@
/*
- Copyright (c) 2008-2011 Gluster, Inc. <http://www.gluster.com>
- This file is part of GlusterFS.
-
- GlusterFS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- GlusterFS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see
- <http://www.gnu.org/licenses/>.
-*/
+ Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
#include <fnmatch.h>
#include "quota.h"
@@ -136,6 +126,7 @@ quota_local_cleanup (xlator_t *this, quota_local_t *local)
inode_unref (local->inode);
LOCK_DESTROY (&local->lock);
+ mem_put (local);
out:
return 0;
}
@@ -497,8 +488,7 @@ quota_get_limit_value (inode_t *inode, xlator_t *this, int64_t *n)
}
out:
- if (path)
- GF_FREE (path);
+ GF_FREE (path);
return ret;
}
@@ -2704,7 +2694,6 @@ int
quota_setxattr (call_frame_t *frame, xlator_t *this,
loc_t *loc, dict_t *dict, int flags, dict_t *xdata)
{
- data_pair_t *trav = NULL;
int op_errno = EINVAL;
int op_ret = -1;
@@ -2713,7 +2702,7 @@ quota_setxattr (call_frame_t *frame, xlator_t *this,
VALIDATE_OR_GOTO (loc, err);
GF_IF_INTERNAL_XATTR_GOTO ("trusted.glusterfs.quota*", dict,
- trav, op_errno, err);
+ op_errno, err);
STACK_WIND (frame, quota_setxattr_cbk,
FIRST_CHILD(this),
@@ -2737,7 +2726,6 @@ int
quota_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd,
dict_t *dict, int flags, dict_t *xdata)
{
- data_pair_t *trav = NULL;
int32_t op_ret = -1;
int32_t op_errno = EINVAL;
@@ -2746,7 +2734,7 @@ quota_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd,
VALIDATE_OR_GOTO (fd, err);
GF_IF_INTERNAL_XATTR_GOTO ("trusted.glusterfs.quota*", dict,
- trav, op_errno, err);
+ op_errno, err);
STACK_WIND (frame, quota_fsetxattr_cbk,
FIRST_CHILD(this),
@@ -2908,8 +2896,11 @@ int32_t
quota_statfs (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
{
inode_t *root_inode = NULL;
+ quota_priv_t *priv = NULL;
+
+ priv = this->private;
- if (loc->inode) {
+ if (priv->consider_statfs && loc->inode) {
root_inode = loc->inode->table->root;
inode_ref(root_inode);
STACK_WIND_COOKIE (frame, quota_statfs_cbk, root_inode,
@@ -2923,9 +2914,13 @@ quota_statfs (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
* which is exactly what would happen with STACK_UNWIND using
* that as a callback. Therefore, use default_statfs_cbk in
* this case instead.
+ *
+ * Also if the option deem-statfs is not set to "on" don't
+ * bother calculating quota limit on / in statfs_cbk.
*/
- gf_log(this->name,GF_LOG_WARNING,
- "missing inode, cannot adjust for quota");
+ if (priv->consider_statfs)
+ gf_log(this->name,GF_LOG_WARNING,
+ "missing inode, cannot adjust for quota");
STACK_WIND (frame, default_statfs_cbk, FIRST_CHILD(this),
FIRST_CHILD(this)->fops->statfs, loc, xdata);
}
@@ -2974,6 +2969,177 @@ err:
return 0;
}
+int32_t
+quota_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf, dict_t *xdata)
+{
+ int32_t ret = 0;
+ uint64_t ctx_int = 0;
+ quota_inode_ctx_t *ctx = NULL;
+ quota_local_t *local = NULL;
+ quota_dentry_t *dentry = NULL;
+ int64_t delta = 0;
+
+ local = frame->local;
+
+ if ((op_ret < 0) || (local == NULL)) {
+ goto out;
+ }
+
+ ret = inode_ctx_get (local->loc.inode, this, &ctx_int);
+ if (ret) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "%s: failed to get the context", local->loc.path);
+ goto out;
+ }
+
+ ctx = (quota_inode_ctx_t *)(unsigned long) ctx_int;
+
+ if (ctx == NULL) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "quota context not set in %s (gfid:%s)",
+ local->loc.path, uuid_utoa (local->loc.inode->gfid));
+ goto out;
+ }
+
+ LOCK (&ctx->lock);
+ {
+ ctx->buf = *postbuf;
+ }
+ UNLOCK (&ctx->lock);
+
+ list_for_each_entry (dentry, &ctx->parents, next) {
+ delta = (postbuf->ia_blocks - prebuf->ia_blocks) * 512;
+ quota_update_size (this, local->loc.inode,
+ dentry->name, dentry->par, delta);
+ }
+
+out:
+ QUOTA_STACK_UNWIND (fallocate, frame, op_ret, op_errno, prebuf, postbuf,
+ xdata);
+
+ return 0;
+}
+
+int32_t
+quota_fallocate_helper(call_frame_t *frame, xlator_t *this, fd_t *fd,
+ int32_t mode, off_t offset, size_t len, dict_t *xdata)
+{
+ quota_local_t *local = NULL;
+ int32_t op_errno = EINVAL;
+
+ local = frame->local;
+ if (local == NULL) {
+ gf_log (this->name, GF_LOG_WARNING, "local is NULL");
+ goto unwind;
+ }
+
+ if (local->op_ret == -1) {
+ op_errno = local->op_errno;
+ goto unwind;
+ }
+
+ STACK_WIND (frame, quota_fallocate_cbk, FIRST_CHILD(this),
+ FIRST_CHILD(this)->fops->fallocate, fd, mode, offset, len,
+ xdata);
+ return 0;
+
+unwind:
+ QUOTA_STACK_UNWIND (fallocate, frame, -1, op_errno, NULL, NULL, NULL);
+ return 0;
+}
+
+int32_t
+quota_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode,
+ off_t offset, size_t len, dict_t *xdata)
+{
+ int32_t ret = -1, op_errno = EINVAL;
+ int32_t parents = 0;
+ quota_local_t *local = NULL;
+ quota_inode_ctx_t *ctx = NULL;
+ quota_priv_t *priv = NULL;
+ call_stub_t *stub = NULL;
+ quota_dentry_t *dentry = NULL;
+
+ GF_ASSERT (frame);
+ GF_VALIDATE_OR_GOTO ("quota", this, unwind);
+ GF_VALIDATE_OR_GOTO (this->name, fd, unwind);
+
+ local = quota_local_new ();
+ if (local == NULL) {
+ goto unwind;
+ }
+
+ frame->local = local;
+ local->loc.inode = inode_ref (fd->inode);
+
+ ret = quota_inode_ctx_get (fd->inode, -1, this, NULL, NULL, &ctx, 0);
+ if (ctx == NULL) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "quota context not set in inode (gfid:%s)",
+ uuid_utoa (fd->inode->gfid));
+ goto unwind;
+ }
+
+ stub = fop_fallocate_stub(frame, quota_fallocate_helper, fd, mode, offset, len,
+ xdata);
+ if (stub == NULL) {
+ op_errno = ENOMEM;
+ goto unwind;
+ }
+
+ priv = this->private;
+ GF_VALIDATE_OR_GOTO (this->name, priv, unwind);
+
+ LOCK (&ctx->lock);
+ {
+ list_for_each_entry (dentry, &ctx->parents, next) {
+ parents++;
+ }
+ }
+ UNLOCK (&ctx->lock);
+
+ /*
+ * Note that by using len as the delta we're assuming the range from
+ * offset to offset+len has not already been allocated. This can result
+ * in ENOSPC errors attempting to allocate an already allocated range.
+ */
+ local->delta = len;
+ local->stub = stub;
+ local->link_count = parents;
+
+ list_for_each_entry (dentry, &ctx->parents, next) {
+ ret = quota_check_limit (frame, fd->inode, this, dentry->name,
+ dentry->par);
+ if (ret == -1) {
+ break;
+ }
+ }
+
+ stub = NULL;
+
+ LOCK (&local->lock);
+ {
+ local->link_count = 0;
+ if (local->validate_count == 0) {
+ stub = local->stub;
+ local->stub = NULL;
+ }
+ }
+ UNLOCK (&local->lock);
+
+ if (stub != NULL) {
+ call_resume (stub);
+ }
+
+ return 0;
+
+unwind:
+ QUOTA_STACK_UNWIND (fallocate, frame, -1, op_errno, NULL, NULL, NULL);
+ return 0;
+}
+
int32_t
mem_acct_init (xlator_t *this)
@@ -3037,14 +3203,17 @@ quota_parse_limits (quota_priv_t *priv, xlator_t *this, dict_t *xl_options,
char *path = NULL, *saveptr = NULL;
uint64_t value = 0;
limits_t *quota_lim = NULL, *old = NULL;
+ char *last_colon= NULL;
ret = dict_get_str (xl_options, "limit-set", &str);
if (str) {
- path = strtok_r (str, ":", &saveptr);
+ path = strtok_r (str, ",", &saveptr);
while (path) {
- str_val = strtok_r (NULL, ",", &saveptr);
+ last_colon = strrchr (path, ':');
+ *last_colon = '\0';
+ str_val = last_colon + 1;
ret = gf_string2bytesize (str_val, &value);
if (ret != 0)
@@ -3078,7 +3247,7 @@ quota_parse_limits (quota_priv_t *priv, xlator_t *this, dict_t *xl_options,
}
UNLOCK (&priv->lock);
- path = strtok_r (NULL, ":", &saveptr);
+ path = strtok_r (NULL, ",", &saveptr);
}
} else {
gf_log (this->name, GF_LOG_INFO,
@@ -3134,6 +3303,7 @@ init (xlator_t *this)
}
GF_OPTION_INIT ("timeout", priv->timeout, int64, err);
+ GF_OPTION_INIT ("deem-statfs", priv->consider_statfs, bool, err);
this->local_pool = mem_pool_new (quota_local_t, 64);
if (!this->local_pool) {
@@ -3233,9 +3403,10 @@ reconfigure (xlator_t *this, dict_t *options)
LOCK (&priv->lock);
{
- list_for_each_entry (limit, &priv->limit_head, limit_list) {
- top = ((glusterfs_ctx_t *)this->ctx)->active->top;
+ top = ((glusterfs_ctx_t *)this->ctx)->active->top;
+ GF_ASSERT (top);
+ list_for_each_entry (limit, &priv->limit_head, limit_list) {
__quota_reconfigure (this, top->itable, limit);
}
@@ -3261,6 +3432,8 @@ reconfigure (xlator_t *this, dict_t *options)
UNLOCK (&priv->lock);
GF_OPTION_RECONF ("timeout", priv->timeout, options, int64, out);
+ GF_OPTION_RECONF ("deem-statfs", priv->consider_statfs, options, bool,
+ out);
ret = 0;
out:
@@ -3302,6 +3475,7 @@ struct xlator_fops fops = {
.removexattr = quota_removexattr,
.fremovexattr = quota_fremovexattr,
.readdirp = quota_readdirp,
+ .fallocate = quota_fallocate,
};
struct xlator_cbks cbks = {
@@ -3318,5 +3492,12 @@ struct volume_options options[] = {
.description = "quota caches the directory sizes on client. Timeout "
"indicates the timeout for the cache to be revalidated."
},
+ {.key = {"deem-statfs"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .default_value = "off",
+ .description = "If set to on, it takes quota limits into"
+ "consideration while estimating fs size. (df command)"
+ " (Default is off)."
+ },
{.key = {NULL}}
};