From 8dcde0c22322cd8c32dcf13d8caa05eec4d07208 Mon Sep 17 00:00:00 2001 From: Amar Tumballi Date: Sat, 20 Sep 2008 00:57:38 +0000 Subject: [PATCH] * cleanup of glusterfs_ctx from fuse, now, whenever umount is called, raise (SIGTERM) will happen, and xlator->fini() is called for every xlator in the graph. * gf_string2bytesize takes uint64_t instead of size_t, which is 32bit on 32bit machine, and hence fails to take more than 4GB as input. * added quota translator. Currently is designed to sit atop the posix translator, and takes 'min-free-disk-limit' (in %), or 'disk-usage-limit' in (bytes) as options. --- configure.ac | 2 + glusterfs/src/glusterfs.c | 15 +- libglusterfs/src/common-utils.c | 8 +- libglusterfs/src/common-utils.h | 6 +- libglusterfs/src/revision.h | 2 +- libglusterfs/src/xlator.c | 7 +- scheduler/alu/src/alu.c | 10 +- xlators/cluster/stripe/src/stripe.c | 4 +- xlators/features/Makefile.am | 2 +- xlators/features/quota/Makefile.am | 3 + xlators/features/quota/src/Makefile.am | 13 + xlators/features/quota/src/quota.c | 945 ++++++++++++++++++ xlators/mount/fuse/src/fuse-bridge.c | 52 +- xlators/performance/io-cache/src/io-cache.c | 12 +- xlators/performance/io-cache/src/io-cache.h | 4 +- .../performance/io-threads/src/io-threads.c | 26 +- .../performance/io-threads/src/io-threads.h | 2 +- .../performance/read-ahead/src/read-ahead.c | 4 +- .../performance/read-ahead/src/read-ahead.h | 4 +- .../write-behind/src/write-behind.c | 21 +- xlators/protocol/client/src/client-protocol.h | 2 +- xlators/storage/bdb/src/bdb.h | 2 +- xlators/storage/posix/src/posix.c | 2 +- 23 files changed, 1037 insertions(+), 111 deletions(-) create mode 100644 xlators/features/quota/Makefile.am create mode 100644 xlators/features/quota/src/Makefile.am create mode 100644 xlators/features/quota/src/quota.c diff --git a/configure.ac b/configure.ac index 9f6baa1cdde..7cf68fa1dbd 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,8 @@ AC_CONFIG_FILES([Makefile xlators/features/trash/src/Makefile xlators/features/filter/Makefile xlators/features/filter/src/Makefile + xlators/features/quota/Makefile + xlators/features/quota/src/Makefile xlators/encryption/Makefile xlators/encryption/rot-13/Makefile xlators/encryption/rot-13/src/Makefile diff --git a/glusterfs/src/glusterfs.c b/glusterfs/src/glusterfs.c index 579db1010ab..ebc61aa9bfd 100644 --- a/glusterfs/src/glusterfs.c +++ b/glusterfs/src/glusterfs.c @@ -532,11 +532,9 @@ void cleanup_and_exit (int signum) { glusterfs_ctx_t *ctx = NULL; - + xlator_t *trav = NULL; ctx = get_global_ctx_ptr (); - gf_log (progname, GF_LOG_WARNING, "shutting down"); - if (ctx->pidfp) { gf_unlockfd (fileno (ctx->pidfp)); fclose (ctx->pidfp); @@ -545,8 +543,15 @@ cleanup_and_exit (int signum) if (ctx->cmd_args.pid_file) unlink (ctx->cmd_args.pid_file); - if (ctx->graph && ctx->cmd_args.mount_point) - ((xlator_t *)ctx->graph)->fini (ctx->graph); + if (ctx->graph) { + trav = ctx->graph; + while (trav) { + trav->fini (trav); + trav = trav->next; + } + } + + gf_log (progname, GF_LOG_WARNING, "shutting down"); exit (0); } diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 4c4d7b9d029..375d4f65538 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -51,8 +51,8 @@ typedef int32_t (*rw_op_t)(int32_t fd, char *buf, int32_t size); typedef int32_t (*rwv_op_t)(int32_t fd, const struct iovec *buf, int32_t size); static glusterfs_ctx_t *gf_global_ctx; -int64_t total_bytes_xferd; -int64_t total_bytes_rcvd; +uint64_t total_bytes_xferd; +uint64_t total_bytes_rcvd; static int32_t full_rw (int32_t fd, char *buf, int32_t size, @@ -154,7 +154,7 @@ void gf_print_bytes () { gf_log ("glusterfs", GF_LOG_WARNING, - "Total data (in bytes): transfered (%"PRId64"), received (%"PRId64")", + "Total data (in bytes): transfered (%"PRIu64"), received (%"PRIu64")", total_bytes_xferd, total_bytes_rcvd); } @@ -1222,7 +1222,7 @@ gf_string2uint64_base10 (const char *str, uint64_t *n) } int -gf_string2bytesize (const char *str, size_t *n) +gf_string2bytesize (const char *str, uint64_t *n) { uint64_t value = 0ULL; char *tail = NULL; diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index e1ed92cdb51..9c200025fc3 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -99,8 +99,8 @@ void gf_print_bytes (void); void gf_log_volume_specfile (FILE *specfp); void gf_print_trace (int32_t signal); -extern int64_t total_bytes_xferd; -extern int64_t total_bytes_rcvd; +extern uint64_t total_bytes_xferd; +extern uint64_t total_bytes_rcvd; extern char *gf_fop_list[GF_FOP_MAXVALUE]; extern char *gf_mop_list[GF_MOP_MAXVALUE]; @@ -277,7 +277,7 @@ int gf_string2uint16_base10 (const char *str, uint16_t *n); int gf_string2uint32_base10 (const char *str, uint32_t *n); int gf_string2uint64_base10 (const char *str, uint64_t *n); -int gf_string2bytesize (const char *str, size_t *n); +int gf_string2bytesize (const char *str, uint64_t *n); int gf_string2boolean (const char *str, gf_boolean_t *b); int gf_string2percent (const char *str, uint32_t *n); diff --git a/libglusterfs/src/revision.h b/libglusterfs/src/revision.h index 92b660b93d6..2f440e646f8 100644 --- a/libglusterfs/src/revision.h +++ b/libglusterfs/src/revision.h @@ -1 +1 @@ -#define GLUSTERFS_REPOSITORY_REVISION "glusterfs--mainline--3.0--patch-378" +#define GLUSTERFS_REPOSITORY_REVISION "glusterfs--mainline--3.0--patch-379" diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index 39d05d3989f..5f86bafaceb 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -113,7 +113,7 @@ xlator_validate_given_options (xlator_t *xl) data_pair_t *pairs = NULL; int32_t index = 0; int32_t valid = 0; - int64_t input_size = 0; + uint64_t input_size = 0; long long inputll = 0; if (!xl->std_options) @@ -195,10 +195,8 @@ xlator_validate_given_options (xlator_t *xl) break; case GF_OPTION_TYPE_SIZET: { - size_t tmp_size = 0; - /* Check the range */ - if (gf_string2bytesize (pairs->value->data, &tmp_size) != 0) { + if (gf_string2bytesize (pairs->value->data, &input_size) != 0) { gf_log (xl->name, GF_LOG_ERROR, "invalid number format \"%s\" in \"option %s\"", @@ -206,7 +204,6 @@ xlator_validate_given_options (xlator_t *xl) return -1; } - input_size = (int64_t)tmp_size; if (trav->min_value == -1) { gf_log (xl->name, GF_LOG_DEBUG, "no range check required for 'option %s %s'", diff --git a/scheduler/alu/src/alu.c b/scheduler/alu/src/alu.c index 20d3a796604..3d7384773b3 100644 --- a/scheduler/alu/src/alu.c +++ b/scheduler/alu/src/alu.c @@ -180,9 +180,7 @@ alu_init (xlator_t *xl) entry_fn = dict_get (xl->options, "alu.disk-usage.entry-threshold"); if (entry_fn) { - size_t tmp_du = 0; - - if (gf_string2bytesize (entry_fn->data, &tmp_du) != 0) + if (gf_string2bytesize (entry_fn->data, &alu_sched->entry_limit.disk_usage) != 0) { gf_log ("alu", GF_LOG_ERROR, @@ -190,7 +188,6 @@ alu_init (xlator_t *xl) entry_fn->data); return -1; } - alu_sched->entry_limit.disk_usage = (uint64_t)tmp_du; } else { @@ -200,9 +197,7 @@ alu_init (xlator_t *xl) exit_fn = dict_get (xl->options, "alu.disk-usage.exit-threshold"); if (exit_fn) { - size_t tmp_du = 0; - - if (gf_string2bytesize (exit_fn->data, &tmp_du) != 0) + if (gf_string2bytesize (exit_fn->data, &alu_sched->exit_limit.disk_usage) != 0) { gf_log ("alu", GF_LOG_ERROR, @@ -210,7 +205,6 @@ alu_init (xlator_t *xl) exit_fn->data); return -1; } - alu_sched->exit_limit.disk_usage = (uint64_t)tmp_du; } else { diff --git a/xlators/cluster/stripe/src/stripe.c b/xlators/cluster/stripe/src/stripe.c index 23f58e03bd1..858c4c71d08 100644 --- a/xlators/cluster/stripe/src/stripe.c +++ b/xlators/cluster/stripe/src/stripe.c @@ -61,7 +61,7 @@ struct stripe_local; */ struct stripe_private { xlator_t **xl_array; - size_t block_size; + uint64_t block_size; gf_lock_t lock; uint8_t nodes_down; int8_t first_child_down; @@ -3080,7 +3080,7 @@ init (xlator_t *this) } } - gf_log (this->name, GF_LOG_DEBUG, "stripe block size %d", priv->block_size); + gf_log (this->name, GF_LOG_DEBUG, "stripe block size %"PRIu64"", priv->block_size); /* notify related */ priv->nodes_down = priv->child_count; diff --git a/xlators/features/Makefile.am b/xlators/features/Makefile.am index 528ffbb31cf..afa8b97f699 100644 --- a/xlators/features/Makefile.am +++ b/xlators/features/Makefile.am @@ -14,6 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -SUBDIRS = posix-locks trash path-convertor filter +SUBDIRS = posix-locks trash path-convertor filter quota CLEANFILES = diff --git a/xlators/features/quota/Makefile.am b/xlators/features/quota/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/xlators/features/quota/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/features/quota/src/Makefile.am b/xlators/features/quota/src/Makefile.am new file mode 100644 index 00000000000..886d839643c --- /dev/null +++ b/xlators/features/quota/src/Makefile.am @@ -0,0 +1,13 @@ +xlator_LTLIBRARIES = quota.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +quota_la_LDFLAGS = -module -avoidversion + +quota_la_SOURCES = quota.c +quota_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \ + -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) + +CLEANFILES = + diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c new file mode 100644 index 00000000000..6388dc47b81 --- /dev/null +++ b/xlators/features/quota/src/quota.c @@ -0,0 +1,945 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. + 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 + . +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include + +#include "xlator.h" +#include "defaults.h" +#include "common-utils.h" + +struct quota_local { + struct stat stbuf; + inode_t *inode; + char *path; + fd_t *fd; + off_t offset; + int32_t count; + struct iovec *vector; + dict_t *refs; +}; + +struct quota_priv { + char only_first_time; /* Used to make sure a call is done only one time */ + gf_lock_t lock; /* Used while updating variables */ + + fsblkcnt_t disk_usage_limit; /* Used for Disk usage quota */ + fsblkcnt_t current_disk_usage; /* Keep the current usage value */ + + uint32_t min_free_disk_limit; /* user specified limit, in % */ + uint32_t current_free_disk; /* current free disk space available, in % */ + uint32_t min_free_disk_refresh; /* interval in seconds */ + uint32_t min_disk_last_updated_time; /* used for interval calculation */ +}; + +int32_t +quota_statvfs_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct statvfs *stbuf) +{ + struct quota_priv *priv = this->private; + + if (op_ret >= 0) { + priv->current_free_disk = (stbuf->f_bavail * 100) / stbuf->f_blocks; + } + + STACK_DESTROY (frame->root); + return 0; +} +void +gf_quota_update_current_free_disk (xlator_t *this) +{ + call_ctx_t *cctx = NULL; + call_pool_t *pool = this->ctx->pool; + + cctx = calloc (1, sizeof (*cctx)); + ERR_ABORT (cctx); + cctx->frames.root = cctx; + cctx->frames.this = this; + cctx->pool = pool; + LOCK (&pool->lock); + { + list_add (&cctx->all_frames, &pool->all_frames); + } + UNLOCK (&pool->lock); + + { + loc_t tmp_loc = { + .inode = NULL, + .path = "/", + }; + STACK_WIND ((&cctx->frames), + quota_statvfs_cbk, + this->children->xlator, + this->children->xlator->fops->statfs, + &tmp_loc); + } + + return ; +} + +static int +gf_quota_check_free_disk (xlator_t *this) +{ + struct quota_priv * priv = NULL; + struct timeval tv = {0, 0}; + + priv = this->private; + if (priv->min_free_disk_limit) { + gettimeofday (&tv, NULL); + if (tv.tv_sec > (priv->min_free_disk_refresh + + priv->min_disk_last_updated_time)) { + priv->min_disk_last_updated_time = tv.tv_sec; + gf_quota_update_current_free_disk (this); + } + if (priv->current_free_disk <= priv->min_free_disk_limit) + return -1; + } + + return 0; +} + + +static int32_t +quota_truncate_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + struct quota_priv *priv = this->private; + if ((op_ret >= 0) && priv->disk_usage_limit) { + LOCK (&priv->lock); + { + priv->current_disk_usage -= (buf->st_blocks * 512); + } + UNLOCK (&priv->lock); + } + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +int32_t +quota_truncate (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + off_t offset) +{ + STACK_WIND (frame, + quota_truncate_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->truncate, + loc, offset); + return 0; +} + +static int32_t +quota_ftruncate_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + struct quota_priv *priv = this->private; + if ((op_ret >= 0) && priv->disk_usage_limit) { + LOCK (&priv->lock); + { + priv->current_disk_usage -= (buf->st_blocks * 512); + } + UNLOCK (&priv->lock); + } + STACK_UNWIND (frame, op_ret, op_errno, buf); + return 0; +} + +int32_t +quota_ftruncate (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset) +{ + STACK_WIND (frame, + quota_ftruncate_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->ftruncate, + fd, offset); + return 0; +} + + + +static int32_t +quota_mknod_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf) +{ + struct quota_priv *priv = this->private; + if ((op_ret >= 0) && priv->disk_usage_limit) { + LOCK (&priv->lock); + { + priv->current_disk_usage += (buf->st_blocks * 512); + } + UNLOCK (&priv->lock); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + return 0; +} + +int32_t +quota_mknod (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode, + dev_t rdev) +{ + struct quota_priv *priv = this->private; + if (gf_quota_check_free_disk (this) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "min-free-disk limit (%u) crossed, current available is %u", + priv->min_free_disk_limit, priv->current_free_disk); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL); + return 0; + } + if (priv->current_disk_usage > priv->disk_usage_limit) { + gf_log (this->name, GF_LOG_ERROR, + "Disk usage limit (%"PRIu64") crossed, current usage is %"PRIu64"", + priv->disk_usage_limit, priv->current_disk_usage); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL); + return 0; + } + + STACK_WIND (frame, + quota_mknod_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mknod, + loc, mode, rdev); + return 0; +} + +static int32_t +quota_mkdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf) +{ + struct quota_priv *priv = this->private; + if ((op_ret >= 0) && priv->disk_usage_limit) { + LOCK (&priv->lock); + { + priv->current_disk_usage += (buf->st_blocks * 512); + } + UNLOCK (&priv->lock); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + return 0; +} + +int32_t +quota_mkdir (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + mode_t mode) +{ + struct quota_priv *priv = this->private; + if (gf_quota_check_free_disk (this) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "min-free-disk limit (%u) crossed, current available is %u", + priv->min_free_disk_limit, priv->current_free_disk); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL); + return 0; + + } + if (priv->current_disk_usage > priv->disk_usage_limit) { + gf_log (this->name, GF_LOG_ERROR, + "Disk usage limit (%"PRIu64") crossed, current usage is %"PRIu64"", + priv->disk_usage_limit, priv->current_disk_usage); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL); + return 0; + } + + STACK_WIND (frame, + quota_mkdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mkdir, + loc, mode); + + return 0; +} + +static int32_t +quota_unlink_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + struct quota_local *local = frame->local; + struct quota_priv *priv = this->private; + + if (local) { + if (op_ret >= 0) { + LOCK (&priv->lock); + { + priv->current_disk_usage -= (local->stbuf.st_blocks * 512); + } + UNLOCK (&priv->lock); + } + FREE (local->path); + inode_unref (local->inode); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +int32_t +quota_unlink_stat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + loc_t tmp_loc; + struct quota_local *local = frame->local; + if (op_ret >= 0) { + if (buf->st_nlink == 1) { + local->stbuf = *buf; + } + } + + tmp_loc.path = local->path; + tmp_loc.inode = local->inode; + + STACK_WIND (frame, + quota_unlink_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, + &tmp_loc); + + return 0; +} + +int32_t +quota_unlink (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + struct quota_local *local = NULL; + struct quota_priv *priv = this->private; + + if (priv->disk_usage_limit) { + local = calloc (1, sizeof (struct quota_local)); + local->path = strdup (loc->path); + local->inode = inode_ref (loc->inode); + frame->local = local; + STACK_WIND (frame, + quota_unlink_stat_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->stat, + loc); + return 0; + } + + STACK_WIND (frame, + quota_unlink_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, + loc); + return 0; +} + +static int32_t +quota_rmdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + struct quota_local *local = frame->local; + struct quota_priv *priv = this->private; + + if (local) { + if (op_ret >= 0) { + LOCK (&priv->lock); + { + priv->current_disk_usage -= (local->stbuf.st_blocks * 512); + } + UNLOCK (&priv->lock); + } + FREE (local->path); + inode_unref (local->inode); + } + + STACK_UNWIND (frame, op_ret, op_errno); + return 0; +} + +int32_t +quota_rmdir_stat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + loc_t tmp_loc; + struct quota_local *local = frame->local; + if (op_ret >= 0) { + local->stbuf = *buf; + } + + tmp_loc.path = local->path; + tmp_loc.inode = local->inode; + + STACK_WIND (frame, + quota_rmdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rmdir, + &tmp_loc); + + return 0; +} + +int32_t +quota_rmdir (call_frame_t *frame, + xlator_t *this, + loc_t *loc) +{ + struct quota_local *local = NULL; + struct quota_priv *priv = this->private; + + if (priv->disk_usage_limit) { + local = calloc (1, sizeof (struct quota_local)); + local->path = strdup (loc->path); + local->inode = inode_ref (loc->inode); + frame->local = local; + STACK_WIND (frame, + quota_rmdir_stat_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->stat, + loc); + return 0; + } + + STACK_WIND (frame, + quota_rmdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rmdir, + loc); + return 0; +} + +static int32_t +quota_symlink_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf) +{ + struct quota_priv *priv = this->private; + if ((op_ret >= 0) && priv->disk_usage_limit) { + LOCK (&priv->lock); + { + priv->current_disk_usage += (buf->st_blocks * 512); + } + UNLOCK (&priv->lock); + } + + STACK_UNWIND (frame, op_ret, op_errno, inode, buf); + return 0; +} + +int32_t +quota_symlink (call_frame_t *frame, + xlator_t *this, + const char *linkpath, + loc_t *loc) +{ + struct quota_priv *priv = this->private; + if (gf_quota_check_free_disk (this) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "min-free-disk limit (%u) crossed, current available is %u", + priv->min_free_disk_limit, priv->current_free_disk); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL); + return 0; + + } + if (priv->current_disk_usage > priv->disk_usage_limit) { + gf_log (this->name, GF_LOG_ERROR, + "Disk usage limit (%"PRIu64") crossed, current usage is %"PRIu64"", + priv->disk_usage_limit, priv->current_disk_usage); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL); + return 0; + } + + STACK_WIND (frame, + quota_symlink_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->symlink, + linkpath, loc); + return 0; +} + + +static int32_t +quota_create_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd, + inode_t *inode, + struct stat *buf) +{ + struct quota_priv *priv = this->private; + if ((op_ret >= 0) && priv->disk_usage_limit) { + LOCK (&priv->lock); + { + priv->current_disk_usage += (buf->st_blocks * 512); + } + UNLOCK (&priv->lock); + } + + STACK_UNWIND (frame, op_ret, op_errno, fd, inode, buf); + return 0; +} + +int32_t +quota_create (call_frame_t *frame, + xlator_t *this, + loc_t *loc, + int32_t flags, + mode_t mode, fd_t *fd) +{ + struct quota_priv *priv = this->private; + if (gf_quota_check_free_disk (this) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "min-free-disk limit (%u) crossed, current available is %u", + priv->min_free_disk_limit, priv->current_free_disk); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL, NULL); + return 0; + + } + if (priv->current_disk_usage > priv->disk_usage_limit) { + gf_log (this->name, GF_LOG_ERROR, + "Disk usage limit (%"PRIu64") crossed, current usage is %"PRIu64"", + priv->disk_usage_limit, priv->current_disk_usage); + STACK_UNWIND (frame, -1, ENOSPC, NULL, NULL, NULL); + return 0; + } + + STACK_WIND (frame, quota_create_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->create, + loc, flags, mode, fd); + return 0; +} + + +static int32_t +quota_writev_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + struct quota_priv *priv = this->private; + struct quota_local *local = frame->local; + + if (priv->disk_usage_limit) { + if (op_ret >= 0) { + LOCK (&priv->lock); + { + priv->current_disk_usage += ((stbuf->st_blocks - local->stbuf.st_blocks) * 512); + } + UNLOCK (&priv->lock); + } + fd_unref (local->fd); + dict_unref (local->refs); + } + + STACK_UNWIND (frame, op_ret, op_errno, stbuf); + return 0; +} + +int32_t +quota_writev_fstat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + struct quota_local *local = frame->local; + struct quota_priv *priv = this->private; + int iovlen = 0; + int idx = 0; + + if (op_ret >= 0) { + if (priv->current_disk_usage > priv->disk_usage_limit) { + for (idx = 0; idx < local->count; idx++) { + iovlen += local->vector[idx].iov_len; + } + if (iovlen > (buf->st_blksize - (buf->st_size % buf->st_blksize))) { + fd_unref (local->fd); + dict_unref (local->refs); + STACK_UNWIND (frame, -1, ENOSPC, NULL); + return 0; + } + } + + local->stbuf = *buf; + } + + STACK_WIND (frame, + quota_writev_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, + local->fd, local->vector, local->count, local->offset); + + return 0; +} + +int32_t +quota_writev (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + struct iovec *vector, + int32_t count, + off_t off) +{ + struct quota_local *local = NULL; + struct quota_priv *priv = this->private; + + if (gf_quota_check_free_disk (this) == -1) { + gf_log (this->name, GF_LOG_ERROR, + "min-free-disk limit (%u) crossed, current available is %u", + priv->min_free_disk_limit, priv->current_free_disk); + STACK_UNWIND (frame, -1, ENOSPC, NULL); + return 0; + } + + if (priv->disk_usage_limit) { + local = calloc (1, sizeof (struct quota_local)); + local->fd = fd_ref (fd); + local->refs = dict_ref (frame->root->req_refs); + local->vector = vector; + local->count = count; + local->offset = off; + frame->local = local; + STACK_WIND (frame, + quota_writev_fstat_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fstat, + fd); + return 0; + } + + STACK_WIND (frame, + quota_writev_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, + fd, vector, count, off); + return 0; +} + + +int32_t +quota_removexattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + if (op_ret == -1) { + gf_log (this->name, GF_LOG_CRITICAL, + "failed to remove the disk-usage value: %s", + strerror (op_errno)); + } + + STACK_DESTROY (frame->root); + return 0; +} + +int32_t +quota_setxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + if (op_ret == -1) { + gf_log (this->name, GF_LOG_CRITICAL, + "failed to set the disk-usage value: %s", + strerror (op_errno)); + } + + STACK_DESTROY (frame->root); + return 0; +} + +int32_t +quota_getxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *value) +{ + data_t *data = NULL; + struct quota_priv *priv = this->private; + loc_t tmp_loc = { + .inode = NULL, + .path = "/", + }; + + if (op_ret >= 0) { + data = dict_get (value, "trusted.glusterfs-quota-du"); + if (data) { + LOCK (&priv->lock); + { + priv->current_disk_usage = data_to_uint64 (data); + } + UNLOCK (&priv->lock); + STACK_WIND (frame, + quota_removexattr_cbk, + this->children->xlator, + this->children->xlator->fops->removexattr, + &tmp_loc, + "trusted.glusterfs-quota-du"); + return 0; + } + } + + STACK_DESTROY (frame->root); + + return 0; +} + +void +gf_quota_get_disk_usage (xlator_t *this) +{ + call_ctx_t *cctx = NULL; + call_pool_t *pool = this->ctx->pool; + + cctx = calloc (1, sizeof (*cctx)); + ERR_ABORT (cctx); + cctx->frames.root = cctx; + cctx->frames.this = this; + cctx->pool = pool; + LOCK (&pool->lock); + { + list_add (&cctx->all_frames, &pool->all_frames); + } + UNLOCK (&pool->lock); + + { + loc_t tmp_loc = { + .inode = NULL, + .path = "/", + }; + + STACK_WIND ((&cctx->frames), + quota_getxattr_cbk, + this->children->xlator, + this->children->xlator->fops->getxattr, + &tmp_loc, + "trusted.glusterfs-quota-du"); + } + + return ; +} + +/* notify */ +int32_t +notify (xlator_t *this, + int32_t event, + void *data, + ...) +{ + struct quota_priv *priv = this->private; + + switch (event) + { + case GF_EVENT_CHILD_UP: + if (priv->only_first_time) { + priv->only_first_time = 0; + if (priv->disk_usage_limit) { + gf_quota_get_disk_usage (this); + } + } + default: + default_notify (this, event, data); + break; + } + + return 0; +} + + +int32_t +init (xlator_t *this) +{ + int ret = 0; + data_t *data = NULL; + struct quota_priv *_private = NULL; + + if (!this->children) { + gf_log (this->name, + GF_LOG_ERROR, + "FATAL: posix-locks should have exactly one child"); + return -1; + } + + if (this->children->next) { + gf_log (this->name, + GF_LOG_ERROR, + "FATAL: posix-locks should have exactly one child"); + return -1; + } + + _private = calloc (1, sizeof (struct quota_priv)); + _private->disk_usage_limit = 0; + data = dict_get (this->options, "disk-usage-limit"); + if (data) { + if (gf_string2bytesize (data->data, &_private->disk_usage_limit) != 0) { + gf_log (this->name, GF_LOG_ERROR, + "invalid number '%s' for disk-usage limit", data->data); + ret = -1; + goto out; + } + + LOCK_INIT (&_private->lock); + _private->current_disk_usage = 0; + } + + _private->min_free_disk_limit = 0; + data = dict_get (this->options, "min-free-disk-limit"); + if (data) { + if (gf_string2percent (data->data, &_private->min_free_disk_limit) != 0) { + gf_log (this->name, GF_LOG_ERROR, + "invalid percent '%s' for min-free-disk limit", data->data); + ret = -1; + goto out; + } + _private->min_free_disk_refresh = 30; /* 30seconds is default */ + data = dict_get (this->options, "min-free-disk-refresh-interval"); + if (data) { + if (gf_string2time (data->data, &_private->min_free_disk_refresh) != 0) { + gf_log (this->name, GF_LOG_ERROR, + "invalid time '%s' for min-free-disk refresh interval", data->data); + ret = -1; + goto out; + } + } + } + + _private->only_first_time = 1; + this->private = (void *)_private; + ret = 0; + out: + return ret; +} + +void +fini (xlator_t *this) +{ + call_ctx_t *cctx = NULL; + struct quota_priv *_private = this->private; + call_pool_t *pool = this->ctx->pool; + + cctx = calloc (1, sizeof (*cctx)); + ERR_ABORT (cctx); + cctx->frames.root = cctx; + cctx->frames.this = this; + cctx->pool = pool; + LOCK (&pool->lock); + { + list_add (&cctx->all_frames, &pool->all_frames); + } + UNLOCK (&pool->lock); + + { + dict_t *dict = get_new_dict (); + loc_t tmp_loc = { + .inode = NULL, + .path = "/", + }; + dict_set (dict, "trusted.glusterfs-quota-du", + data_from_uint64 (_private->current_disk_usage)); + + STACK_WIND ((&cctx->frames), + quota_setxattr_cbk, + this->children->xlator, + this->children->xlator->fops->setxattr, + &tmp_loc, + dict, + 0); + } + + FREE (_private); + return ; +} + +struct xlator_fops fops = { + .create = quota_create, + .truncate = quota_truncate, + .ftruncate = quota_ftruncate, + .writev = quota_writev, + .unlink = quota_unlink, + .rmdir = quota_rmdir, + .mknod = quota_mknod, + .mkdir = quota_mkdir, + .symlink = quota_symlink, +}; + +struct xlator_mops mops = { +}; + +struct xlator_cbks cbks = { +}; + +struct xlator_options options[] = { + { "min-free-disk-limit", GF_OPTION_TYPE_PERCENT, 0, }, + { "min-free-disk-refresh-interval", GF_OPTION_TYPE_TIME, 0, }, + { "disk-usage-limit", GF_OPTION_TYPE_SIZET, 0, -1, }, + { NULL, 0,}, +}; diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index 89075a63e3c..630762e2b5e 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -2447,7 +2447,6 @@ static struct fuse_lowlevel_ops fuse_ops = { static void * fuse_thread_proc (void *data) { - glusterfs_ctx_t *ctx = NULL; char *mount_point = NULL; xlator_t *this = data; fuse_private_t *priv = this->private; @@ -2505,29 +2504,19 @@ fuse_thread_proc (void *data) priv->buf->is_locked = 1; } } - - ctx = get_global_ctx_ptr (); - if ((mount_point = data_to_str (dict_get (this->options, - GF_FUSE_MOUNT_POINT_OPTION_STRING))) != NULL) { - gf_log (basename (ctx->program_invocation_name), GF_LOG_WARNING, + if (dict_get (this->options, GF_FUSE_MOUNT_POINT_OPTION_STRING)) + mount_point = data_to_str (dict_get (this->options, + GF_FUSE_MOUNT_POINT_OPTION_STRING)); + if (mount_point) { + gf_log (this->name, GF_LOG_WARNING, "unmounting %s\n", mount_point); + dict_del (this->options, GF_FUSE_MOUNT_POINT_OPTION_STRING); } - fuse_session_remove_chan (priv->ch); - fuse_session_destroy (priv->se); - // fuse_unmount (priv->mount_point, priv->ch); - - gf_log (basename (ctx->program_invocation_name), GF_LOG_WARNING, - "shutting down\n"); - - if (ctx->pidfp) { - gf_unlockfd (fileno (ctx->pidfp)); - fclose (ctx->pidfp); - } - - if (ctx->cmd_args.pid_file) - unlink (ctx->cmd_args.pid_file); + fuse_session_remove_chan (priv->ch); + fuse_session_destroy (priv->se); + // fuse_unmount (priv->mount_point, priv->ch); - exit (0); + raise (SIGTERM); return NULL; } @@ -2740,7 +2729,6 @@ void fini (xlator_t *this_xl) { struct fuse_private *priv = NULL; - glusterfs_ctx_t *ctx = NULL; char *mount_point = NULL; if (this_xl == NULL) @@ -2749,27 +2737,17 @@ fini (xlator_t *this_xl) if ((priv = this_xl->private) == NULL) return; - ctx = get_global_ctx_ptr (); - mount_point = data_to_str (dict_get (this_xl->options, - GF_FUSE_MOUNT_POINT_OPTION_STRING)); + if (dict_get (this_xl->options, GF_FUSE_MOUNT_POINT_OPTION_STRING)) + mount_point = data_to_str (dict_get (this_xl->options, + GF_FUSE_MOUNT_POINT_OPTION_STRING)); if (mount_point != NULL) { - gf_log (basename (ctx->program_invocation_name), GF_LOG_WARNING, + gf_log (this_xl->name, GF_LOG_WARNING, "unmounting %s\n", mount_point); + dict_del (this_xl->options, GF_FUSE_MOUNT_POINT_OPTION_STRING); fuse_session_exit (priv->se); fuse_unmount (mount_point, priv->ch); } - - gf_log (basename (ctx->program_invocation_name), GF_LOG_WARNING, - "shutting down\n"); - - if (ctx->pidfp) { - gf_unlockfd (fileno (ctx->pidfp)); - fclose (ctx->pidfp); - } - - if (ctx->cmd_args.pid_file) - unlink (ctx->cmd_args.pid_file); } struct xlator_fops fops = { diff --git a/xlators/performance/io-cache/src/io-cache.c b/xlators/performance/io-cache/src/io-cache.c index 081b7a47235..955625a6c45 100644 --- a/xlators/performance/io-cache/src/io-cache.c +++ b/xlators/performance/io-cache/src/io-cache.c @@ -1278,10 +1278,8 @@ init (xlator_t *this) page_size_string); return -1; } - gf_log (this->name, - GF_LOG_DEBUG, - "using page-size %d", - table->page_size); + gf_log (this->name, GF_LOG_DEBUG, + "using page-size %"PRIu64"", table->page_size); } if (dict_get (options, "cache-size")) @@ -1298,10 +1296,8 @@ init (xlator_t *this) return -1; } - gf_log (this->name, - GF_LOG_DEBUG, - "using cache-size %d", - table->cache_size); + gf_log (this->name, GF_LOG_DEBUG, + "using cache-size %"PRIu64"", table->cache_size); } table->force_revalidate_timeout = 1; diff --git a/xlators/performance/io-cache/src/io-cache.h b/xlators/performance/io-cache/src/io-cache.h index f9a825d0d1a..459b48055ef 100644 --- a/xlators/performance/io-cache/src/io-cache.h +++ b/xlators/performance/io-cache/src/io-cache.h @@ -132,8 +132,8 @@ struct ioc_inode { }; struct ioc_table { - size_t page_size; - size_t cache_size; + uint64_t page_size; + uint64_t cache_size; uint64_t cache_used; struct list_head inodes; /* list of inodes cached */ struct list_head active; diff --git a/xlators/performance/io-threads/src/io-threads.c b/xlators/performance/io-threads/src/io-threads.c index 7854c4422f2..fbf15b4801d 100644 --- a/xlators/performance/io-threads/src/io-threads.c +++ b/xlators/performance/io-threads/src/io-threads.c @@ -1160,21 +1160,17 @@ init (xlator_t *this) if (dict_get (options, "cache-size")) cache_size_string = data_to_str (dict_get (options, "cache-size")); - if (cache_size_string) - { - if (gf_string2bytesize (cache_size_string, &conf->cache_size) != 0) - { - gf_log ("io-threads", - GF_LOG_ERROR, - "invalid number format \"%s\" of \"option cache-size\"", - cache_size_string); - return -1; - } - gf_log ("io-threads", - GF_LOG_DEBUG, - "Using conf->cache_size = %lld", - conf->cache_size); - } + if (cache_size_string) { + if (gf_string2bytesize (cache_size_string, &conf->cache_size) != 0) { + gf_log ("io-threads", + GF_LOG_ERROR, + "invalid number format \"%s\" of \"option cache-size\"", + cache_size_string); + return -1; + } + gf_log ("io-threads", GF_LOG_DEBUG, + "Using conf->cache_size = %"PRIu64"", conf->cache_size); + } pthread_mutex_init (&conf->lock, NULL); pthread_cond_init (&conf->q_cond, NULL); diff --git a/xlators/performance/io-threads/src/io-threads.h b/xlators/performance/io-threads/src/io-threads.h index 27a4ddfabaa..6595d3e277b 100644 --- a/xlators/performance/io-threads/src/io-threads.h +++ b/xlators/performance/io-threads/src/io-threads.h @@ -84,7 +84,7 @@ struct iot_conf { struct iot_file files; pthread_mutex_t files_lock; - size_t cache_size; + uint64_t cache_size; off_t current_size; pthread_cond_t q_cond; pthread_mutex_t lock; diff --git a/xlators/performance/read-ahead/src/read-ahead.c b/xlators/performance/read-ahead/src/read-ahead.c index 19b66db8509..ec374886258 100644 --- a/xlators/performance/read-ahead/src/read-ahead.c +++ b/xlators/performance/read-ahead/src/read-ahead.c @@ -861,7 +861,7 @@ init (xlator_t *this) return -1; } - gf_log (this->name, GF_LOG_DEBUG, "Using conf->page_size = 0x%x", + gf_log (this->name, GF_LOG_DEBUG, "Using conf->page_size = %"PRIu64"", conf->page_size); } @@ -878,7 +878,7 @@ init (xlator_t *this) page_count_string); return -1; } - gf_log (this->name, GF_LOG_DEBUG, "Using conf->page_count = 0x%x", + gf_log (this->name, GF_LOG_DEBUG, "Using conf->page_count = %u", conf->page_count); } diff --git a/xlators/performance/read-ahead/src/read-ahead.h b/xlators/performance/read-ahead/src/read-ahead.h index 886d5e5b51c..e1cb501e97c 100644 --- a/xlators/performance/read-ahead/src/read-ahead.h +++ b/xlators/performance/read-ahead/src/read-ahead.h @@ -96,12 +96,12 @@ struct ra_file { int32_t refcount; pthread_mutex_t file_lock; struct stat stbuf; - size_t page_size; + uint64_t page_size; uint32_t page_count; }; struct ra_conf { - size_t page_size; + uint64_t page_size; uint32_t page_count; void *cache_block; struct ra_file files; diff --git a/xlators/performance/write-behind/src/write-behind.c b/xlators/performance/write-behind/src/write-behind.c index 93e139b212a..dac620d7847 100644 --- a/xlators/performance/write-behind/src/write-behind.c +++ b/xlators/performance/write-behind/src/write-behind.c @@ -43,8 +43,8 @@ struct wb_file; struct wb_conf { - size_t aggregate_size; - size_t window_size; + uint64_t aggregate_size; + uint64_t window_size; char flush_behind; }; @@ -1280,9 +1280,8 @@ init (xlator_t *this) } } - gf_log (this->name, - GF_LOG_DEBUG, - "using aggregate-size = %d", conf->aggregate_size); + gf_log (this->name, GF_LOG_DEBUG, + "using aggregate-size = %"PRIu64"", conf->aggregate_size); conf->window_size = 0; @@ -1304,7 +1303,7 @@ init (xlator_t *this) if (!conf->window_size && conf->aggregate_size) { gf_log (this->name, GF_LOG_WARNING, - "setting window-size to be equal to aggregate-size(%"PRId32")", + "setting window-size to be equal to aggregate-size(%"PRIu64")", conf->aggregate_size); conf->window_size = conf->aggregate_size; } @@ -1312,8 +1311,8 @@ init (xlator_t *this) if (conf->window_size < conf->aggregate_size) { gf_log (this->name, GF_LOG_ERROR, - "aggregate-size(%"PRId32") cannot be more than window-size" - "(%"PRId32")", conf->window_size, conf->aggregate_size); + "aggregate-size(%"PRIu64") cannot be more than window-size" + "(%"PRIu64")", conf->window_size, conf->aggregate_size); FREE (conf); return -1; } @@ -1323,10 +1322,8 @@ init (xlator_t *this) if (dict_get (options, "flush-behind")) { - if ((!strcasecmp (data_to_str (dict_get (options, "flush-behind")), - "on")) || - (!strcasecmp (data_to_str (dict_get (options, "flush-behind")), - "yes"))) { + if ((!strcasecmp (data_to_str (dict_get (options, "flush-behind")), "on")) || + (!strcasecmp (data_to_str (dict_get (options, "flush-behind")), "yes"))) { if (conf->aggregate_size != 0) { gf_log (this->name, GF_LOG_WARNING, "aggregate-size is not zero, disabling flush-behind"); diff --git a/xlators/protocol/client/src/client-protocol.h b/xlators/protocol/client/src/client-protocol.h index e7669f69267..ca714a8075f 100644 --- a/xlators/protocol/client/src/client-protocol.h +++ b/xlators/protocol/client/src/client-protocol.h @@ -53,7 +53,7 @@ struct client_proto_priv { char connected; int32_t n_minus_1; int32_t n; - size_t max_block_size; /* maximum size of protocol data block that this client can recieve, 0 is unlimited */ + uint64_t max_block_size; /* maximum size of protocol data block that this client can recieve, 0 is unlimited */ struct timeval last_sent; struct timeval last_received; gf_timer_t *timer; diff --git a/xlators/storage/bdb/src/bdb.h b/xlators/storage/bdb/src/bdb.h index 69517d09f77..73f635c4083 100644 --- a/xlators/storage/bdb/src/bdb.h +++ b/xlators/storage/bdb/src/bdb.h @@ -213,7 +213,7 @@ struct bctx_table { int32_t transaction; xlator_t *this; - size_t page_size; /* page-size of DB, + uint64_t page_size; /* page-size of DB, * DB->set_pagesize(), should be set before DB->open */ }; diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 0ece7794637..594020c56db 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -2336,7 +2336,7 @@ posix_getxattr (call_frame_t *frame, xlator_t *this, SET_FS_ID (frame->root->uid, frame->root->gid); MAKE_REAL_PATH (real_path, this, loc->path); - if (S_ISDIR(loc->inode->st_mode) && name && + if (loc->inode && S_ISDIR(loc->inode->st_mode) && name && GF_FILE_CONTENT_REQUEST(name)) { ret = get_file_contents (this, real_path, name, &file_contents); if (ret < 0) {