diff options
-rw-r--r-- | xlators/features/quota/src/quota.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c index 3ec480a94df..3ff3d1bded9 100644 --- a/xlators/features/quota/src/quota.c +++ b/xlators/features/quota/src/quota.c @@ -19,6 +19,7 @@ #include "quota.h" #include "common-utils.h" +#include "defaults.h" int32_t quota_check_limit (call_frame_t *frame, inode_t *inode, xlator_t *this, @@ -2683,6 +2684,102 @@ err: int32_t +quota_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf) +{ + inode_t *root_inode = NULL; + quota_priv_t *priv = NULL; + uint64_t value = 0; + quota_inode_ctx_t *ctx = NULL; + limits_t *limit_node = NULL; + int64_t usage = -1; + int64_t avail = -1; + + root_inode = cookie; + /* + * We should never get here unless quota_statfs (below) sent us a + * cookie, and it would only do so if the value was non-NULL. This + * check is therefore just routine defensive coding. + */ + if (!root_inode) { + gf_log(this->name,GF_LOG_WARNING, + "null inode, cannot adjust for quota"); + goto unwind; + } + if (!root_inode->table || (root_inode != root_inode->table->root)) { + gf_log(this->name,GF_LOG_WARNING, + "non-root inode, cannot adjust for quota"); + goto unwind; + } + + inode_ctx_get (root_inode, this, &value); + if (!value) { + goto unwind; + } + ctx = (quota_inode_ctx_t *)(unsigned long)value; + usage = (ctx->size) / buf->f_bsize; + priv = this->private; + + list_for_each_entry (limit_node, &priv->limit_head, limit_list) { + /* Notice that this only works for volume-level quota. */ + if (strcmp (limit_node->path, "/") == 0) { + buf->f_blocks = limit_node->value / buf->f_bsize; + avail = buf->f_blocks - usage; + if (buf->f_bfree > avail) { + buf->f_bfree = avail; + } + /* + * We have to assume that the total assigned quota + * won't cause us to dip into the reserved space, + * because dealing with the overcommitted cases is + * just too hairy (especially when different bricks + * might be using different reserved percentages and + * such). + */ + buf->f_bavail = buf->f_bfree; + break; + } + } + +unwind: + if (root_inode) { + inode_unref(root_inode); + } + STACK_UNWIND_STRICT (statfs, frame, op_ret, op_errno, buf); + return 0; +} + + +int32_t +quota_statfs (call_frame_t *frame, xlator_t *this, loc_t *loc) +{ + inode_t *root_inode = NULL; + + if (loc->inode) { + root_inode = loc->inode->table->root; + inode_ref(root_inode); + STACK_WIND_COOKIE (frame, quota_statfs_cbk, root_inode, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->statfs, loc); + } + else { + /* + * We have to make sure that we never get to quota_statfs_cbk + * with a cookie that points to something other than an inode, + * which is exactly what would happen with STACK_UNWIND using + * that as a callback. Therefore, use default_statfs_cbk in + * this case instead. + */ + 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); + } + return 0; +} + + +int32_t mem_acct_init (xlator_t *this) { int ret = -1; @@ -2865,6 +2962,7 @@ fini (xlator_t *this) struct xlator_fops fops = { + .statfs = quota_statfs, .lookup = quota_lookup, .writev = quota_writev, .create = quota_create, |