summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xlators/features/quota/src/quota.c98
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,